--- build.xml 2008/07/07 16:38:13 +++ build.xml 2008/07/28 14:57:22 @@ -145,7 +145,7 @@ -Dwith-logchar=[utf-8|wchar_t|unichar] (default=utf-8 on Unix, wchar_t on Windows) -Dwith-apr=APRPATH -Dwith-apr-util=PATH --Dwith-SMTP=[libesmtp, no] (default no) +-Dwith-SMTP=[libesmtp, CDO, no] (default no) -Dwith-ODBC=[unixODBC, iODBC, Microsoft, no] (default no) @@ -165,6 +165,9 @@ + + + @@ -334,7 +337,18 @@ - + + + + + + + + --- configure.in 2008/07/07 16:38:13 +++ configure.in 2008/07/28 14:57:22 @@ -254,21 +254,29 @@ AC_MSG_CHECKING(for SMTP support) AC_ARG_WITH(SMTP, AC_HELP_STRING(--with-SMTP, [SMTP support. Accepted arguments : - libesmtp, no (default=no)]), + libesmtp, CDO, no (default=no)]), [ac_with_smtp=$withval], [ac_with_smtp=no]) case "$ac_with_smtp" in + CDO) + AC_MSG_RESULT(CDO) + AC_CHECK_HEADER(cdosys.h,, AC_MSG_ERROR(CDO not found !)) + AC_SUBST(HAS_LIBESMTP, 0, SMTP support through libesmtp library.) + AC_SUBST(HAS_CDO, 1, SMTP support through CDO library.) + ;; libesmtp) AC_MSG_RESULT(libesmtp) AC_CHECK_LIB([esmtp], [smtp_create_session],, AC_MSG_ERROR(libesmtp library not found !), -lesmtp) AC_SUBST(HAS_LIBESMTP, 1, SMTP support through libesmtp library.) + AC_SUBST(HAS_CDO, 0, SMTP support through CDO library.) LIBS="-lesmtp $LIBS" ;; - no) + no) AC_MSG_RESULT(no) AC_SUBST(HAS_LIBESMTP, 0, SMTP support through libesmtp library.) + AC_SUBST(HAS_CDO, 0, SMTP support through CDO library.) ;; *) AC_MSG_RESULT(???) --- src/main/cpp/smtpappender.cpp 2008/07/28 14:22:05 +++ src/main/cpp/smtpappender.cpp 2008/07/28 16:09:10 @@ -29,6 +29,11 @@ #include +#if LOG4CXX_HAVE_CDO +// we need to include windows.h _before_ apr_strings.h which disables +// definitions from windows.h (see WIN32_LEAN_AND_MEAN and _WIN32_WINNT) +#include +#endif #include #include @@ -43,6 +48,17 @@ #include #endif +#if LOG4CXX_HAVE_CDO +#include +#include +#include +#include +#include +#include +#include +#endif + + namespace log4cxx { namespace net { // @@ -274,7 +290,267 @@ }; #endif - + +#if LOG4CXX_HAVE_CDO + namespace { + /** + * Class wrapping CDO for sending mail + */ + class CDOSender { + public: + CDOSender(const LogString& smtpHost, + int smtpPort, + const LogString& smtpUsername, + const LogString& smtpPassword, + Pool& p); + ~CDOSender(); + + void sendMail(const LogString& from, + const LogString& to, + const LogString& cc, + const LogString& bcc, + const LogString& subject, + const LogString& msg, + bool sendHtmlFormat, + Pool& p); + + private: + /** + Check the result of a COM call. If it failed the function throws an + Exception. + */ + void checkCoResult(HRESULT hr, const logchar* errorMsg); + + CDO::IConfiguration* pConfig; + }; + + CDOSender::CDOSender(const LogString& smtpHost, + int smtpPort, + const LogString& smtpUsername, + const LogString& smtpPassword, + Pool& p) + : pConfig(0) + { + CDO::Fields* pFields = NULL; + CDO::Field* pField = NULL; + try + { + // create the SMTP configuration + HRESULT hr = ::CoCreateInstance( + CDO::CLSID_Configuration, + NULL, + CLSCTX_INPROC_SERVER, + CDO::IID_IConfiguration, + reinterpret_cast(&pConfig)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp configuration (1)")); + + hr = pConfig->get_Fields(&pFields); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp configuration (2)")); + + hr = pFields->get_Item(_variant_t(cdoSendUsingMethod), &pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp send method (1)")); + hr = pField->put_Value(_variant_t((long)CDO::cdoSendUsingPort)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp send method (2)")); + pField->Release(); + pField = NULL; + + hr = pFields->get_Item(_variant_t(cdoSMTPServer), &pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp server (1)")); + hr = pField->put_Value(_variant_t(smtpHost.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp server (2)")); + pField->Release(); + pField = NULL; + + hr = pFields->get_Item(_variant_t(cdoSMTPServerPort), &pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp port (1)")); + hr = pField->put_Value(_variant_t((long)smtpPort)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp port (2)")); + pField->Release(); + pField = NULL; + + hr = pFields->get_Item(_variant_t(cdoSMTPAuthenticate), &pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (1)")); + + if (smtpUsername.empty() || smtpPassword.empty()) + {// use anonymous SMTP + pField->put_Value(_variant_t((long)CDO::cdoAnonymous)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (2)")); + pField->Release(); + pField = NULL; + } + else + {// use basic SMTP authentication + pField->put_Value(_variant_t((long)CDO::cdoBasic)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (3)")); + pField->Release(); + pField = NULL; + + hr = pFields->get_Item(_variant_t(cdoSendUserName), &pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (4)")); + hr = pField->put_Value(_variant_t(_variant_t(smtpUsername.c_str()))); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (5)")); + pField->Release(); + pField = NULL; + + hr = pFields->get_Item(_variant_t(cdoSendPassword),& pField); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (6)")); + hr = pField->put_Value(_variant_t(_variant_t(smtpPassword.c_str()))); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup smtp auth (7)")); + pField->Release(); + pField = NULL; + } + + hr = pFields->Update(); + checkCoResult(hr, LOG4CXX_STR("Error occurred while updating smtp configuration (1)")); + pFields->Release(); + pFields = NULL; + + } + catch(_com_error& e) + { + try + { + if (pField) + pField->Release(); + if (pFields) + pFields->Release(); + } + catch(_com_error) + {} + catch(...) + {} + + std::basic_ostringstream s; + s << LOG4CXX_STR("COM error occurred while seting up the SMTP configuration.") + << e.ErrorMessage(); + throw Exception(s.str()); + } + catch(...) + { + try + { + if (pField) + pField->Release(); + if (pFields) + pFields->Release(); + } + catch(_com_error) + {} + catch(...) + {} + + LogString msg(LOG4CXX_STR("error occurred while seting up the SMTP configuration.")); + throw Exception(msg); + } + } + + CDOSender::~CDOSender() + { + if (pConfig) + pConfig->Release(); + } + + void CDOSender::sendMail(const LogString& from, + const LogString& to, + const LogString& cc, + const LogString& bcc, + const LogString& subject, + const LogString& msg, + bool sendHtmlFormat, + Pool& p) + { + CDO::IMessage* pMsg = NULL; + try + { + // create a message + HRESULT hr = ::CoCreateInstance( + CDO::CLSID_Message, + NULL, + CLSCTX_INPROC_SERVER, + CDO::IID_IMessage, + reinterpret_cast(&pMsg)); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail (1)")); + + // set message attributes + hr = pMsg->put_To(_bstr_t(to.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail header TO")); + + if (!cc.empty()) + { + hr = pMsg->put_CC(_bstr_t(cc.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail header CC")); + } + + if (!bcc.empty()) + { + hr = pMsg->put_BCC(_bstr_t(bcc.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail header BCC")); + } + + hr = pMsg->put_From(_bstr_t(from.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail header From")); + + hr = pMsg->put_Subject(_bstr_t(subject.c_str())); + checkCoResult(hr, LOG4CXX_STR("Error occurred while setup mail header Subject")); + + // set the message body + if (sendHtmlFormat) + { + pMsg->put_HTMLBody(_bstr_t(msg.c_str())); + } + else + { + pMsg->put_TextBody(_bstr_t(msg.c_str())); + } + + // set the SMTP prperties + hr = pMsg->putref_Configuration(pConfig); + checkCoResult(hr, LOG4CXX_STR("Error occurred while updating smtp configuration (2)")); + + // send the mail + hr = pMsg->Send(); + checkCoResult(hr, LOG4CXX_STR("Error occurred while sending the message")); + pMsg->Release(); + pMsg = NULL; + } + catch(_com_error& e) + { + if (pMsg) + pMsg->Release(); + + std::basic_ostringstream s; + s << LOG4CXX_STR("COM error occurred while sending mail.") + << e.ErrorMessage(); + LogString msg(LOG4CXX_STR("COM error occurred while sending mail.")); + // LogLog::error(s.str()); + throw Exception(msg); + } + catch(...) + { + if (pMsg) + pMsg->Release(); + + LogString msg(LOG4CXX_STR("error occurred while sending mail.")); + // LogLog::error(s.str()); + throw Exception(msg); + } + } + + void CDOSender::checkCoResult(HRESULT hr, const logchar* errorMsg) + { + if (FAILED(hr)) + { + std::basic_ostringstream s; + s << errorMsg << LOG4CXX_STR(" [HRESULT: ") << hr << LOG4CXX_STR("]"); + // LogLog::error(s.str()); + + throw Exception(s.str()); + } + } + + } // anonymous namespace +#endif // LOG4CXX_HAVE_CDO + class LOG4CXX_EXPORT DefaultEvaluator : public virtual spi::TriggeringEventEvaluator, public virtual helpers::ObjectImpl @@ -327,10 +603,20 @@ : smtpPort(25), bufferSize(512), locationInfo(false), cb(bufferSize), evaluator(evaluator) { +#if LOG4CXX_HAVE_CDO + HRESULT hr = ::CoInitialize(NULL); + if (hr == RPC_E_CHANGED_MODE) + { + throw Exception("Failed to initialize the COM library"); + } +#endif } SMTPAppender::~SMTPAppender() { +#if LOG4CXX_HAVE_CDO + ::CoUninitialize(); +#endif finalize(); } @@ -496,7 +782,7 @@ activate &= asciiCheck(bcc, LOG4CXX_STR("bcc")); activate &= asciiCheck(from, LOG4CXX_STR("from")); -#if !LOG4CXX_HAVE_LIBESMTP +#if !LOG4CXX_HAVE_SMTP errorHandler->error(LOG4CXX_STR("log4cxx built without SMTP support.")); activate = false; #endif @@ -537,7 +823,7 @@ value false is returned. */ bool SMTPAppender::checkEntryConditions() { -#if LOG4CXX_HAVE_LIBESMTP +#if LOG4CXX_HAVE_SMTP if((to.empty() && cc.empty() && bcc.empty()) || from.empty() || smtpHost.empty()) { errorHandler->error(LOG4CXX_STR("Message not configured.")); @@ -598,7 +884,7 @@ */ void SMTPAppender::sendBuffer(Pool& p) { -#if LOG4CXX_HAVE_LIBESMTP +#if LOG4CXX_HAVE_SMTP // Note: this code already owns the monitor for this // appender. This frees us from needing to synchronize on 'cb'. try @@ -615,13 +901,31 @@ layout->appendFooter(sbuf, p); +#if LOG4CXX_HAVE_LIBESMTP SMTPSession session(smtpHost, smtpPort, smtpUsername, smtpPassword, p); SMTPMessage message(session, from, to, cc, bcc, subject, sbuf, p); session.send(p); +#endif +#if LOG4CXX_HAVE_CDO + CDOSender sender(smtpHost, + smtpPort, + smtpUsername, + smtpPassword, + p); + bool sendHtmlFormat = layout->getContentType() == LOG4CXX_STR("text/html"); + sender.sendMail(from, + to, + cc, + bcc, + subject, + sbuf, + sendHtmlFormat, + p); +#endif } catch(std::exception& e) { --- src/main/include/log4cxx/private/log4cxx_private.h.in 2008/07/07 16:38:13 +++ src/main/include/log4cxx/private/log4cxx_private.h.in 2008/07/28 14:57:22 @@ -47,6 +47,9 @@ #define LOG4CXX_CHARSET_EBCDIC @CHARSET_EBCDIC@ #define LOG4CXX_HAVE_LIBESMTP @HAS_LIBESMTP@ +#define LOG4CXX_HAVE_CDO @HAS_CDO@ +#define LOG4CXX_HAVE_SMTP (LOG4CXX_HAVE_LIBESMTP || LOG4CXX_HAVE_CDO) + #define LOG4CXX_HAVE_SYSLOG @HAS_SYSLOG@ #define LOG4CXX_WIN32_THREAD_FMTSPEC "0x%.8x" --- src/main/include/log4cxx/private/log4cxx_private.hw 2008/07/07 16:38:13 +++ src/main/include/log4cxx/private/log4cxx_private.hw 2008/07/28 14:57:22 @@ -76,6 +76,9 @@ #define LOG4CXX_HAVE_LIBESMTP 0 +#define LOG4CXX_HAVE_CDO 0 +#define LOG4CXX_HAVE_SMTP (LOG4CXX_HAVE_LIBESMTP || LOG4CXX_HAVE_CDO) + #define LOG4CXX_HAVE_SYSLOG 0 #define LOG4CXX_WIN32_THREAD_FMTSPEC "0x%.8x" --- src/site/apt/building/ant.apt 2008/07/07 16:38:13 +++ src/site/apt/building/ant.apt 2008/07/28 14:57:22 @@ -136,7 +136,7 @@ *-------------------+---------------------------------------------------------------------------------------------+ | -Dwith-charset | Exteral character encoding, choice of utf-8, iso-8859-1, usascii, ebcdic, auto (default). | *-------------------+---------------------------------------------------------------------------------------------+ -| -Dwith-SMTP | SMTP implementation for SMTPAppender, choice of libesmtp, no (default). | +| -Dwith-SMTP | SMTP implementation for SMTPAppender, choice of libesmtp, CDO, no (default). | *-------------------+---------------------------------------------------------------------------------------------+ | -Dwith-ODBC | OBDC implementation for ODBCAppender, choice of unixODBC, iODBC, Microsoft, no (default). | *-------------------+---------------------------------------------------------------------------------------------+ @@ -172,6 +172,8 @@ If -Dwith-SMTP=libesmtp is specified, the build will attempt to build libesmtp from source, unfortunately libesmtp depends on poll.h and will not build. + + If -Dwith-SMTP=CDO is specified, the SMTPAppender will be built using CDO. APR 1.2.12 has a known issue that will prevent compilation with Visual Studio 6 unless a later Platform SDK is installed. --- src/site/apt/building/autotools.apt 2008/07/07 16:38:13 +++ src/site/apt/building/autotools.apt 2008/07/28 14:57:22 @@ -50,7 +50,7 @@ *-------------------+---------------------------------------------------------------------------------------------+ | --with-charset | Exteral character encoding, choice of utf-8, iso-8859-1, usascii, ebcdic, auto (default). | *-------------------+---------------------------------------------------------------------------------------------+ -| --with-SMTP | SMTP implementation for SMTPAppender, choice of libesmtp, no (default). | +| --with-SMTP | SMTP implementation for SMTPAppender, choice of libesmtp, CDO, no (default). | *-------------------+---------------------------------------------------------------------------------------------+ | --with-ODBC | OBDC implementation for ODBCAppender, choice of unixODBC, iODBC, Microsoft, no (default). | *-------------------+---------------------------------------------------------------------------------------------+