diff options
| author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
|---|---|---|
| committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-04-30 00:33:56 +0200 | 
| commit | aa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch) | |
| tree | 4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /vmime-master/src/vmime/platforms | |
| download | smtps-and-pop3s-console-program-master.tar.gz smtps-and-pop3s-console-program-master.zip | |
Diffstat (limited to 'vmime-master/src/vmime/platforms')
19 files changed, 5408 insertions, 0 deletions
| diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp new file mode 100644 index 0000000..4a9fef3 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp @@ -0,0 +1,410 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/platforms/posix/posixChildProcess.hpp" +#include "vmime/platforms/posix/posixFile.hpp" + +#include "vmime/exception.hpp" + +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/wait.h> + + +namespace vmime { +namespace platforms { +namespace posix { + + +// posixChildProcessFactory + +shared_ptr <utility::childProcess> posixChildProcessFactory::create(const utility::file::path& path) const { + +	return make_shared <posixChildProcess>(path); +} + + + +#ifndef VMIME_BUILDING_DOC + + +// getPosixSignalMessage +// Returns the name of a POSIX signal. + +static const string getPosixSignalMessage(const int num) { + +	switch (num) { +		case SIGHUP:  return "SIGHUP"; +		case SIGINT:  return "SIGINT"; +		case SIGQUIT: return "SIGQUIT"; +		case SIGILL:  return "SIGILL"; +		case SIGABRT: return "SIGABRT"; +		case SIGFPE:  return "SIGFPE"; +		case SIGKILL: return "SIGKILL"; +		case SIGSEGV: return "SIGSEGV"; +		case SIGPIPE: return "SIGPIPE"; +		case SIGALRM: return "SIGALRM"; +		case SIGTERM: return "SIGTERM"; +		case SIGUSR1: return "SIGUSR1"; +		case SIGUSR2: return "SIGUSR2"; +		case SIGCHLD: return "SIGCHLD"; +		case SIGCONT: return "SIGCONT"; +		case SIGSTOP: return "SIGSTOP"; +		case SIGTSTP: return "SIGTSTP"; +		case SIGTTIN: return "SIGTTIN"; +		case SIGTTOU: return "SIGTTOU"; +	} + +	return "(unknown)"; +} + + +// getPosixErrorMessage +// Returns a message corresponding to an error code. + +static const string getPosixErrorMessage(const int num) { + +#ifdef strerror_r +	char res[256]; +	res[0] = '\0'; + +	strerror_r(num, res, sizeof(res)); + +	return string(res); +#else +	return string(strerror(num)); +#endif + +} + + +// Output stream adapter for POSIX pipe + +class outputStreamPosixPipeAdapter : public utility::outputStream { + +public: + +	outputStreamPosixPipeAdapter(const int desc) +		: m_desc(desc) { + +	} + +	void flush() { + +		::fsync(m_desc); +	} + +protected: + +	void writeImpl(const byte_t* const data, const size_t count) { + +		if (::write(m_desc, data, count) == -1) { +			const string errorMsg = getPosixErrorMessage(errno); +			throw exceptions::system_error(errorMsg); +		} +	} + +private: + +	const int m_desc; +}; + + +// Input stream adapter for POSIX pipe + +class inputStreamPosixPipeAdapter : public utility::inputStream { + +public: + +	inputStreamPosixPipeAdapter(const int desc) +		: m_desc(desc) { +	} + +	bool eof() const { + +		return m_eof; +	} + +	void reset() { + +		// Do nothing: unsupported +	} + +	size_t skip(const size_t count) { + +		// TODO: not tested +		byte_t buffer[4096]; + +		ssize_t bytesSkipped = 0; +		ssize_t bytesRead = 0; + +		while ((bytesRead = ::read(m_desc, buffer, +			std::min(sizeof(buffer), count - bytesSkipped))) != 0) { + +			if (bytesRead == -1) { +				const string errorMsg = getPosixErrorMessage(errno); +				throw exceptions::system_error(errorMsg); +			} + +			bytesSkipped += bytesRead; +		} + +		return static_cast <size_t>(bytesSkipped); +	} + +	size_t read(byte_t* const data, const size_t count) { + +		ssize_t bytesRead = 0; + +		if ((bytesRead = ::read(m_desc, data, count)) == -1) { +			const string errorMsg = getPosixErrorMessage(errno); +			throw exceptions::system_error(errorMsg); +		} + +		m_eof = (bytesRead == 0); + +		return static_cast <size_t>(bytesRead); +	} + +private: + +	const int m_desc; + +	bool m_eof; +}; + + +#endif // VMIME_BUILDING_DOC + + + +// posixChildProcess + +posixChildProcess::posixChildProcess(const utility::file::path& path) +	: m_processPath(path), +	  m_started(false), +	  m_stdIn(null), +	  m_stdOut(null), +	  m_pid(0), +	  m_argArray(NULL) { + +	m_pipe[0] = 0; +	m_pipe[1] = 0; + +	sigemptyset(&m_oldProcMask); +} + + +posixChildProcess::~posixChildProcess() { + +	if (m_started) { +		sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL); +	} + +	if (m_pipe[0] != 0) { +		close(m_pipe[0]); +	} + +	if (m_pipe[1] != 0) { +		close(m_pipe[1]); +	} + +	delete [] m_argArray; +} + + +// The following code is highly inspired and adapted from the 'sendmail' +// provider module in Evolution data server code. +// +// Original authors: Dan Winship <danw@ximian.com> +// Copyright 2000 Ximian, Inc. (www.ximian.com) + +void posixChildProcess::start(const std::vector <string>& args, const int flags) { + +	if (m_started) { +		return; +	} + +	// Construct C-style argument array +	const char** argv = new const char*[args.size() + 2]; + +	m_argVector = args;  // for c_str() pointer to remain valid +	m_argArray = argv;   // to free later + +	argv[0] = m_processPath.getLastComponent().getBuffer().c_str(); +	argv[args.size() + 1] = NULL; + +	for (unsigned int i = 0 ; i < m_argVector.size() ; ++i) { +		argv[i + 1] = m_argVector[i].c_str(); +	} + +	// Create a pipe to communicate with the child process +	int fd[2]; + +	if (pipe(fd) == -1) { +		throw exceptions::system_error(getPosixErrorMessage(errno)); +	} + +	m_pipe[0] = fd[0]; +	m_pipe[1] = fd[1]; + +	// Block SIGCHLD so the calling application doesn't notice +	// process exiting before we do +	sigset_t mask; + +	sigemptyset(&mask); +	sigaddset(&mask, SIGCHLD); +	sigprocmask(SIG_BLOCK, &mask, &m_oldProcMask); + +	// Spawn process +	const pid_t pid = fork(); + +	if (pid == -1) {  // error + +		const string errorMsg = getPosixErrorMessage(errno); + +		sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL); + +		close(fd[0]); +		close(fd[1]); + +		throw exceptions::system_error(errorMsg); + +	} else if (pid == 0) {  // child process + +		if (flags & FLAG_REDIRECT_STDIN) { +			dup2(fd[0], STDIN_FILENO); +		} else { +			close(fd[0]); +		} + +		if (flags & FLAG_REDIRECT_STDOUT) { +			dup2(fd[1], STDOUT_FILENO); +		} else { +			close(fd[1]); +		} + +		posixFileSystemFactory* pfsf = new posixFileSystemFactory(); + +		const string path = pfsf->pathToString(m_processPath); + +		delete pfsf; + +		execv(path.c_str(), const_cast <char**>(argv)); +		_exit(255); +	} + +	if (flags & FLAG_REDIRECT_STDIN) { + +		m_stdIn = make_shared <outputStreamPosixPipeAdapter>(m_pipe[1]); + +	} else { + +		close(m_pipe[1]); +		m_pipe[1] = 0; +	} + +	if (flags & FLAG_REDIRECT_STDOUT) { + +		m_stdOut = make_shared <inputStreamPosixPipeAdapter>(m_pipe[0]); + +	} else { + +		close(m_pipe[0]); +		m_pipe[0] = 0; +	} + +	m_pid = pid; +	m_started = true; +} + + +shared_ptr <utility::outputStream> posixChildProcess::getStdIn() { + +	return m_stdIn; +} + + +shared_ptr <utility::inputStream> posixChildProcess::getStdOut() { + +	return m_stdOut; +} + + +void posixChildProcess::waitForFinish() { + +	// Close stdin pipe +	if (m_pipe[1] != 0) { +		close(m_pipe[1]); +		m_pipe[1] = 0; +	} + +	int wstat; + +	while (waitpid(m_pid, &wstat, 0) == -1 && errno == EINTR) { +		; +	} + +	if (!WIFEXITED(wstat)) { + +		throw exceptions::system_error("Process exited with signal " +			+ getPosixSignalMessage(WTERMSIG(wstat))); + +	} else if (WEXITSTATUS(wstat) != 0) { + +		if (WEXITSTATUS(wstat) == 255) { + +			scoped_ptr <posixFileSystemFactory> pfsf(new posixFileSystemFactory()); + +			throw exceptions::system_error("Could not execute '" +				+ pfsf->pathToString(m_processPath) + "'"); + +		} else { + +			std::ostringstream oss; +			oss.imbue(std::locale::classic()); + +			oss << "Process exited with status " << WEXITSTATUS(wstat); + +			throw exceptions::system_error(oss.str()); +		} +	} +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp new file mode 100644 index 0000000..b831e8b --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp @@ -0,0 +1,92 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/utility/childProcess.hpp" + +#include <sys/types.h> +#include <signal.h> + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixChildProcess : public utility::childProcess { + +public: + +	posixChildProcess(const utility::file::path& path); +	~posixChildProcess(); + +	void start(const std::vector <string>& args, const int flags = 0); + +	shared_ptr <utility::outputStream> getStdIn(); +	shared_ptr <utility::inputStream> getStdOut(); + +	void waitForFinish(); + +private: + +	utility::file::path m_processPath; +	bool m_started; + +	shared_ptr <utility::outputStream> m_stdIn; +	shared_ptr <utility::inputStream> m_stdOut; + +	sigset_t m_oldProcMask; +	pid_t m_pid; +	int m_pipe[2]; + +	std::vector <string> m_argVector; +	const char** m_argArray; +}; + + +class posixChildProcessFactory : public utility::childProcessFactory { + +public: + +	shared_ptr <utility::childProcess> create(const utility::file::path& path) const; +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED + diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp new file mode 100644 index 0000000..2f25cfa --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/platforms/posix/posixCriticalSection.hpp" + + +namespace vmime { +namespace platforms { +namespace posix { + + +posixCriticalSection::posixCriticalSection() { + +	pthread_mutex_init(&m_cs, NULL); +} + + +posixCriticalSection::~posixCriticalSection() { + +	pthread_mutex_destroy(&m_cs); +} + + +void posixCriticalSection::lock() { + +	pthread_mutex_lock(&m_cs); +} + + +void posixCriticalSection::unlock() { + +	pthread_mutex_unlock(&m_cs); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp new file mode 100644 index 0000000..9a4bed5 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp @@ -0,0 +1,69 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/utility/sync/criticalSection.hpp" + + +#include <unistd.h> +#include <pthread.h> + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixCriticalSection : public utility::sync::criticalSection { + +public: + +	posixCriticalSection(); +	~posixCriticalSection(); + +	void lock(); +	void unlock(); + +private: + +	pthread_mutex_t m_cs; +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX + +#endif // VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.cpp b/vmime-master/src/vmime/platforms/posix/posixFile.cpp new file mode 100644 index 0000000..9773b3a --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixFile.cpp @@ -0,0 +1,715 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/platforms/posix/posixFile.hpp" + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <dirent.h> + +#include <stdio.h> +#include <string.h> + +#include "vmime/exception.hpp" + + +namespace vmime { +namespace platforms { +namespace posix { + + +// +// posixFileIterator +// + +posixFileIterator::posixFileIterator( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath), +	  m_dir(NULL), +	  m_dirEntry(NULL) { + +	if ((m_dir = ::opendir(m_nativePath.c_str())) == NULL) { +		posixFileSystemFactory::reportError(path, errno); +	} + +	getNextElement(); +} + + +posixFileIterator::~posixFileIterator() { + +	if (m_dir) { + +		if (::closedir(m_dir) == -1) { +			posixFileSystemFactory::reportError(m_path, errno); +		} +	} +} + + +bool posixFileIterator::hasMoreElements() const { + +	return (m_dirEntry != NULL); +} + + +shared_ptr <vmime::utility::file> posixFileIterator::nextElement() { + +	shared_ptr <posixFile> file = make_shared <posixFile>( +		m_path / vmime::utility::file::path::component(m_dirEntry->d_name) +	); + +	getNextElement(); + +	return file; +} + + +void posixFileIterator::getNextElement() { + +	errno = 0; + +	while ((m_dirEntry = ::readdir(m_dir)) != NULL) { + +		const char* name = m_dirEntry->d_name; +		const size_t len = ::strlen(name); + +		if (!(len == 1 && name[0] == '.') && +		    !(len == 2 && name[0] == '.' && name[1] == '.')) { + +			break; +		} +	} + +	if (errno) { +		posixFileSystemFactory::reportError(m_path, errno); +	} +} + + + +// +// posixFileWriterOutputStream +// + +posixFileWriterOutputStream::posixFileWriterOutputStream( +	const vmime::utility::file::path& path, +	const int fd +) +	: m_path(path), +	  m_fd(fd) { + +} + + +posixFileWriterOutputStream::~posixFileWriterOutputStream() { + +	::close(m_fd); +} + + +void posixFileWriterOutputStream::writeImpl( +	const byte_t* const data, +	const size_t count +) { + +	const byte_t* array = data; +	size_t size = count; + +	while (1) { + +		ssize_t ret = ::write(m_fd, array, size); + +		if (ret == -1) { + +			if (errno == EINTR) { +				continue; +			} + +			posixFileSystemFactory::reportError(m_path, errno); +			break; + +		} else if (size_t(ret) < size) { + +			array += ret; +			size -= ret; +		} + +		break; +	} +} + + +void posixFileWriterOutputStream::flush() { + +	if (::fsync(m_fd) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} +} + + + +// +// posixFileReaderInputStream +// + +posixFileReaderInputStream::posixFileReaderInputStream( +	const vmime::utility::file::path& path, +	const int fd +) +	: m_path(path), +	  m_fd(fd), +	  m_eof(false) { + +} + + +posixFileReaderInputStream::~posixFileReaderInputStream() { + +	if (::close(m_fd) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} +} + + +bool posixFileReaderInputStream::eof() const { + +	return m_eof; +} + + +void posixFileReaderInputStream::reset() { + +	if (::lseek(m_fd, 0, SEEK_SET) == off_t(-1)) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	m_eof = false; +} + + +size_t posixFileReaderInputStream::read( +	byte_t* const data, +	const size_t count +) { + +	ssize_t c = 0; + +	if ((c = ::read(m_fd, data, count)) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	if (c == 0 && count != 0) { +		m_eof = true; +	} + +	return static_cast <size_t>(c); +} + + +size_t posixFileReaderInputStream::skip(const size_t count) { + +	const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR); + +	if (curPos == off_t(-1)) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	const off_t newPos = ::lseek(m_fd, count, SEEK_CUR); + +	if (newPos == off_t(-1)) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	return static_cast <size_t>(newPos - curPos); +} + + +size_t posixFileReaderInputStream::getPosition() const { + +	const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR); + +	if (curPos == off_t(-1)) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	return static_cast <size_t>(curPos); +} + + +void posixFileReaderInputStream::seek(const size_t pos) { + +	const off_t newPos = ::lseek(m_fd, pos, SEEK_SET); + +	if (newPos == off_t(-1)) { +		posixFileSystemFactory::reportError(m_path, errno); +	} +} + + + +// +// posixFileWriter +// + +posixFileWriter::posixFileWriter( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath) { + +} + + +shared_ptr <vmime::utility::outputStream> posixFileWriter::getOutputStream() { + +	int fd = 0; + +	if ((fd = ::open(m_nativePath.c_str(), O_WRONLY, 0660)) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	return make_shared <posixFileWriterOutputStream>(m_path, fd); +} + + + +// +// posixFileReader +// + +posixFileReader::posixFileReader( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath) { + +} + + +shared_ptr <vmime::utility::inputStream> posixFileReader::getInputStream() { + +	int fd = 0; + +	if ((fd = ::open(m_nativePath.c_str(), O_RDONLY, 0640)) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	return make_shared <posixFileReaderInputStream>(m_path, fd); +} + + + +// +// posixFile +// + +posixFile::posixFile(const vmime::utility::file::path& path) +	: m_path(path), +	  m_nativePath(posixFileSystemFactory::pathToStringImpl(path)) { + +} + + +void posixFile::createFile() { + +	int fd = 0; + +	if ((fd = ::open(m_nativePath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660)) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	if (::fsync(fd) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	if (::close(fd) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} +} + + +void posixFile::createDirectory(const bool createAll) { + +	createDirectoryImpl(m_path, m_path, createAll); +} + + +bool posixFile::isFile() const { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { + +		if (errno == ENOENT) { +			return false; +		} + +		posixFileSystemFactory::reportError(m_path, errno); +		return false; +	} + +	return S_ISREG(buf.st_mode); +} + + +bool posixFile::isDirectory() const { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { + +		if (errno == ENOENT) { +			return false; +		} + +		posixFileSystemFactory::reportError(m_path, errno); +		return false; +	} + +	return S_ISDIR(buf.st_mode); +} + + +bool posixFile::canRead() const { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { + +		if (errno == ENOENT) { +			return false; +		} + +		posixFileSystemFactory::reportError(m_path, errno); +		return false; +	} + +	return S_ISREG(buf.st_mode) +	    && ::access(m_nativePath.c_str(), R_OK | F_OK) == 0; +} + + +bool posixFile::canWrite() const { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { + +		if (errno == ENOENT) { +			return false; +		} + +		posixFileSystemFactory::reportError(m_path, errno); +		return false; +	} + +	return S_ISREG(buf.st_mode) +	    && ::access(m_nativePath.c_str(), W_OK | F_OK) == 0; +} + + +posixFile::length_type posixFile::getLength() { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	return static_cast <length_type>(buf.st_size); +} + + +const posixFile::path& posixFile::getFullPath() const { + +	return m_path; +} + + +bool posixFile::exists() const { + +	struct stat buf; +	return ::stat(m_nativePath.c_str(), &buf) == 0; +} + + +shared_ptr <vmime::utility::file> posixFile::getParent() const { + +	if (m_path.isEmpty()) { +		return null; +	} else { +		return make_shared <posixFile>(m_path.getParent()); +	} +} + + +void posixFile::rename(const path& newName) { + +	const vmime::string newNativePath = posixFileSystemFactory::pathToStringImpl(newName); + +	posixFile dest(newName); + +	if (isDirectory()) { +		dest.createDirectory(); +	} else { +		dest.createFile(); +	} + +	if (::rename(m_nativePath.c_str(), newNativePath.c_str()) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	m_path = newName; +	m_nativePath = newNativePath; +} + + +void posixFile::remove() { + +	struct stat buf; + +	if (::stat(m_nativePath.c_str(), &buf) == -1) { +		posixFileSystemFactory::reportError(m_path, errno); +	} + +	if (S_ISDIR(buf.st_mode)) { + +		if (::rmdir(m_nativePath.c_str()) == -1) { +			posixFileSystemFactory::reportError(m_path, errno); +		} + +	} else if (S_ISREG(buf.st_mode)) { + +		if (::unlink(m_nativePath.c_str()) == -1) { +			posixFileSystemFactory::reportError(m_path, errno); +		} +	} +} + + +shared_ptr <vmime::utility::fileWriter> posixFile::getFileWriter() { + +	return make_shared <posixFileWriter>(m_path, m_nativePath); +} + + +shared_ptr <vmime::utility::fileReader> posixFile::getFileReader() { + +	return make_shared <posixFileReader>(m_path, m_nativePath); +} + + +shared_ptr <vmime::utility::fileIterator> posixFile::getFiles() const { + +	if (!isDirectory()) { +		throw vmime::exceptions::not_a_directory(m_path); +	} + +	return make_shared <posixFileIterator>(m_path, m_nativePath); +} + + +void posixFile::createDirectoryImpl( +	const vmime::utility::file::path& fullPath, +	const vmime::utility::file::path& path, +	const bool recursive +) { + +	const vmime::string nativePath = posixFileSystemFactory::pathToStringImpl(path); +	struct stat buf; + +	if (::stat(nativePath.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) { +		return; +	} + +	if (!path.isEmpty() && recursive) { +		createDirectoryImpl(fullPath, path.getParent(), true); +	} + +	if (::mkdir(nativePath.c_str(), 0750) == -1) { +		posixFileSystemFactory::reportError(fullPath, errno); +	} +} + + + +// +// posixFileSystemFactory +// + +shared_ptr <vmime::utility::file> posixFileSystemFactory::create( +	const vmime::utility::file::path& path +) const { + +	return make_shared <posixFile>(path); +} + + +const vmime::utility::file::path posixFileSystemFactory::stringToPath( +	const vmime::string& str +) const { + +	return stringToPathImpl(str); +} + + +const vmime::string posixFileSystemFactory::pathToString( +	const vmime::utility::file::path& path +) const { + +	return pathToStringImpl(path); +} + + +const vmime::utility::file::path posixFileSystemFactory::stringToPathImpl( +	const vmime::string& str +) { + +	vmime::size_t offset = 0; +	vmime::size_t prev = 0; + +	vmime::utility::file::path path; + +	while ((offset = str.find_first_of("/", offset)) != vmime::string::npos) { + +		if (offset != prev) { + +			path.appendComponent( +				vmime::utility::file::path::component( +					vmime::string(str.begin() + prev, str.begin() + offset) +				) +			); +		} + +		prev = offset + 1; +		offset++; +	} + +	if (prev < str.length()) { + +		path.appendComponent( +			vmime::utility::file::path::component( +				vmime::string(str.begin() + prev, str.end()) +			) +		); +	} + +	return path; +} + + +const vmime::string posixFileSystemFactory::pathToStringImpl(const vmime::utility::file::path& path) { + +	vmime::string native = "/"; + +	for (size_t i = 0 ; i < path.getSize() ; ++i) { + +		if (i > 0) { +			native += "/"; +		} + +		native += path[i].getBuffer(); +	} + +	return native; +} + + +bool posixFileSystemFactory::isValidPathComponent( +	const vmime::utility::file::path::component& comp +) const { + +	return comp.getBuffer().find_first_of("/*") == vmime::string::npos; +} + + +bool posixFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const { + +	for (size_t i = 0 ; i < path.getSize() ; ++i) { + +		if (!isValidPathComponent(path[i])) { +			return false; +		} +	} + +	return true; +} + + +void posixFileSystemFactory::reportError(const vmime::utility::path& path, const int err) { + +	vmime::string desc; + +	switch (err) { +		case EEXIST: desc = "EEXIST: file already exists."; break; +		case EISDIR: desc = "EISDIR: path refers to a directory."; break; +		case EACCES: desc = "EACCES: permission denied"; break; +		case ENAMETOOLONG: desc = "ENAMETOOLONG: path too long."; break; +		case ENOENT: desc = "ENOENT: a directory in the path does not exist."; break; +		case ENOTDIR: desc = "ENOTDIR: path is not a directory."; break; +		case EROFS: desc = "EROFS: read-only filesystem."; break; +		case ELOOP: desc = "ELOOP: too many symbolic links."; break; +		case ENOSPC: desc = "ENOSPC: no space left on device."; break; +		case ENOMEM: desc = "ENOMEM: insufficient kernel memory."; break; +		case EMFILE: desc = "ENFILE: limit on number of files open by the process has been reached."; break; +		case ENFILE: desc = "ENFILE: limit on number of files open on the system has been reached."; break; +#ifndef AIX +		case ENOTEMPTY: desc = "ENOTEMPTY: directory is not empty."; break; +#endif + +		default: + +			std::ostringstream oss; +			oss << ::strerror(err) << "."; + +			desc = oss.str(); +			break; +	} + +	throw vmime::exceptions::filesystem_exception(desc, path); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.hpp b/vmime-master/src/vmime/platforms/posix/posixFile.hpp new file mode 100644 index 0000000..d1fda9e --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixFile.hpp @@ -0,0 +1,224 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/utility/file.hpp" +#include "vmime/utility/seekableInputStream.hpp" + + +#include <dirent.h> + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixFileWriterOutputStream : public vmime::utility::outputStream { + +public: + +	posixFileWriterOutputStream(const vmime::utility::file::path& path, const int fd); +	~posixFileWriterOutputStream(); + +	void flush(); + +protected: + +	void writeImpl(const byte_t* const data, const size_t count); + +private: + +	const vmime::utility::file::path m_path; +	const int m_fd; +}; + + + +class posixFileReaderInputStream : public vmime::utility::seekableInputStream { + +public: + +	posixFileReaderInputStream(const vmime::utility::file::path& path, const int fd); +	~posixFileReaderInputStream(); + +	bool eof() const; + +	void reset(); + +	size_t read(byte_t* const data, const size_t count); + +	size_t skip(const size_t count); + +	size_t getPosition() const; +	void seek(const size_t pos); + +private: + +	const vmime::utility::file::path m_path; +	const int m_fd; + +	bool m_eof; +}; + + + +class posixFileWriter : public vmime::utility::fileWriter { + +public: + +	posixFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath); + +	shared_ptr <vmime::utility::outputStream> getOutputStream(); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + + +class posixFileReader : public vmime::utility::fileReader { + +public: + +	posixFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath); + +	shared_ptr <vmime::utility::inputStream> getInputStream(); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + + +class posixFileIterator : public vmime::utility::fileIterator { + +public: + +	posixFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath); +	~posixFileIterator(); + +	bool hasMoreElements() const; +	shared_ptr <vmime::utility::file> nextElement(); + +private: + +	void getNextElement(); + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; + +	DIR* m_dir; +	struct dirent* m_dirEntry; +}; + + + +class posixFile : public vmime::utility::file { + +public: + +	posixFile(const vmime::utility::file::path& path); + +	void createFile(); +	void createDirectory(const bool createAll = false); + +	bool isFile() const; +	bool isDirectory() const; + +	bool canRead() const; +	bool canWrite() const; + +	length_type getLength(); + +	const path& getFullPath() const; + +	bool exists() const; + +	shared_ptr <vmime::utility::file> getParent() const; + +	void rename(const path& newName); + +	void remove(); + +	shared_ptr <vmime::utility::fileWriter> getFileWriter(); +	shared_ptr <vmime::utility::fileReader> getFileReader(); + +	shared_ptr <vmime::utility::fileIterator> getFiles() const; + +private: + +	static void createDirectoryImpl( +		const vmime::utility::file::path& fullPath, +		const vmime::utility::file::path& path, +		const bool recursive = false +	); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + + +class posixFileSystemFactory : public vmime::utility::fileSystemFactory { + +public: + +	shared_ptr <vmime::utility::file> create(const vmime::utility::file::path& path) const; + +	const vmime::utility::file::path stringToPath(const vmime::string& str) const; +	const vmime::string pathToString(const vmime::utility::file::path& path) const; + +	static const vmime::utility::file::path stringToPathImpl(const vmime::string& str); +	static const vmime::string pathToStringImpl(const vmime::utility::file::path& path); + +	bool isValidPathComponent(const vmime::utility::file::path::component& comp) const; +	bool isValidPath(const vmime::utility::file::path& path) const; + +	static void reportError(const vmime::utility::path& path, const int err); +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.cpp b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp new file mode 100644 index 0000000..eecdbea --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp @@ -0,0 +1,292 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/platforms/posix/posixHandler.hpp" + +#include "vmime/platforms/posix/posixCriticalSection.hpp" + +#include "vmime/utility/stringUtils.hpp" + +#include <time.h> +#include <fcntl.h> +#include <unistd.h> +#include <locale.h> +#include <langinfo.h> +#include <errno.h> +#include <limits.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#if VMIME_HAVE_SYSCALL +#	include <sys/syscall.h> +#endif + +#include <netdb.h> + +#include <string.h> +#include <cassert> +#include <cstdlib> + + +/* +#ifdef _POSIX_PRIORITY_SCHEDULING +	#include <sched.h> +#endif // _POSIX_PRIORITY_SCHEDULING +*/ + + +namespace vmime { +namespace platforms { +namespace posix { + + +posixHandler::posixHandler() { + +#if VMIME_HAVE_MESSAGING_FEATURES +	m_socketFactory = make_shared <posixSocketFactory>(); +#endif +#if VMIME_HAVE_FILESYSTEM_FEATURES +	m_fileSysFactory = make_shared <posixFileSystemFactory>(); +	m_childProcFactory = make_shared <posixChildProcessFactory>(); +#endif + +} + + +posixHandler::~posixHandler() { + +} + + +unsigned long posixHandler::getUnixTime() const { + +	return static_cast <unsigned long>(::time(NULL)); +} + + +const vmime::datetime posixHandler::getCurrentLocalTime() const { + +	const time_t t(::time(NULL)); + +	// Get the local time +#if VMIME_HAVE_LOCALTIME_R +	tm local; +	::localtime_r(&t, &local); +#else +	tm local = *::localtime(&t);  // WARNING: this is not thread-safe! +#endif + +	// Get the UTC time +#if VMIME_HAVE_GMTIME_R +	tm gmt; +	::gmtime_r(&t, &gmt); +#else +	tm gmt = *::gmtime(&t);  // WARNING: this is not thread-safe! +#endif + +	// "A negative value for tm_isdst causes mktime() to attempt +	//  to determine whether Daylight Saving Time is in effect +	//  for the specified time." +	local.tm_isdst = -1; +	gmt.tm_isdst = -1; + +	// Calculate the difference (in seconds) +	const time_t diff = ::mktime(&local) - ::mktime(&gmt); + +	// Return the date +	return vmime::datetime( +		local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, +		local.tm_hour, local.tm_min, local.tm_sec, static_cast <int>(diff / 60) +	); +} + + +const vmime::charset posixHandler::getLocalCharset() const { + +	// Note: nl_langinfo() might be affected by calls to setlocale() +	// in a multithread environment. There is not MT-safe alternative +	// to nl_langinfo(). +	auto codeset = ::nl_langinfo(CODESET); + +	if (codeset) { +		return vmime::charset(codeset); +	} + +	return vmime::charset(); +} + + +static inline bool isAcceptableHostname(const vmime::string& str) { + +	// At least, try to find something better than "localhost" +	if (utility::stringUtils::isStringEqualNoCase(str, "localhost", 9) || +	    utility::stringUtils::isStringEqualNoCase(str, "localhost.localdomain", 21)) { + +		return false; +	} + +	// Anything else will be OK, as long as it is a valid hostname +	return utility::stringUtils::isValidHostname(str); +} + + +const vmime::string posixHandler::getHostName() const { +	char hostname[256]; + +	::gethostname(hostname, sizeof(hostname)); +	hostname[sizeof(hostname)-1] = '\0'; + +	// Try to get official canonical name of this host +	struct addrinfo hints; +	memset(&hints, 0, sizeof hints); +	hints.ai_family = AF_UNSPEC;  // either IPV4 or IPV6 +	hints.ai_socktype = SOCK_STREAM; +	hints.ai_flags = AI_CANONNAME; + +	struct addrinfo* info; + +	if (getaddrinfo(hostname, "http", &hints, &info) == 0) { +		// First, try to get a Fully-Qualified Domain Name (FQDN) +		for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) { + +			if (p->ai_canonname) { + +				const string hn(p->ai_canonname); + +				if (utility::stringUtils::isValidFQDN(hn)) { +					freeaddrinfo(info); +					return hn; +				} +			} +		} + +		// Then, try to find an acceptable host name +		for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) { + +			if (p->ai_canonname) { + +				const string hn(p->ai_canonname); + +				if (isAcceptableHostname(hn)) { +					freeaddrinfo(info); +					return hn; +				} +			} +		} + +		freeaddrinfo(info); +	} + +	if (::strlen(hostname) == 0 || !isAcceptableHostname(hostname)) { +		::strcpy(hostname, "localhost.localdomain"); +	} + +	return hostname; +} + + +unsigned int posixHandler::getProcessId() const { + +	return ::getpid(); +} + + +unsigned int posixHandler::getThreadId() const { + +#if VMIME_HAVE_GETTID +	return static_cast <unsigned int>(::gettid()); +#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID +	return static_cast <unsigned int>(::syscall(SYS_gettid)); +#elif VMIME_HAVE_GETTHRID  // OpenBSD +	return static_cast <unsigned int>(::getthrid()); +#else +	#error We have no implementation of getThreadId() for this platform! +#endif + +} + + +#if VMIME_HAVE_MESSAGING_FEATURES + +shared_ptr <vmime::net::socketFactory> posixHandler::getSocketFactory() { + +	return m_socketFactory; +} + +#endif + + +#if VMIME_HAVE_FILESYSTEM_FEATURES + +shared_ptr <vmime::utility::fileSystemFactory> posixHandler::getFileSystemFactory() { + +	return m_fileSysFactory; +} + + +shared_ptr <vmime::utility::childProcessFactory> posixHandler::getChildProcessFactory() { + +	return m_childProcFactory; +} + +#endif + + +void posixHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count) { + +	int fd = open("/dev/urandom", O_RDONLY); + +	if (fd != -1) { + +		read(fd, buffer, count); +		close(fd); + +	} else {  // fallback + +		for (unsigned int i = 0 ; i < count ; ++i) { +			buffer[i] = static_cast <unsigned char>(rand() % 255); +		} +	} +} + + +shared_ptr <utility::sync::criticalSection> posixHandler::createCriticalSection() { + +	return make_shared <posixCriticalSection>(); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.hpp b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp new file mode 100644 index 0000000..30417f1 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp @@ -0,0 +1,103 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX + + +#include "vmime/platform.hpp" + +#if VMIME_HAVE_MESSAGING_FEATURES +	#include "vmime/platforms/posix/posixSocket.hpp" +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +     #include "vmime/platforms/posix/posixFile.hpp" +     #include "vmime/platforms/posix/posixChildProcess.hpp" +#endif + + +namespace vmime { +namespace platforms { +namespace posix { + + +class VMIME_EXPORT posixHandler : public vmime::platform::handler { + +public: + +	posixHandler(); +	~posixHandler(); + +	unsigned long getUnixTime() const; + +	const vmime::datetime getCurrentLocalTime() const; + +	const vmime::charset getLocalCharset() const; + +	const vmime::string getHostName() const; + +	unsigned int getProcessId() const; +	unsigned int getThreadId() const; + +#if VMIME_HAVE_MESSAGING_FEATURES +	shared_ptr <vmime::net::socketFactory> getSocketFactory(); +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +	shared_ptr <vmime::utility::fileSystemFactory> getFileSystemFactory(); + +	shared_ptr <vmime::utility::childProcessFactory> getChildProcessFactory(); +#endif + +	void generateRandomBytes(unsigned char* buffer, const unsigned int count); + +	shared_ptr <utility::sync::criticalSection> createCriticalSection(); + +private: + +#if VMIME_HAVE_MESSAGING_FEATURES +	shared_ptr <posixSocketFactory> m_socketFactory; +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +	shared_ptr <posixFileSystemFactory> m_fileSysFactory; +	shared_ptr <posixChildProcessFactory> m_childProcFactory; +#endif +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX + +#endif // VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.cpp b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp new file mode 100644 index 0000000..aec6a83 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp @@ -0,0 +1,969 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES + + +#include "vmime/platforms/posix/posixSocket.hpp" +#include "vmime/platforms/posix/posixHandler.hpp" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE  // for getaddrinfo_a() in <netdb.h> +#endif + +#include <unistd.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <netdb.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <poll.h> + +#include "vmime/utility/stringUtils.hpp" + +#include "vmime/exception.hpp" + + +#if defined(EWOULDBLOCK) +#   define IS_EAGAIN(x)  ((x) == EAGAIN || (x) == EWOULDBLOCK || (x) == EINTR || (x) == EINPROGRESS) +#else +#   define IS_EAGAIN(x)  ((x) == EAGAIN || (x) == EINTR || (x) == EINPROGRESS) +#endif + + +// Workaround for detection of strerror_r variants +#if VMIME_HAVE_STRERROR_R + +namespace { + +char* vmime_strerror_r_result(int /* res */, char* buf) { + +	// XSI-compliant prototype: +	// int strerror_r(int errnum, char *buf, size_t buflen); +	return buf; +} + +char* vmime_strerror_r_result(char* res, char* /* buf */) { + +	// GNU-specific prototype: +	// char *strerror_r(int errnum, char *buf, size_t buflen); +	return res; +} + +} + +#endif // VMIME_HAVE_STRERROR_R + + + +namespace vmime { +namespace platforms { +namespace posix { + + +// +// posixSocket +// + +posixSocket::posixSocket(shared_ptr <vmime::net::timeoutHandler> th) +	: m_timeoutHandler(th), +	  m_desc(-1), +	  m_status(0) { + +} + + +posixSocket::~posixSocket() { + +	if (m_desc != -1) { +		::close(m_desc); +	} +} + + +void posixSocket::connect(const vmime::string& address, const vmime::port_t port) { + +	// Close current connection, if any +	if (m_desc != -1) { +		::close(m_desc); +		m_desc = -1; +	} + +	if (m_tracer) { + +		std::ostringstream trace; +		trace << "Connecting to " << address << ", port " << port; + +		m_tracer->traceSend(trace.str()); +	} + +#if VMIME_HAVE_GETADDRINFO  // use thread-safe and IPv6-aware getaddrinfo() if available + +	// Resolve address, if needed +	m_serverAddress = address; + +	struct ::addrinfo* addrInfo = NULL;  // resolved addresses +	resolve(&addrInfo, address, port); + +	// Connect to host +	int sock = -1; +	int connectErrno = 0; + +	if (m_timeoutHandler != NULL) { +		m_timeoutHandler->resetTimeOut(); +	} + +	for (struct ::addrinfo* curAddrInfo = addrInfo ; +	     sock == -1 && curAddrInfo != NULL ; +	     curAddrInfo = curAddrInfo->ai_next, connectErrno = ETIMEDOUT) { + +		if (curAddrInfo->ai_family != AF_INET && curAddrInfo->ai_family != AF_INET6) { +			continue; +		} + +		sock = ::socket(curAddrInfo->ai_family, curAddrInfo->ai_socktype, curAddrInfo->ai_protocol); + +		if (sock < 0) { +			connectErrno = errno; +			continue;  // try next +		} + +#if VMIME_HAVE_SO_KEEPALIVE + +		// Enable TCP Keepalive +		int keepAlive_optval = 1; +		socklen_t keepAlive_optlen = sizeof(keepAlive_optval); + +		::setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive_optval, keepAlive_optlen); + +#endif // VMIME_HAVE_SO_KEEPALIVE + +#if VMIME_HAVE_SO_NOSIGPIPE + +		// Return EPIPE instead of generating SIGPIPE +		int nosigpipe_optval = 1; +		socklen_t nosigpipe_optlen = sizeof(nosigpipe_optval); + +		::setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe_optval, nosigpipe_optlen); + +#endif // VMIME_HAVE_SO_NOSIGPIPE + + +		if (m_timeoutHandler) { + +			::fcntl(sock, F_SETFL, ::fcntl(sock, F_GETFL) | O_NONBLOCK); + +			if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->ai_addrlen) < 0) { + +				switch (errno) { + +					case 0: +					case EINPROGRESS: +					case EINTR: +#if defined(EAGAIN) +					case EAGAIN: +#endif // EAGAIN +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) +					case EWOULDBLOCK: +#endif // EWOULDBLOCK + +						// Connection in progress +						break; + +					default: + +						connectErrno = errno; +						::close(sock); +						sock = -1; +						continue;  // try next +				} + +				// Wait for socket to be connected. +				bool connected = false; + +				const int pollTimeout = 1000;   // poll() timeout (ms) +				const int tryNextTimeout = 5000;  // maximum time before trying next (ms) + +				timeval startTime = { 0, 0 }; +				gettimeofday(&startTime, /* timezone */ NULL); + +				do { + +					pollfd fds[1]; +					fds[0].fd = sock; +					fds[0].events = POLLIN | POLLOUT; + +					const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), pollTimeout); + +					// Success +					if (ret > 0) { + +						if (fds[0].revents & (POLLIN | POLLOUT)) { + +							int error = 0; +							socklen_t len = sizeof(error); + +							if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + +								connectErrno = errno; + +							} else { + +								if (error != 0) { +									connectErrno = error; +								} else { +									connected = true; +								} +							} +						} + +						break; + +					// Error +					} else if (ret < -1) { + +						if (errno != EAGAIN && errno != EINTR) { + +							// Cancel connection +							connectErrno = errno; +							break; +						} +					} + +					// Check for timeout +					if (m_timeoutHandler->isTimeOut()) { + +						if (!m_timeoutHandler->handleTimeOut()) { + +							// Cancel connection +							connectErrno = ETIMEDOUT; +							break; + +						} else { + +							// Reset timeout and keep waiting for connection +							m_timeoutHandler->resetTimeOut(); +						} + +					} else { + +						// Keep waiting for connection +					} + +					timeval curTime = { 0, 0 }; +					gettimeofday(&curTime, /* timezone */ NULL); + +					if (curAddrInfo->ai_next != NULL && +						curTime.tv_usec - startTime.tv_usec >= tryNextTimeout * 1000) { + +						connectErrno = ETIMEDOUT; +						break; +					} + +				} while (true); + +				if (!connected) { + +					::close(sock); +					sock = -1; +					continue;  // try next +				} + +				break; + +			} else { + +				// Connection successful +				break; +			} + +		} else { + +			if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->ai_addrlen) < 0) { + +				connectErrno = errno; +				::close(sock); +				sock = -1; +				continue;  // try next +			} +		} +	} + +	::freeaddrinfo(addrInfo); + +	if (sock == -1) { + +		try { +			throwSocketError(connectErrno); +		} catch (exceptions::socket_exception& e) {  // wrap +			throw vmime::exceptions::connection_error("Error while connecting socket.", e); +		} +	} + +	m_desc = sock; + +#else // !VMIME_HAVE_GETADDRINFO + +	// Resolve address +	::sockaddr_in addr; + +	memset(&addr, 0, sizeof(addr)); + +	addr.sin_family = AF_INET; +	addr.sin_port = htons(static_cast <unsigned short>(port)); +	addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + +	if (addr.sin_addr.s_addr == static_cast <in_addr_t>(-1)) { + +		::hostent* hostInfo = ::gethostbyname(address.c_str()); + +		if (hostInfo == NULL) { +			// Error: cannot resolve address +			throw vmime::exceptions::connection_error("Cannot resolve address."); +		} + +		::memcpy(reinterpret_cast <char*>(&addr.sin_addr), hostInfo->h_addr, hostInfo->h_length); +	} + +	m_serverAddress = address; + +	// Get a new socket +	m_desc = ::socket(AF_INET, SOCK_STREAM, 0); + +	if (m_desc == -1) { + +		try { +			throwSocketError(errno); +		} catch (exceptions::socket_exception& e) {  // wrap +			throw vmime::exceptions::connection_error("Error while creating socket.", e); +		} +	} + +	// Start connection +	if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1) { + +		try { + +			throwSocketError(errno); + +		} catch (exceptions::socket_exception& e) {  // wrap + +			::close(m_desc); +			m_desc = -1; + +			// Error +			throw vmime::exceptions::connection_error("Error while connecting socket.", e); +		} +	} + +#endif // VMIME_HAVE_GETADDRINFO + +	::fcntl(m_desc, F_SETFL, ::fcntl(m_desc, F_GETFL) | O_NONBLOCK); +} + + +void posixSocket::resolve( +	struct ::addrinfo** addrInfo, +	const vmime::string& address, +	const vmime::port_t port +) { + +	char portStr[16]; +	snprintf(portStr, sizeof(portStr), "%u", static_cast <unsigned int>(port)); + + +	struct ::addrinfo hints; +	memset(&hints, 0, sizeof(hints)); + +	hints.ai_flags = AI_CANONNAME | AI_NUMERICSERV; +	hints.ai_family = PF_UNSPEC; +	hints.ai_socktype = SOCK_STREAM; + +#if VMIME_HAVE_GETADDRINFO_A + +	// If getaddrinfo_a() is available, use asynchronous resolving to allow +	// the timeout handler to cancel the operation + +	struct ::gaicb gaiRequest; +	memset(&gaiRequest, 0, sizeof(gaiRequest)); + +	gaiRequest.ar_name = address.c_str(); +	gaiRequest.ar_service = portStr; +	gaiRequest.ar_request = &hints; + +	struct ::gaicb* gaiRequests = &gaiRequest; +	int gaiError; + +	if ((gaiError = getaddrinfo_a(GAI_NOWAIT, &gaiRequests, 1, NULL)) != 0) { + +		throw vmime::exceptions::connection_error( +			"getaddrinfo_a() failed: " + std::string(gai_strerror(gaiError)) +		); +	} + +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} + +	while (true) { + +		struct timespec gaiTimeout; +		gaiTimeout.tv_sec = 1;  // query timeout handler every second +		gaiTimeout.tv_nsec = 0; + +		gaiError = gai_suspend(&gaiRequests, 1, &gaiTimeout); + +		if (gaiError == 0 || gaiError == EAI_ALLDONE) { + +			const int ret = gai_error(&gaiRequest); + +			if (ret != 0) { + +				throw vmime::exceptions::connection_error( +					"getaddrinfo_a() request failed: " + std::string(gai_strerror(ret)) +				); + +			} else { + +				*addrInfo = gaiRequest.ar_result; +				break; +			} + +		} else if (gaiError != EAI_AGAIN) { + +			if (gaiError == EAI_SYSTEM) { + +				const int ret = gai_error(&gaiRequest); + +				if (ret != EAI_INPROGRESS && errno != 0) { + +					try { +						throwSocketError(errno); +					} catch (exceptions::socket_exception& e) {  // wrap +						throw vmime::exceptions::connection_error("Error while connecting socket.", e); +					} +				} + +			} else { + +				throw vmime::exceptions::connection_error( +					"gai_suspend() failed: " + std::string(gai_strerror(gaiError)) +				); +			} +		} + +		// Check for timeout +		if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				throw exceptions::operation_timed_out(); + +			} else { + +				// Reset timeout and keep waiting for connection +				m_timeoutHandler->resetTimeOut(); +			} +		} +	} + +#else  // !VMIME_HAVE_GETADDRINFO_A + +	if (::getaddrinfo(address.c_str(), portStr, &hints, addrInfo) != 0) { + +		// Error: cannot resolve address +		throw vmime::exceptions::connection_error("Cannot resolve address."); +	} + +#endif  // VMIME_HAVE_GETADDRINFO_A + +} + + +bool posixSocket::isConnected() const { + +	if (m_desc == -1) { +		return false; +	} + +	char buff; + +	return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0; +} + + +void posixSocket::disconnect() { + +	if (m_desc != -1) { + +		if (m_tracer) { +			m_tracer->traceSend("Disconnecting"); +		} + +		::shutdown(m_desc, SHUT_RDWR); +		::close(m_desc); + +		m_desc = -1; +	} +} + + +static bool isNumericAddress(const char* address) { + +#if VMIME_HAVE_GETADDRINFO + +	struct addrinfo hint, *info = NULL; +	memset(&hint, 0, sizeof(hint)); + +	hint.ai_family = AF_UNSPEC; +	hint.ai_flags = AI_NUMERICHOST; + +	if (getaddrinfo(address, 0, &hint, &info) == 0) { + +		freeaddrinfo(info); +		return true; + +	} else { + +		return false; +	} + +#else + +	return inet_addr(address) != INADDR_NONE; + +#endif + +} + + +const string posixSocket::getPeerAddress() const { + +	// Get address of connected peer +	sockaddr peer; +	socklen_t peerLen = sizeof(peer); + +	if (getpeername(m_desc, &peer, &peerLen) != 0) { +		throwSocketError(errno); +	} + +	// Convert to numerical presentation format +	char buf[INET6_ADDRSTRLEN]; + +	if (!inet_ntop(peer.sa_family, &(reinterpret_cast <struct sockaddr_in *>(&peer))->sin_addr, buf, sizeof(buf))) { +		throwSocketError(errno); +	} + +	return string(buf); +} + + +const string posixSocket::getPeerName() const { + +	// Get address of connected peer +	sockaddr peer; +	socklen_t peerLen = sizeof(peer); + +	if (getpeername(m_desc, &peer, &peerLen) != 0) { +		throwSocketError(errno); +	} + +	// If server address as specified when connecting is a numeric +	// address, try to get a host name for it +	if (isNumericAddress(m_serverAddress.c_str())) { + +#if VMIME_HAVE_GETNAMEINFO + +		char host[NI_MAXHOST + 1]; +		char service[NI_MAXSERV + 1]; + +		if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen, +				host, sizeof(host), service, sizeof(service), +				/* flags */ NI_NAMEREQD) == 0) { + +			return string(host); +		} + +#else + +		struct hostent *hp; + +		if ((hp = gethostbyaddr(reinterpret_cast <const void *>(&peer), +				sizeof(peer), peer.sa_family)) != NULL) { + +			return string(hp->h_name); +		} + +#endif + +	} + +	return m_serverAddress; +} + + +size_t posixSocket::getBlockSize() const { + +	return 16384;  // 16 KB +} + + +bool posixSocket::waitForData(const bool read, const bool write, const int msecs) { + +	for (int i = 0 ; i <= msecs / 10 ; ++i) { + +		// Check whether data is available +		pollfd fds[1]; +		fds[0].fd = m_desc; +		fds[0].events = 0; + +		if (read) { +			fds[0].events |= POLLIN; +		} + +		if (write) { +			fds[0].events |= POLLOUT; +		} + +		const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), 10 /* ms */); + +		if (ret < 0) { + +			if (errno != EAGAIN && errno != EINTR) { +				throwSocketError(errno); +			} + +		} else if (ret > 0) { + +			if (fds[0].revents & (POLLIN | POLLOUT)) { +				return true; +			} +		} + +		// No data available at this time +		// Check if we are timed out +		if (m_timeoutHandler && +		    m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				// Server did not react within timeout delay +				throw exceptions::operation_timed_out(); + +			} else { + +				// Reset timeout +				m_timeoutHandler->resetTimeOut(); +			} +		} +	} + +	return false;  // time out +} + + +bool posixSocket::waitForRead(const int msecs) { + +	return waitForData(/* read */ true, /* write */ false, msecs); +} + + +bool posixSocket::waitForWrite(const int msecs) { + +	return waitForData(/* read */ false, /* write */ true, msecs); +} + + +void posixSocket::receive(vmime::string& buffer) { + +	const size_t size = receiveRaw(m_buffer, sizeof(m_buffer)); +	buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size); +} + + +size_t posixSocket::receiveRaw(byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +	// Check whether data is available +	if (!waitForRead(50 /* msecs */)) { + +		m_status |= STATUS_WOULDBLOCK; + +		// Continue waiting for data +		return 0; +	} + +	// Read available data +	ssize_t ret = ::recv(m_desc, buffer, count, 0); + +	if (ret < 0) { + +		if (!IS_EAGAIN(errno)) { +			throwSocketError(errno); +		} + +		// Check if we are timed out +		if (m_timeoutHandler && +		    m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				// Server did not react within timeout delay +				throwSocketError(errno); + +			} else { + +				// Reset timeout +				m_timeoutHandler->resetTimeOut(); +			} +		} + +		m_status |= STATUS_WOULDBLOCK; + +		// No data available at this time +		return 0; + +	} else if (ret == 0) { + +		// Host shutdown +		throwSocketError(ENOTCONN); + +	} else { + +		// Data received, reset timeout +		if (m_timeoutHandler) { +			m_timeoutHandler->resetTimeOut(); +		} +	} + +	return ret; +} + + +void posixSocket::send(const vmime::string& buffer) { + +	sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); +} + + +void posixSocket::send(const char* str) { + +	sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str)); +} + + +void posixSocket::sendRaw(const byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +	size_t size = count; + +	while (size > 0) { + +#if VMIME_HAVE_MSG_NOSIGNAL +		const ssize_t ret = ::send(m_desc, buffer, size, MSG_NOSIGNAL); +#else +		const ssize_t ret = ::send(m_desc, buffer, size, 0); +#endif + +		if (ret <= 0) { + +			if (ret < 0 && !IS_EAGAIN(errno)) { +				throwSocketError(errno); +			} + +			waitForWrite(50 /* msecs */); + +		} else { + +			buffer += ret; +			size -= ret; +		} +	} + +	// Reset timeout +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} +} + + +size_t posixSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +#if VMIME_HAVE_MSG_NOSIGNAL +	const ssize_t ret = ::send(m_desc, buffer, count, MSG_NOSIGNAL); +#else +	const ssize_t ret = ::send(m_desc, buffer, count, 0); +#endif + +	if (ret <= 0) { + +		if (ret < 0 && !IS_EAGAIN(errno)) { +			throwSocketError(errno); +		} + +		// Check if we are timed out +		if (m_timeoutHandler && +		    m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				// Could not send data within timeout delay +				throw exceptions::operation_timed_out(); + +			} else { + +				// Reset timeout +				m_timeoutHandler->resetTimeOut(); +			} +		} + +		m_status |= STATUS_WOULDBLOCK; + +		// No data can be written at this time +		return 0; +	} + +	// Reset timeout +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} + +	return ret; +} + + +void posixSocket::throwSocketError(const int err) { + +	const char* msg = NULL; + +	switch (err) { + +		case EACCES:          msg = "EACCES: permission denied"; break; +		case EAFNOSUPPORT:    msg = "EAFNOSUPPORT: address family not supported"; break; +		case EMFILE:          msg = "EMFILE: process file table overflow"; break; +		case ENFILE:          msg = "ENFILE: system limit reached"; break; +		case EPROTONOSUPPORT: msg = "EPROTONOSUPPORT: protocol not supported"; break; +		case EAGAIN:          msg = "EGAIN: blocking operation"; break; +		case EBADF:           msg = "EBADF: invalid descriptor"; break; +		case ECONNRESET:      msg = "ECONNRESET: connection reset by peer"; break; +		case EFAULT:          msg = "EFAULT: bad user space address"; break; +		case EINTR:           msg = "EINTR: signal occurred before transmission"; break; +		case EINVAL:          msg = "EINVAL: invalid argument"; break; +		case EMSGSIZE:        msg = "EMSGSIZE: message cannot be sent atomically"; break; +		case ENOBUFS:         msg = "ENOBUFS: output queue is full"; break; +		case ENOMEM:          msg = "ENOMEM: out of memory"; break; +		case EPIPE:           msg = "EPIPE: broken pipe"; break; +		case ENOTCONN:        msg = "ENOTCONN: not connected"; break; +		case ECONNREFUSED:    msg = "ECONNREFUSED: connection refused"; break; +	} + +	if (msg) { + +		throw exceptions::socket_exception(msg); + +	} else { + +		// Use strerror() to get string describing error number + +#if VMIME_HAVE_STRERROR_R + +		char errbuf[512]; + +		throw exceptions::socket_exception( +			vmime_strerror_r_result( +				strerror_r(err, errbuf, sizeof(errbuf)), +				errbuf +			) +		); + +#else  // !VMIME_HAVE_STRERROR_R + +		const std::string strmsg(strerror(err)); +		throw exceptions::socket_exception(strmsg); + +#endif  // VMIME_HAVE_STRERROR_R + +	} +} + + +unsigned int posixSocket::getStatus() const { + +	return m_status; +} + + +shared_ptr <net::timeoutHandler> posixSocket::getTimeoutHandler() { + +	return m_timeoutHandler; +} + + +void posixSocket::setTracer(const shared_ptr <net::tracer>& tracer) { + +	m_tracer = tracer; +} + + +shared_ptr <net::tracer> posixSocket::getTracer() { + +	return m_tracer; +} + + + +// +// posixSocketFactory +// + +shared_ptr <vmime::net::socket> posixSocketFactory::create() { + +	shared_ptr <vmime::net::timeoutHandler> th; +	return make_shared <posixSocket>(th); +} + + +shared_ptr <vmime::net::socket> posixSocketFactory::create(const shared_ptr <vmime::net::timeoutHandler>& th) { + +	return make_shared <posixSocket>(th); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.hpp b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp new file mode 100644 index 0000000..7d732b7 --- /dev/null +++ b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp @@ -0,0 +1,118 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED +#define VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES + + +#include "vmime/net/socket.hpp" + + +struct addrinfo; + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixSocket : public vmime::net::socket { + +public: + +	posixSocket(shared_ptr <vmime::net::timeoutHandler> th); +	~posixSocket(); + +	void connect(const vmime::string& address, const vmime::port_t port); +	bool isConnected() const; +	void disconnect(); + +	bool waitForRead(const int msecs = 30000); +	bool waitForWrite(const int msecs = 30000); + +	void receive(vmime::string& buffer); +	size_t receiveRaw(byte_t* buffer, const size_t count); + +	void send(const vmime::string& buffer); +	void send(const char* str); +	void sendRaw(const byte_t* buffer, const size_t count); +	size_t sendRawNonBlocking(const byte_t* buffer, const size_t count); + +	size_t getBlockSize() const; + +	unsigned int getStatus() const; + +	const string getPeerName() const; +	const string getPeerAddress() const; + +	shared_ptr <net::timeoutHandler> getTimeoutHandler(); + +	void setTracer(const shared_ptr <net::tracer>& tracer); +	shared_ptr <net::tracer> getTracer(); + +protected: + +	void resolve(struct ::addrinfo** addrInfo, const vmime::string& address, const vmime::port_t port); + +	bool waitForData(const bool read, const bool write, const int msecs); + +	static void throwSocketError(const int err); + +private: + +	shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler; +	shared_ptr <net::tracer> m_tracer; + +	byte_t m_buffer[65536]; +	int m_desc; + +	unsigned int m_status; + +	string m_serverAddress; +}; + + + +class posixSocketFactory : public vmime::net::socketFactory { + +public: + +	shared_ptr <vmime::net::socket> create(); +	shared_ptr <vmime::net::socket> create(const shared_ptr <vmime::net::timeoutHandler>& th); +}; + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES + +#endif // VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp b/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp new file mode 100644 index 0000000..1457c59 --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp @@ -0,0 +1,197 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED +#define VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS + + +#include <string.h> + + +namespace vmime { +namespace platforms { +namespace windows { + + +struct windowsCodepages { + +	static int getByName(const char* s8_Name) { + +		if (stricmp(s8_Name, "ASMO-708")          == 0) return 708; +		if (stricmp(s8_Name, "big5")              == 0) return 950; +		if (stricmp(s8_Name, "cp1025")            == 0) return 21025; +		if (stricmp(s8_Name, "cp866")             == 0) return 866; +		if (stricmp(s8_Name, "cp875")             == 0) return 875; +		if (stricmp(s8_Name, "DOS-720")           == 0) return 720; +		if (stricmp(s8_Name, "DOS-862")           == 0) return 862; +		if (stricmp(s8_Name, "EUC-CN")            == 0) return 51936; +		if (stricmp(s8_Name, "euc-jp")            == 0) return 51932; +		if (stricmp(s8_Name, "EUC-JP")            == 0) return 20932; +		if (stricmp(s8_Name, "euc-kr")            == 0) return 51949; +		if (stricmp(s8_Name, "GB18030")           == 0) return 54936; +		if (stricmp(s8_Name, "GBK")	          == 0) return 54936; +		if (stricmp(s8_Name, "gb2312")            == 0) return 936; +		if (stricmp(s8_Name, "hz-gb-2312")        == 0) return 52936; +		if (stricmp(s8_Name, "IBM00858")          == 0) return 858; +		if (stricmp(s8_Name, "IBM00924")          == 0) return 20924; +		if (stricmp(s8_Name, "IBM01047")          == 0) return 1047; +		if (stricmp(s8_Name, "IBM01140")          == 0) return 1140; +		if (stricmp(s8_Name, "IBM01141")          == 0) return 1141; +		if (stricmp(s8_Name, "IBM01142")          == 0) return 1142; +		if (stricmp(s8_Name, "IBM01143")          == 0) return 1143; +		if (stricmp(s8_Name, "IBM01144")          == 0) return 1144; +		if (stricmp(s8_Name, "IBM01145")          == 0) return 1145; +		if (stricmp(s8_Name, "IBM01146")          == 0) return 1146; +		if (stricmp(s8_Name, "IBM01147")          == 0) return 1147; +		if (stricmp(s8_Name, "IBM01148")          == 0) return 1148; +		if (stricmp(s8_Name, "IBM01149")          == 0) return 1149; +		if (stricmp(s8_Name, "IBM037")            == 0) return 37; +		if (stricmp(s8_Name, "IBM1026")           == 0) return 1026; +		if (stricmp(s8_Name, "IBM273")            == 0) return 20273; +		if (stricmp(s8_Name, "IBM277")            == 0) return 20277; +		if (stricmp(s8_Name, "IBM278")            == 0) return 20278; +		if (stricmp(s8_Name, "IBM280")            == 0) return 20280; +		if (stricmp(s8_Name, "IBM284")            == 0) return 20284; +		if (stricmp(s8_Name, "IBM285")            == 0) return 20285; +		if (stricmp(s8_Name, "IBM290")            == 0) return 20290; +		if (stricmp(s8_Name, "IBM297")            == 0) return 20297; +		if (stricmp(s8_Name, "IBM420")            == 0) return 20420; +		if (stricmp(s8_Name, "IBM423")            == 0) return 20423; +		if (stricmp(s8_Name, "IBM424")            == 0) return 20424; +		if (stricmp(s8_Name, "IBM437")            == 0) return 437; +		if (stricmp(s8_Name, "IBM500")            == 0) return 500; +		if (stricmp(s8_Name, "ibm737")            == 0) return 737; +		if (stricmp(s8_Name, "ibm775")            == 0) return 775; +		if (stricmp(s8_Name, "ibm850")            == 0) return 850; +		if (stricmp(s8_Name, "ibm852")            == 0) return 852; +		if (stricmp(s8_Name, "IBM855")            == 0) return 855; +		if (stricmp(s8_Name, "ibm857")            == 0) return 857; +		if (stricmp(s8_Name, "IBM860")            == 0) return 860; +		if (stricmp(s8_Name, "ibm861")            == 0) return 861; +		if (stricmp(s8_Name, "IBM863")            == 0) return 863; +		if (stricmp(s8_Name, "IBM864")            == 0) return 864; +		if (stricmp(s8_Name, "IBM865")            == 0) return 865; +		if (stricmp(s8_Name, "ibm869")            == 0) return 869; +		if (stricmp(s8_Name, "IBM870")            == 0) return 870; +		if (stricmp(s8_Name, "IBM871")            == 0) return 20871; +		if (stricmp(s8_Name, "IBM880")            == 0) return 20880; +		if (stricmp(s8_Name, "IBM905")            == 0) return 20905; +		if (stricmp(s8_Name, "IBM-Thai")          == 0) return 20838; +		if (stricmp(s8_Name, "iso-2022-jp")       == 0) return 50222; +		if (stricmp(s8_Name, "iso-2022-kr")       == 0) return 50225; +		if (stricmp(s8_Name, "iso-8859-1")        == 0) return 28591; +		if (stricmp(s8_Name, "iso-8859-13")       == 0) return 28603; +		if (stricmp(s8_Name, "iso-8859-15")       == 0) return 28605; +		if (stricmp(s8_Name, "iso-8859-2")        == 0) return 28592; +		if (stricmp(s8_Name, "iso-8859-3")        == 0) return 28593; +		if (stricmp(s8_Name, "iso-8859-4")        == 0) return 28594; +		if (stricmp(s8_Name, "iso-8859-5")        == 0) return 28595; +		if (stricmp(s8_Name, "iso-8859-6")        == 0) return 28596; +		if (stricmp(s8_Name, "iso-8859-7")        == 0) return 28597; +		if (stricmp(s8_Name, "iso-8859-8")        == 0) return 28598; +		if (stricmp(s8_Name, "iso-8859-8-i")      == 0) return 38598; +		if (stricmp(s8_Name, "iso-8859-9")        == 0) return 28599; +		if (stricmp(s8_Name, "Johab")             == 0) return 1361; +		if (stricmp(s8_Name, "koi8-r")            == 0) return 20866; +		if (stricmp(s8_Name, "koi8-u")            == 0) return 21866; +		if (stricmp(s8_Name, "ks_c_5601-1987")    == 0) return 949; +		if (stricmp(s8_Name, "macintosh")         == 0) return 10000; +		if (stricmp(s8_Name, "unicodeFFFE")       == 0) return 1201; +		if (stricmp(s8_Name, "us-ascii")          == 0) return 20127; +		if (stricmp(s8_Name, "utf-16")            == 0) return 1200; +		if (stricmp(s8_Name, "utf-32")            == 0) return 12000; +		if (stricmp(s8_Name, "utf-32BE")          == 0) return 12001; +		if (stricmp(s8_Name, "utf-7")             == 0) return 65000; +		if (stricmp(s8_Name, "utf-8")             == 0) return 65001; +		if (stricmp(s8_Name, "windows-1250")      == 0) return 1250; +		if (stricmp(s8_Name, "windows-1251")      == 0) return 1251; +		if (stricmp(s8_Name, "Windows-1252")      == 0) return 1252; +		if (stricmp(s8_Name, "windows-1253")      == 0) return 1253; +		if (stricmp(s8_Name, "windows-1254")      == 0) return 1254; +		if (stricmp(s8_Name, "windows-1255")      == 0) return 1255; +		if (stricmp(s8_Name, "windows-1256")      == 0) return 1256; +		if (stricmp(s8_Name, "windows-1257")      == 0) return 1257; +		if (stricmp(s8_Name, "windows-1258")      == 0) return 1258; +		if (stricmp(s8_Name, "windows-874")       == 0) return 874; +		if (stricmp(s8_Name, "x-Chinese-CNS")     == 0) return 20000; +		if (stricmp(s8_Name, "x-Chinese-Eten")    == 0) return 20002; +		if (stricmp(s8_Name, "x-cp20001")         == 0) return 20001; +		if (stricmp(s8_Name, "x-cp20003")         == 0) return 20003; +		if (stricmp(s8_Name, "x-cp20004")         == 0) return 20004; +		if (stricmp(s8_Name, "x-cp20005")         == 0) return 20005; +		if (stricmp(s8_Name, "x-cp20261")         == 0) return 20261; +		if (stricmp(s8_Name, "x-cp20269")         == 0) return 20269; +		if (stricmp(s8_Name, "x-cp20936")         == 0) return 20936; +		if (stricmp(s8_Name, "x-cp20949")         == 0) return 20949; +		if (stricmp(s8_Name, "x-cp50227")         == 0) return 50227; +		if (stricmp(s8_Name, "x-EBCDIC-KoreanExtended") == 0) return 20833; +		if (stricmp(s8_Name, "x-Europa")          == 0) return 29001; +		if (stricmp(s8_Name, "x-IA5")             == 0) return 20105; +		if (stricmp(s8_Name, "x-IA5-German")      == 0) return 20106; +		if (stricmp(s8_Name, "x-IA5-Norwegian")   == 0) return 20108; +		if (stricmp(s8_Name, "x-IA5-Swedish")     == 0) return 20107; +		if (stricmp(s8_Name, "x-iscii-as")        == 0) return 57006; +		if (stricmp(s8_Name, "x-iscii-be")        == 0) return 57003; +		if (stricmp(s8_Name, "x-iscii-de")        == 0) return 57002; +		if (stricmp(s8_Name, "x-iscii-gu")        == 0) return 57010; +		if (stricmp(s8_Name, "x-iscii-ka")        == 0) return 57008; +		if (stricmp(s8_Name, "x-iscii-ma")        == 0) return 57009; +		if (stricmp(s8_Name, "x-iscii-or")        == 0) return 57007; +		if (stricmp(s8_Name, "x-iscii-pa")        == 0) return 57011; +		if (stricmp(s8_Name, "x-iscii-ta")        == 0) return 57004; +		if (stricmp(s8_Name, "x-iscii-te")        == 0) return 57005; +		if (stricmp(s8_Name, "x-mac-arabic")      == 0) return 10004; +		if (stricmp(s8_Name, "x-mac-ce")          == 0) return 10029; +		if (stricmp(s8_Name, "x-mac-chinesesimp") == 0) return 10008; +		if (stricmp(s8_Name, "x-mac-chinesetrad") == 0) return 10002; +		if (stricmp(s8_Name, "x-mac-croatian")    == 0) return 10082; +		if (stricmp(s8_Name, "x-mac-cyrillic")    == 0) return 10007; +		if (stricmp(s8_Name, "x-mac-greek")       == 0) return 10006; +		if (stricmp(s8_Name, "x-mac-hebrew")      == 0) return 10005; +		if (stricmp(s8_Name, "x-mac-icelandic")   == 0) return 10079; +		if (stricmp(s8_Name, "x-mac-japanese")    == 0) return 10001; +		if (stricmp(s8_Name, "x-mac-korean")      == 0) return 10003; +		if (stricmp(s8_Name, "x-mac-romanian")    == 0) return 10010; +		if (stricmp(s8_Name, "x-mac-thai")        == 0) return 10021; +		if (stricmp(s8_Name, "x-mac-turkish")     == 0) return 10081; +		if (stricmp(s8_Name, "x-mac-ukrainian")   == 0) return 10017; + +		throw exception(std::string("Unknown charset: ") + s8_Name); +	} +}; + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS + +#endif // VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp new file mode 100644 index 0000000..c0a0bec --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp @@ -0,0 +1,67 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS + + +#include "vmime/platforms/windows/windowsCriticalSection.hpp" + + +namespace vmime { +namespace platforms { +namespace windows { + + +windowsCriticalSection::windowsCriticalSection() { + +	InitializeCriticalSectionAndSpinCount(&m_cs, 0x400); +} + + +windowsCriticalSection::~windowsCriticalSection() { + +	DeleteCriticalSection(&m_cs); +} + + +void windowsCriticalSection::lock() { + +	EnterCriticalSection(&m_cs); +} + + +void windowsCriticalSection::unlock() { + +	LeaveCriticalSection(&m_cs); +} + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS diff --git a/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp new file mode 100644 index 0000000..ffe8294 --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp @@ -0,0 +1,68 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED +#define VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS + + +#include "vmime/utility/sync/criticalSection.hpp" + + +#include <windows.h> + + +namespace vmime { +namespace platforms { +namespace windows { + + +class windowsCriticalSection : public utility::sync::criticalSection { + +public: + +	windowsCriticalSection(); +	~windowsCriticalSection(); + +	void lock(); +	void unlock(); + +private: + +	CRITICAL_SECTION m_cs; +}; + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS + +#endif // VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/windows/windowsFile.cpp b/vmime-master/src/vmime/platforms/windows/windowsFile.cpp new file mode 100644 index 0000000..774731c --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsFile.cpp @@ -0,0 +1,712 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/platforms/windows/windowsFile.hpp" + +#include <windows.h> +#include <string.h> + +#include "vmime/exception.hpp" +#include "vmime/utility/stringUtils.hpp" + + +namespace vmime { +namespace platforms { +namespace windows { + + +shared_ptr <vmime::utility::file> windowsFileSystemFactory::create( +	const vmime::utility::file::path& path +) const { + +	return make_shared <windowsFile>(path); +} + + +const vmime::utility::file::path windowsFileSystemFactory::stringToPath( +	const vmime::string& str +) const { + +	return stringToPathImpl(str); +} + + +const vmime::string windowsFileSystemFactory::pathToString( +	const vmime::utility::file::path& path +) const { + +	return pathToStringImpl(path); +} + + +const vmime::utility::file::path windowsFileSystemFactory::stringToPathImpl( +	const vmime::string& str +) { + +	vmime::size_t offset = 0; +	vmime::size_t prev = 0; + +	vmime::utility::file::path path; + +	while ((offset = str.find_first_of("\\", offset)) != vmime::string::npos) { + +		if (offset != prev) { + +			path.appendComponent( +				vmime::utility::file::path::component( +					vmime::string(str.begin() + prev, str.begin() + offset) +				) +			); +		} + +		prev = offset + 1; +		offset++; +	} + +	if (prev < str.length()) { + +		path.appendComponent( +			vmime::utility::file::path::component( +				vmime::string(str.begin() + prev, str.end()) +			) +		); +	} + +	return path; +} + + +const vmime::string windowsFileSystemFactory::pathToStringImpl( +	const vmime::utility::file::path& path +) { + +	vmime::string native = ""; + +	for (int i = 0 ; i < path.getSize() ; ++i) { + +		if (i > 0) { +			native += "\\"; +		} + +		native += path[i].getBuffer(); +	} + +	return native; +} + + +bool windowsFileSystemFactory::isValidPathComponent( +	const vmime::utility::file::path::component& comp +) const { + +	return isValidPathComponent(comp, false); +} + + +bool windowsFileSystemFactory::isValidPathComponent( +	const vmime::utility::file::path::component& comp, +	bool firstComponent +) const { + +	const string& buffer = comp.getBuffer(); + +	// If first component, check if component is a drive +	if (firstComponent && (buffer.length() == 2) && (buffer[1] == ':')) { + +		char drive = tolower(buffer[0]); + +		if ((drive >= 'a') && (drive <= 'z')) { +			return true; +		} +	} + +	// Check for invalid characters +	for (size_t i = 0 ; i < buffer.length() ; ++i) { + +		const unsigned char c = buffer[i]; + +		switch (c) { + +			// Reserved characters +			case '<': case '>': case ':': +			case '"': case '/': case '\\': +			case '|': case '$': case '*': + +				return false; + +			default: + +				if (c <= 31) { +					return false; +				} +		} +	} + +	string upperBuffer = vmime::utility::stringUtils::toUpper(buffer); + +	// Check for reserved names +	if (upperBuffer.length() == 3) { + +		if (upperBuffer == "CON" || buffer == "PRN" || buffer == "AUX" || buffer == "NUL") { +			return false; +		} + +	} else if (upperBuffer.length() == 4) { + +		if ((upperBuffer.substr(0, 3) == "COM") && // COM0 to COM9 +		    (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) { + +			return false; + +		} else if ((upperBuffer.substr(0, 3) == "LPT") && // LPT0 to LPT9 +		           (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) { + +			return false; +		} +	} + +	return true; +} + + +bool windowsFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const { + +	for (int i = 0 ; i < path.getSize() ; ++i) { + +		if (!isValidPathComponent(path[i], (i == 0))) { +			return false; +		} +	} + +	return true; +} + + +void windowsFileSystemFactory::reportError(const vmime::utility::path& path, const int err) { + +	vmime::string desc; + +	LPVOID lpMsgBuf; + +	if (FormatMessage( +			FORMAT_MESSAGE_ALLOCATE_BUFFER | +			FORMAT_MESSAGE_FROM_SYSTEM | +			FORMAT_MESSAGE_IGNORE_INSERTS, +			NULL, +			err, +			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), +			(LPTSTR) &lpMsgBuf, +			0, +			NULL)) { + +		desc = (char*) lpMsgBuf; +		LocalFree(lpMsgBuf); +	} + +	throw vmime::exceptions::filesystem_exception(desc, path); +} + + + + +windowsFile::windowsFile(const vmime::utility::file::path& path) +	: m_path(path), +	  m_nativePath(windowsFileSystemFactory::pathToStringImpl(path)) { + +} + + +void windowsFile::createFile() { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_WRITE, +		FILE_SHARE_READ | FILE_SHARE_WRITE, +		NULL, +		CREATE_ALWAYS, +		FILE_ATTRIBUTE_NORMAL, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	CloseHandle(hFile); +} + + +void windowsFile::createDirectory(const bool createAll) { + +	createDirectoryImpl(m_path, m_path, createAll); +} + + +bool windowsFile::isFile() const { + +	DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str()); + +	if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) { +		return false; +	} + +	return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == 0; +} + + +bool windowsFile::isDirectory() const { + +	DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str()); + +	if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) { +		return false; +	} + +	return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; +} + + +bool windowsFile::canRead() const { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_READ, +		FILE_SHARE_READ, +		NULL, +		OPEN_EXISTING, +		FILE_ATTRIBUTE_NORMAL, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		return false; +	} + +	CloseHandle(hFile); + +	return true; +} + + +bool windowsFile::canWrite() const { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_WRITE, +		FILE_SHARE_WRITE, +		NULL, +		OPEN_ALWAYS, +		FILE_ATTRIBUTE_NORMAL, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		return false; +	} + +	CloseHandle(hFile); + +	return true; +} + + +windowsFile::length_type windowsFile::getLength() { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_READ, +		FILE_SHARE_READ, +		NULL, +		OPEN_EXISTING, +		FILE_ATTRIBUTE_NORMAL, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	DWORD dwSize = GetFileSize(hFile, NULL); + +	CloseHandle(hFile); + +	return dwSize; +} + + +const vmime::utility::path& windowsFile::getFullPath() const { + +	return m_path; +} + + +bool windowsFile::exists() const { + +	WIN32_FIND_DATA findData; +	HANDLE hFind = FindFirstFile(m_nativePath.c_str(), &findData); + +	if (hFind != INVALID_HANDLE_VALUE) { +		FindClose(hFind); +		return true; +	} + +	return false; +} + + +shared_ptr <vmime::utility::file> windowsFile::getParent() const { + +	if (m_path.isEmpty()) { +		return null; +	} else { +		return make_shared <windowsFile>(m_path.getParent()); +	} +} + + +void windowsFile::rename(const path& newName) { + +	const vmime::string newNativeName = windowsFileSystemFactory::pathToStringImpl(newName); + +	if (MoveFile(m_nativePath.c_str(), newNativeName.c_str())) { + +		m_path = newName; +		m_nativePath = newNativeName; + +	} else { + +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} +} + + +void windowsFile::remove() { + +	if (!DeleteFile(m_nativePath.c_str())) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} +} + + +shared_ptr <vmime::utility::fileWriter> windowsFile::getFileWriter() { + +	return make_shared <windowsFileWriter>(m_path, m_nativePath); +} + + +shared_ptr <vmime::utility::fileReader> windowsFile::getFileReader() { + +	return make_shared <windowsFileReader>(m_path, m_nativePath); +} + + +shared_ptr <vmime::utility::fileIterator> windowsFile::getFiles() const { + +	return make_shared <windowsFileIterator>(m_path, m_nativePath); +} + + +void windowsFile::createDirectoryImpl( +	const vmime::utility::file::path& fullPath, +	const vmime::utility::file::path& path, +	const bool recursive +) { + +	const vmime::string nativePath = windowsFileSystemFactory::pathToStringImpl(path); + +	windowsFile tmp(path); + +	if (tmp.isDirectory()) { +		return; +	} + +	if (!path.isEmpty() && recursive) { +		createDirectoryImpl(fullPath, path.getParent(), true); +	} + +	if (!CreateDirectory(nativePath.c_str(), NULL)) { +		windowsFileSystemFactory::reportError(fullPath, GetLastError()); +	} +} + + + +windowsFileIterator::windowsFileIterator( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath), +	  m_moreElements(false), +	  m_hFind(INVALID_HANDLE_VALUE) { + +	findFirst(); +} + + +windowsFileIterator::~windowsFileIterator() { + +	if (m_hFind != INVALID_HANDLE_VALUE) { +		FindClose(m_hFind); +	} +} + + +bool windowsFileIterator::hasMoreElements() const { + +	return m_moreElements; +} + + +shared_ptr <vmime::utility::file> windowsFileIterator::nextElement() { + +	shared_ptr <vmime::utility::file> pFile = make_shared <windowsFile>( +		m_path / vmime::utility::file::path::component(m_findData.cFileName) +	); + +	findNext(); + +	return pFile; +} + + +void windowsFileIterator::findFirst() { + +	m_hFind = FindFirstFile(m_nativePath.c_str(), &m_findData); + +	if (m_hFind == INVALID_HANDLE_VALUE) { +		m_moreElements = false; +		return; +	} + +	m_moreElements = true; + +	if (isCurrentOrParentDir()) { +		findNext(); +	} +} + + +void windowsFileIterator::findNext() { + +	do { + +		if (!FindNextFile(m_hFind, &m_findData)) { +			m_moreElements = false; +			return; +		} + +	} while (isCurrentOrParentDir()); +} + + +bool windowsFileIterator::isCurrentOrParentDir() const { + +	vmime::string s(m_findData.cFileName); + +	if ((s == ".") || (s == "..")) { +		return true; +	} + +	return false; +} + + + +windowsFileReader::windowsFileReader( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath) { + +} + + +shared_ptr <vmime::utility::inputStream> windowsFileReader::getInputStream() { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_READ, +		FILE_SHARE_READ, +		NULL, +		OPEN_EXISTING, +		0, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	return make_shared <windowsFileReaderInputStream>(m_path, hFile); +} + + +windowsFileReaderInputStream::windowsFileReaderInputStream( +	const vmime::utility::file::path& path, +	HANDLE hFile +) +	: m_path(path), +	  m_hFile(hFile) { + +} + +windowsFileReaderInputStream::~windowsFileReaderInputStream() { + +	CloseHandle(m_hFile); +} + + +bool windowsFileReaderInputStream::eof() const { + +	DWORD dwSize = GetFileSize(m_hFile, NULL); +	DWORD dwPosition = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); + +	return dwSize == dwPosition; +} + + +void windowsFileReaderInputStream::reset() { + +	SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN); +} + + +size_t windowsFileReaderInputStream::read(byte_t* const data, const size_t count) { + +	DWORD dwBytesRead; + +	if (!ReadFile(m_hFile, (LPVOID) data, (DWORD) count, &dwBytesRead, NULL)) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	return dwBytesRead; +} + + +size_t windowsFileReaderInputStream::skip(const size_t count) { + +	DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); +	DWORD dwNewPos = SetFilePointer(m_hFile, (LONG) count, NULL, FILE_CURRENT); + +	return dwNewPos - dwCurPos; +} + + +size_t windowsFileReaderInputStream::getPosition() const { + +	DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); + +	if (dwCurPos == INVALID_SET_FILE_POINTER) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	return static_cast <size_t>(dwCurPos); +} + +void windowsFileReaderInputStream::seek(const size_t pos) { + +	DWORD dwNewPos = SetFilePointer(m_hFile, (LONG) pos, NULL, FILE_BEGIN); + +	if (dwNewPos == INVALID_SET_FILE_POINTER) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} +} + + + +windowsFileWriter::windowsFileWriter( +	const vmime::utility::file::path& path, +	const vmime::string& nativePath +) +	: m_path(path), +	  m_nativePath(nativePath) { + +} + +shared_ptr <vmime::utility::outputStream> windowsFileWriter::getOutputStream() { + +	HANDLE hFile = CreateFile( +		m_nativePath.c_str(), +		GENERIC_WRITE, +		FILE_SHARE_WRITE, +		NULL, +		CREATE_ALWAYS, +		FILE_ATTRIBUTE_NORMAL, +		NULL +	); + +	if (hFile == INVALID_HANDLE_VALUE) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} + +	return make_shared <windowsFileWriterOutputStream>(m_path, hFile); +} + + +windowsFileWriterOutputStream::windowsFileWriterOutputStream( +	const vmime::utility::file::path& path, +	HANDLE hFile +) +	: m_path(path), +	  m_hFile(hFile) { + +} + + +windowsFileWriterOutputStream::~windowsFileWriterOutputStream() { + +	CloseHandle(m_hFile); +} + + +void windowsFileWriterOutputStream::writeImpl(const byte_t* const data, const size_t count) { + +	DWORD dwBytesWritten; + +	if (!WriteFile(m_hFile, data, (DWORD) count, &dwBytesWritten, NULL)) { +		windowsFileSystemFactory::reportError(m_path, GetLastError()); +	} +} + + +void windowsFileWriterOutputStream::flush() { + +	// TODO +} + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES + diff --git a/vmime-master/src/vmime/platforms/windows/windowsFile.hpp b/vmime-master/src/vmime/platforms/windows/windowsFile.hpp new file mode 100644 index 0000000..dc4b5ed --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsFile.hpp @@ -0,0 +1,225 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED +#define VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES + + +#include "vmime/utility/file.hpp" +#include "vmime/utility/seekableInputStream.hpp" + +#include <windows.h> + + +namespace vmime { +namespace platforms { +namespace windows { + + +class windowsFileSystemFactory : public vmime::utility::fileSystemFactory { + +public: + +	shared_ptr <vmime::utility::file> create(const vmime::utility::file::path& path) const; + +	const vmime::utility::file::path stringToPath(const vmime::string& str) const; +	const vmime::string pathToString(const vmime::utility::file::path& path) const; + +	static const vmime::utility::file::path stringToPathImpl(const vmime::string& str); +	static const vmime::string pathToStringImpl(const vmime::utility::file::path& path); + +	bool isValidPathComponent(const vmime::utility::file::path::component& comp) const; +	bool isValidPathComponent(const vmime::utility::file::path::component& comp, +		                              bool firstComponent) const; +	bool isValidPath(const vmime::utility::file::path& path) const; + +	static void reportError(const vmime::utility::path& path, const int err); +}; + + +class windowsFile : public vmime::utility::file { + +public: + +	windowsFile(const vmime::utility::file::path& path); + +	void createFile(); +	void createDirectory(const bool createAll = false); + +	bool isFile() const; +	bool isDirectory() const; + +	bool canRead() const; +	bool canWrite() const; + +	length_type getLength(); + +	const path& getFullPath() const; + +	bool exists() const; + +	shared_ptr <file> getParent() const; + +	void rename(const path& newName); +	void remove(); + +	shared_ptr <vmime::utility::fileWriter> getFileWriter(); + +	shared_ptr <vmime::utility::fileReader> getFileReader(); + +	shared_ptr <vmime::utility::fileIterator> getFiles() const; + +private: + +	static void createDirectoryImpl( +		const vmime::utility::file::path& fullPath, +		const vmime::utility::file::path& path, +		const bool recursive = false +	); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + +class windowsFileIterator : public vmime::utility::fileIterator { + +public: + +	windowsFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath); +	~windowsFileIterator(); + +	bool hasMoreElements() const; +	shared_ptr <vmime::utility::file> nextElement(); + +private: + +	void findFirst(); +	void findNext(); +	bool isCurrentOrParentDir() const; + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +	WIN32_FIND_DATA m_findData; +	bool m_moreElements; +	HANDLE m_hFind; +}; + + +class windowsFileReader : public vmime::utility::fileReader { + +public: + +	windowsFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath); + +public: + +	shared_ptr <vmime::utility::inputStream> getInputStream(); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + +class windowsFileReaderInputStream : public vmime::utility::inputStream { + +public: + +	windowsFileReaderInputStream(const vmime::utility::file::path& path, HANDLE hFile); +	~windowsFileReaderInputStream(); + +public: + +	bool eof() const; +	void reset(); +	size_t read(byte_t* const data, const size_t count); +	size_t skip(const size_t count); +	size_t getPosition() const; +	void seek(const size_t pos); + +private: + +	const vmime::utility::file::path m_path; +	HANDLE m_hFile; +}; + + +class windowsFileWriter : public vmime::utility::fileWriter { + +public: + +	windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath); + +public: + +	shared_ptr <vmime::utility::outputStream> getOutputStream(); + +private: + +	vmime::utility::file::path m_path; +	vmime::string m_nativePath; +}; + + +class windowsFileWriterOutputStream : public vmime::utility::outputStream { + +public: + +	windowsFileWriterOutputStream(const vmime::utility::file::path& path, HANDLE hFile); +	~windowsFileWriterOutputStream(); + +public: + +	void flush(); + +protected: + +	void writeImpl(const byte_t* const data, const size_t count); + +private: + +	const vmime::utility::file::path m_path; +	HANDLE m_hFile; +}; + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES + +#endif // VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp b/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp new file mode 100644 index 0000000..551f672 --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp @@ -0,0 +1,315 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS + + +#include "vmime/platforms/windows/windowsHandler.hpp" + +#include "vmime/platforms/windows/windowsCriticalSection.hpp" + +#include "vmime/utility/stringUtils.hpp" + +#include <time.h> +#include <locale.h> +#include <process.h> +#include <winsock2.h> // for WSAStartup() +#include <windows.h>  // for winnls.h +#include <ws2tcpip.h> +#include <wincrypt.h> + +#if VMIME_HAVE_MLANG +#   include <mlang.h> +#endif + + +namespace vmime { +namespace platforms { +namespace windows { + + +windowsHandler::windowsHandler() { + +	WSAData wsaData; +	WSAStartup(MAKEWORD(1, 1), &wsaData); + +#if VMIME_HAVE_MESSAGING_FEATURES +	m_socketFactory = make_shared <windowsSocketFactory>(); +#endif +#if VMIME_HAVE_FILESYSTEM_FEATURES +	m_fileSysFactory = make_shared <windowsFileSystemFactory>(); +#endif + +} + + +windowsHandler::~windowsHandler() { + +	WSACleanup(); +} + + +unsigned long windowsHandler::getUnixTime() const { + +	return static_cast <unsigned long>(::time(NULL)); +} + + +const vmime::datetime windowsHandler::getCurrentLocalTime() const { + +	const time_t t(::time(NULL)); + +	// Get the local time +#if VMIME_HAVE_LOCALTIME_S +	tm local; +	::localtime_s(&local, &t); +#elif VMIME_HAVE_LOCALTIME_R +	tm local; +	::localtime_r(&t, &local); +#else +	tm local = *::localtime(&t);  // WARNING: this is not thread-safe! +#endif + +	// Get the UTC time +#if VMIME_HAVE_GMTIME_S +	tm gmt; +	::gmtime_s(&gmt, &t); +#elif VMIME_HAVE_GMTIME_R +	tm gmt; +	::gmtime_r(&t, &gmt); +#else +	tm gmt = *::gmtime(&t);  // WARNING: this is not thread-safe! +#endif + +	// "A negative value for tm_isdst causes mktime() to attempt +	//  to determine whether Daylight Saving Time is in effect +	//  for the specified time." +	local.tm_isdst = -1; +	gmt.tm_isdst = -1; + +	// Calculate the difference (in seconds) +	const int diff = (const int)(::mktime(&local) - ::mktime(&gmt)); + +	// Return the date +	return vmime::datetime( +		local.tm_year + 1900, local.tm_mon + 1, local.tm_mday, +		local.tm_hour, local.tm_min, local.tm_sec, diff / 60  // minutes needed +	); +} + + +const vmime::charset windowsHandler::getLocalCharset() const { + +#if VMIME_HAVE_MLANG + +	char szCharset[256]; + +	CoInitialize(NULL); +	{ +		IMultiLanguage* pMultiLanguage; + +		CoCreateInstance( +			CLSID_CMultiLanguage, +			NULL, +			CLSCTX_INPROC_SERVER, +			IID_IMultiLanguage, +			(void**) &pMultiLanguage +		); + +		UINT codePage = GetACP(); +		MIMECPINFO cpInfo; +		pMultiLanguage->GetCodePageInfo(codePage, &cpInfo); + +		int nLengthW = lstrlenW(cpInfo.wszBodyCharset) + 1; + +		WideCharToMultiByte( +			codePage, 0, cpInfo.wszBodyCharset, nLengthW, +			szCharset, sizeof(szCharset), NULL, NULL +		); + +		pMultiLanguage->Release(); +	} +	CoUninitialize(); + +	return vmime::charset(szCharset); + +#else // VMIME_HAVE_MLANG + +	vmime::string ch = vmime::charsets::ISO8859_1; // default + +	switch (GetACP()) { + +		case 437: ch = vmime::charsets::CP_437; break; +		case 737: ch = vmime::charsets::CP_737; break; +		case 775: ch = vmime::charsets::CP_775; break; +		case 850: ch = vmime::charsets::CP_850; break; +		case 852: ch = vmime::charsets::CP_852; break; +		case 853: ch = vmime::charsets::CP_853; break; +		case 855: ch = vmime::charsets::CP_855; break; +		case 857: ch = vmime::charsets::CP_857; break; +		case 858: ch = vmime::charsets::CP_858; break; +		case 860: ch = vmime::charsets::CP_860; break; +		case 861: ch = vmime::charsets::CP_861; break; +		case 862: ch = vmime::charsets::CP_862; break; +		case 863: ch = vmime::charsets::CP_863; break; +		case 864: ch = vmime::charsets::CP_864; break; +		case 865: ch = vmime::charsets::CP_865; break; +		case 866: ch = vmime::charsets::CP_866; break; +		case 869: ch = vmime::charsets::CP_869; break; +		case 874: ch = vmime::charsets::CP_874; break; + +		case 1125: ch = vmime::charsets::CP_1125; break; +		case 1250: ch = vmime::charsets::CP_1250; break; +		case 1251: ch = vmime::charsets::CP_1251; break; +		case 1252: ch = vmime::charsets::CP_1252; break; +		case 1253: ch = vmime::charsets::CP_1253; break; +		case 1254: ch = vmime::charsets::CP_1254; break; +		case 1255: ch = vmime::charsets::CP_1255; break; +		case 1256: ch = vmime::charsets::CP_1256; break; +		case 1257: ch = vmime::charsets::CP_1257; break; + +		case 28591: ch = vmime::charsets::ISO8859_1; break; +		case 28592: ch = vmime::charsets::ISO8859_2; break; +		case 28593: ch = vmime::charsets::ISO8859_3; break; +		case 28594: ch = vmime::charsets::ISO8859_4; break; +		case 28595: ch = vmime::charsets::ISO8859_5; break; +		case 28596: ch = vmime::charsets::ISO8859_6; break; +		case 28597: ch = vmime::charsets::ISO8859_7; break; +		case 28598: ch = vmime::charsets::ISO8859_8; break; +		case 28599: ch = vmime::charsets::ISO8859_9; break; +		case 28605: ch = vmime::charsets::ISO8859_15; break; + +		case 65000: ch = vmime::charsets::UTF_7; break; +		case 65001: ch = vmime::charsets::UTF_8; break; +	} + +	return vmime::charset(ch); + +#endif + +} + + +const vmime::string windowsHandler::getHostName() const { + +	char hostname[1024]; +	DWORD hostnameLen; + +	// First, try to get a Fully-Qualified Domain Name (FQDN) +	for (int cnf = ComputerNameDnsHostname ; cnf <= ComputerNameDnsFullyQualified ; ++cnf) { + +		hostnameLen = sizeof(hostname); + +		if (GetComputerNameEx((COMPUTER_NAME_FORMAT) cnf, hostname, &hostnameLen)) { + +			const vmime::string hostnameStr(hostname); + +			if (utility::stringUtils::isValidFQDN(hostnameStr)) { +				return hostnameStr; +			} +		} +	} + +	// Anything else will be OK, as long as it is a valid hostname +	for (int cnf = 0 ; cnf < ComputerNameMax ; ++cnf) { + +		hostnameLen = sizeof(hostname); + +		if (GetComputerNameEx((COMPUTER_NAME_FORMAT) cnf, hostname, &hostnameLen)) { + +			const vmime::string hostnameStr(hostname); + +			if (utility::stringUtils::isValidHostname(hostnameStr)) { +				return hostnameStr; +			} +		} +	} + +	return "localhost.localdomain"; +} + + +unsigned int windowsHandler::getProcessId() const { + +	return static_cast <unsigned int>(::GetCurrentProcessId()); +} + + +unsigned int windowsHandler::getThreadId() const { + +	return static_cast <unsigned int>(::GetCurrentThreadId()); +} + + +#if VMIME_HAVE_MESSAGING_FEATURES + +shared_ptr <vmime::net::socketFactory> windowsHandler::getSocketFactory() { + +	return m_socketFactory; +} + +#endif + + +#if VMIME_HAVE_FILESYSTEM_FEATURES + +shared_ptr <vmime::utility::fileSystemFactory> windowsHandler::getFileSystemFactory() { + +	return m_fileSysFactory; +} + + +shared_ptr <vmime::utility::childProcessFactory> windowsHandler::getChildProcessFactory() { + +	// TODO: Not implemented +	return null; +} + +#endif + + +void windowsHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count) { + +	HCRYPTPROV cryptProvider = 0; +	CryptAcquireContext(&cryptProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); +	CryptGenRandom(cryptProvider, static_cast <unsigned long>(count), static_cast <unsigned char*>(buffer)); +	CryptReleaseContext(cryptProvider, 0); +} + + +shared_ptr <utility::sync::criticalSection> windowsHandler::createCriticalSection() { + +	return make_shared <windowsCriticalSection>(); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS + diff --git a/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp b/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp new file mode 100644 index 0000000..9dda256 --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp @@ -0,0 +1,101 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED +#define VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS + + +#include "vmime/platform.hpp" + +#if VMIME_HAVE_MESSAGING_FEATURES +	#include "vmime/platforms/windows/windowsSocket.hpp" +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +	 #include "vmime/platforms/windows/windowsFile.hpp" +#endif + + +namespace vmime { +namespace platforms { +namespace windows { + + +class VMIME_EXPORT windowsHandler : public vmime::platform::handler { + +public: + +	windowsHandler(); +	~windowsHandler(); + +	unsigned long getUnixTime() const; + +	const vmime::datetime getCurrentLocalTime() const; + +	const vmime::charset getLocalCharset() const; + +	const vmime::string getHostName() const; + +	unsigned int getProcessId() const; +	unsigned int getThreadId() const; + +#if VMIME_HAVE_MESSAGING_FEATURES +	shared_ptr <vmime::net::socketFactory> getSocketFactory(); +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +	shared_ptr <vmime::utility::fileSystemFactory> getFileSystemFactory(); + +	shared_ptr <vmime::utility::childProcessFactory> getChildProcessFactory(); +#endif + +	void generateRandomBytes(unsigned char* buffer, const unsigned int count); + +	shared_ptr <utility::sync::criticalSection> createCriticalSection(); + +private: + +#if VMIME_HAVE_MESSAGING_FEATURES +	shared_ptr <windowsSocketFactory> m_socketFactory; +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES +	shared_ptr <windowsFileSystemFactory> m_fileSysFactory; +#endif +}; + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS + +#endif // VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED diff --git a/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp b/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp new file mode 100644 index 0000000..3a93c53 --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp @@ -0,0 +1,547 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES + + +#pragma warning(disable: 4267) + +#include "vmime/platforms/windows/windowsSocket.hpp" + +#include "vmime/utility/stringUtils.hpp" +#include "vmime/exception.hpp" + +#include <ws2tcpip.h> + + +namespace vmime { +namespace platforms { +namespace windows { + + +// +// windowsSocket +// + +windowsSocket::windowsSocket(shared_ptr <vmime::net::timeoutHandler> th) +	: m_timeoutHandler(th), +	  m_desc(INVALID_SOCKET), +	  m_status(0) { + +	WSAData wsaData; +	WSAStartup(MAKEWORD(1, 1), &wsaData); +} + + +windowsSocket::~windowsSocket() { + +	if (m_desc != INVALID_SOCKET) { +		::closesocket(m_desc); +	} + +	WSACleanup(); +} + + +void windowsSocket::connect(const vmime::string& address, const vmime::port_t port) { + +	// Close current connection, if any +	if (m_desc != INVALID_SOCKET) { +		::closesocket(m_desc); +		m_desc = INVALID_SOCKET; +	} + +	// Resolve address +	::sockaddr_in addr; + +	memset(&addr, 0, sizeof(addr)); + +	addr.sin_family = AF_INET; +	addr.sin_port = htons(static_cast <unsigned short>(port)); +	addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + +	if (m_tracer) { + +		std::ostringstream trace; +		trace << "Connecting to " << address << ", port " << port; + +		m_tracer->traceSend(trace.str()); +	} + +	if (addr.sin_addr.s_addr == static_cast <int>(-1)) { + +		::hostent* hostInfo = ::gethostbyname(address.c_str()); + +		if (!hostInfo) { +			// Error: cannot resolve address +			throw vmime::exceptions::connection_error("Cannot resolve address."); +		} + +		memcpy(reinterpret_cast <char*>(&addr.sin_addr), hostInfo->h_addr, hostInfo->h_length); +	} + +	m_serverAddress = address; + +	// Get a new socket +	m_desc = ::socket(AF_INET, SOCK_STREAM, 0); + +	if (m_desc == INVALID_SOCKET) { + +		try { + +			int err = WSAGetLastError(); +			throwSocketError(err); + +		} catch (exceptions::socket_exception& e) { + +			throw vmime::exceptions::connection_error("Error while creating socket.", e); +		} +	} + +	// Start connection +	if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1) { + +		try { + +			int err = WSAGetLastError(); +			throwSocketError(err); + +		} catch (exceptions::socket_exception& e) { + +			::closesocket(m_desc); +			m_desc = INVALID_SOCKET; + +			// Error +			throw vmime::exceptions::connection_error("Error while connecting socket.", e); +		} +	} + +	// Set socket to non-blocking +	unsigned long non_blocking = 1; +	::ioctlsocket(m_desc, FIONBIO, &non_blocking); +} + + +bool windowsSocket::isConnected() const { + +	if (m_desc == INVALID_SOCKET) { +		return false; +	} + +	char buff; + +	return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0; +} + + +void windowsSocket::disconnect() { + +	if (m_desc != INVALID_SOCKET) { + +		if (m_tracer) { +			m_tracer->traceSend("Disconnecting"); +		} + +		::shutdown(m_desc, SD_BOTH); +		::closesocket(m_desc); + +		m_desc = INVALID_SOCKET; +	} +} + + +static bool isNumericAddress(const char* address) { + +	struct addrinfo hint, *info = NULL; +	memset(&hint, 0, sizeof(hint)); + +	hint.ai_family = AF_UNSPEC; +	hint.ai_flags = AI_NUMERICHOST; + +	if (getaddrinfo(address, 0, &hint, &info) == 0) { + +		freeaddrinfo(info); +		return true; + +	} else { + +		return false; +	} +} + + +const string windowsSocket::getPeerAddress() const { + +	// Get address of connected peer +	sockaddr peer; +	socklen_t peerLen = sizeof(peer); + +	getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen); + +	// Convert to numerical presentation format +	char host[NI_MAXHOST + 1]; +	char service[NI_MAXSERV + 1]; + +	if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen, +			host, sizeof(host), service, sizeof(service), +			/* flags */ NI_NUMERICHOST) == 0) { + +		return string(host); +	} + +	return "";  // should not happen +} + + +const string windowsSocket::getPeerName() const { + +	// Get address of connected peer +	sockaddr peer; +	socklen_t peerLen = sizeof(peer); + +	getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen); + +	// If server address as specified when connecting is a numeric +	// address, try to get a host name for it +	if (isNumericAddress(m_serverAddress.c_str())) { + +		char host[NI_MAXHOST + 1]; +		char service[NI_MAXSERV + 1]; + +		if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen, +				host, sizeof(host), service, sizeof(service), +				/* flags */ NI_NAMEREQD) == 0) { + +			return string(host); +		} +	} + +	return m_serverAddress; +} + + +size_t windowsSocket::getBlockSize() const { + +	return 16384;  // 16 KB +} + + +void windowsSocket::receive(vmime::string& buffer) { + +	const size_t size = receiveRaw(m_buffer, sizeof(m_buffer)); +	buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size); +} + + +size_t windowsSocket::receiveRaw(byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +	// Check whether data is available +	if (!waitForRead(50 /* msecs */)) { + +		// No data available at this time +		// Check if we are timed out +		if (m_timeoutHandler && +		    m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				// Server did not react within timeout delay +				throwSocketError(WSAETIMEDOUT); + +			} else { + +				// Reset timeout +				m_timeoutHandler->resetTimeOut(); +			} +		} + +		// Continue waiting for data +		return 0; +	} + +	// Read available data +	int ret = ::recv(m_desc, reinterpret_cast <char*>(buffer), count, 0); + +	if (ret == SOCKET_ERROR) { + +		int err = WSAGetLastError(); + +		if (err != WSAEWOULDBLOCK) { +			throwSocketError(err); +		} + +		m_status |= STATUS_WOULDBLOCK; + +		// Error or no data +		return 0; + +	} else if (ret == 0) { + +		// Host shutdown +		throwSocketError(WSAENOTCONN); + +	} else { + +		// Data received, reset timeout +		if (m_timeoutHandler) { +			m_timeoutHandler->resetTimeOut(); +		} + +		return ret; +	} +} + + +void windowsSocket::send(const vmime::string& buffer) { + +	sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length()); +} + + +void windowsSocket::send(const char* str) { + +	sendRaw(reinterpret_cast <const byte_t*>(str), strlen(str)); +} + + +void windowsSocket::sendRaw(const byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +	size_t size = count; + +	while (size > 0) { + +		const int ret = ::send(m_desc, reinterpret_cast <const char*>(buffer), size, 0); + +		if (ret == SOCKET_ERROR) { + +			int err = WSAGetLastError(); + +			if (err != WSAEWOULDBLOCK) { +				throwSocketError(err); +			} + +			waitForWrite(50 /* msecs */); + +		} else { + +			buffer += ret; +			size -= ret; +		} +	} + +	// Reset timeout +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} +} + + +size_t windowsSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count) { + +	m_status &= ~STATUS_WOULDBLOCK; + +	const int ret = ::send(m_desc, reinterpret_cast <const char*>(buffer), count, 0); + +	if (ret == SOCKET_ERROR) { + +		int err = WSAGetLastError(); + +		if (err == WSAEWOULDBLOCK) { + +			// Check if we are timed out +			if (m_timeoutHandler && +			    m_timeoutHandler->isTimeOut()) { + +				if (!m_timeoutHandler->handleTimeOut()) { + +					// Could not send data within timeout delay +					throwSocketError(err); + +				} else { + +					// Reset timeout +					m_timeoutHandler->resetTimeOut(); +				} +			} + +			m_status |= STATUS_WOULDBLOCK; + +			// No data can be written at this time +			return 0; + +		} else { + +			throwSocketError(err); +		} +	} + +	// Reset timeout +	if (m_timeoutHandler) { +		m_timeoutHandler->resetTimeOut(); +	} + +	return ret; +} + + +unsigned int windowsSocket::getStatus() const { + +	return m_status; +} + + +void windowsSocket::throwSocketError(const int err) { + +	std::ostringstream oss; +	string msg; + +	LPTSTR str; + +	if (::FormatMessage( +			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, +			NULL, err, 0, (LPTSTR) &str, 0, NULL) == 0) { + +		// Failed getting message +		oss << "Unknown socket error (code " << err << ")"; + +	} else { + +		oss << str; +		::LocalFree(str); +	} + +	msg = oss.str(); + +	throw exceptions::socket_exception(msg); +} + + +bool windowsSocket::waitForData(const bool read, const bool write, const int msecs) { + +	for (int i = 0 ; i <= msecs / 10 ; ++i) { + +		// Check whether data is available +		fd_set fds; +		FD_ZERO(&fds); +		FD_SET(m_desc, &fds); + +		struct timeval tv; +		tv.tv_sec = 0; +		tv.tv_usec = 10000;  // 10 ms + +		int ret = ::select(m_desc + 1, read ? &fds : NULL, write ? &fds : NULL, NULL, &tv); + +		if (ret == SOCKET_ERROR) { + +			int err = WSAGetLastError(); +			throwSocketError(err); + +		} else if (ret > 0) { + +			return true; +		} + +		// No data available at this time +		// Check if we are timed out +		if (m_timeoutHandler && +		    m_timeoutHandler->isTimeOut()) { + +			if (!m_timeoutHandler->handleTimeOut()) { + +				// Server did not react within timeout delay +				throw exceptions::operation_timed_out(); + +			} else { + +				// Reset timeout +				m_timeoutHandler->resetTimeOut(); +			} +		} +	} + +	return false;  // time out +} + + +bool windowsSocket::waitForRead(const int msecs) { + +	return waitForData(/* read */ true, /* write */ false, msecs); +} + + +bool windowsSocket::waitForWrite(const int msecs) { + +	return waitForData(/* read */ false, /* write */ true, msecs); +} + + +shared_ptr <net::timeoutHandler> windowsSocket::getTimeoutHandler() { + +	return m_timeoutHandler; +} + + +void windowsSocket::setTracer(const shared_ptr <net::tracer>& tracer) { + +	m_tracer = tracer; +} + + +shared_ptr <net::tracer> windowsSocket::getTracer() { + +	return m_tracer; +} + + + +// +// posixSocketFactory +// + +shared_ptr <vmime::net::socket> windowsSocketFactory::create() { + +	shared_ptr <vmime::net::timeoutHandler> th; +	return make_shared <windowsSocket>(th); +} + + +shared_ptr <vmime::net::socket> windowsSocketFactory::create(const shared_ptr <vmime::net::timeoutHandler>& th) { + +    return make_shared <windowsSocket>(th); +} + + +} // posix +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES + diff --git a/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp b/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp new file mode 100644 index 0000000..ddb82da --- /dev/null +++ b/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp @@ -0,0 +1,117 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library.  Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED +#define VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES + + +#include <winsock2.h> +#include "vmime/net/socket.hpp" + + +namespace vmime { +namespace platforms { +namespace windows { + + +class windowsSocket : public vmime::net::socket { + +public: + +	windowsSocket(); +	windowsSocket(shared_ptr <vmime::net::timeoutHandler> th); +	~windowsSocket(); + +public: + +	void connect(const vmime::string& address, const vmime::port_t port); +	bool isConnected() const; +	void disconnect(); + +	bool waitForRead(const int msecs = 30000); +	bool waitForWrite(const int msecs = 30000); + +	void receive(vmime::string& buffer); +	size_t receiveRaw(byte_t* buffer, const size_t count); + +	void send(const vmime::string& buffer); +	void send(const char* str); +	void sendRaw(const byte_t* buffer, const size_t count); +	size_t sendRawNonBlocking(const byte_t* buffer, const size_t count); + +	size_t getBlockSize() const; + +	unsigned int getStatus() const; + +	const string getPeerName() const; +	const string getPeerAddress() const; + +	shared_ptr <net::timeoutHandler> getTimeoutHandler(); +	shared_ptr <net::tracer> m_tracer; + +	void setTracer(const shared_ptr <net::tracer>& tracer); +	shared_ptr <net::tracer> getTracer(); + +protected: + +	void throwSocketError(const int err); + +	bool waitForData(const bool read, const bool write, const int msecs); + +private: + +	shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler; + +	byte_t m_buffer[65536]; +	SOCKET m_desc; + +	unsigned int m_status; + +	string m_serverAddress; +}; + + + +class windowsSocketFactory : public vmime::net::socketFactory { + +public: + +	shared_ptr <vmime::net::socket> create(); +	shared_ptr <vmime::net::socket> create(const shared_ptr <vmime::net::timeoutHandler>& th); +}; + + +} // windows +} // platforms +} // vmime + + +#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES + +#endif // VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED | 
