You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4cxx-dev@logging.apache.org by ca...@apache.org on 2007/12/11 03:11:37 UTC

svn commit: r603118 - in /logging/log4cxx/trunk: ./ src/dependencies/ src/dependencies/esmtp/ src/main/cpp/ src/main/include/log4cxx/net/ src/main/include/log4cxx/private/ src/main/include/log4cxx/xml/ src/test/cpp/net/ src/test/resources/input/xml/

Author: carnold
Date: Mon Dec 10 18:11:34 2007
New Revision: 603118

URL: http://svn.apache.org/viewvc?rev=603118&view=rev
Log:
LOGCXX-1: Migrate SMTPAppender to libesmtp

Added:
    logging/log4cxx/trunk/src/dependencies/
    logging/log4cxx/trunk/src/dependencies/esmtp/
    logging/log4cxx/trunk/src/dependencies/esmtp/build.xml   (with props)
    logging/log4cxx/trunk/src/test/resources/input/xml/smtpAppender1.xml
      - copied unchanged from r598753, logging/log4j/trunk/tests/input/xml/smtpAppender1.xml
Modified:
    logging/log4cxx/trunk/configure.in
    logging/log4cxx/trunk/src/main/cpp/class.cpp
    logging/log4cxx/trunk/src/main/cpp/domconfigurator.cpp
    logging/log4cxx/trunk/src/main/cpp/propertysetter.cpp
    logging/log4cxx/trunk/src/main/cpp/smtpappender.cpp
    logging/log4cxx/trunk/src/main/include/log4cxx/net/smtpappender.h
    logging/log4cxx/trunk/src/main/include/log4cxx/private/log4cxx_private.h.in
    logging/log4cxx/trunk/src/main/include/log4cxx/xml/domconfigurator.h
    logging/log4cxx/trunk/src/test/cpp/net/smtpappendertestcase.cpp

Modified: logging/log4cxx/trunk/configure.in
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/configure.in?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/configure.in (original)
+++ logging/log4cxx/trunk/configure.in Mon Dec 10 18:11:34 2007
@@ -121,7 +121,7 @@
 
 AC_ARG_ENABLE(cppunit,
         AC_HELP_STRING(--enable-cppunit,
-                [enable test excution with cppunit (auto)]))
+                [enable test execution with cppunit (auto)]))
 
 enable_tests=yes
 
@@ -198,12 +198,6 @@
 AC_PROG_RANLIB
 
 
-# for SocketAppender
-AC_CHECK_FUNCS(gethostbyname,,
-        [AC_CHECK_LIB(nsl,gethostbyname,,
-        [AC_CHECK_LIB(socket,gethostbyname)])])
-AC_CHECK_FUNCS(setsockopt,,[AC_CHECK_LIB(socket,setsockopt)])
-
 #for ODBCAppender
 AC_MSG_CHECKING(for ODBC support)
 AC_ARG_WITH(ODBC,
@@ -256,43 +250,27 @@
 AC_MSG_CHECKING(for SMTP support)
 AC_ARG_WITH(SMTP,
         AC_HELP_STRING(--with-SMTP, [SMTP support. Accepted arguments :
-                libsmtp, CDO, no (default=no)]),
+                libesmtp, no (default=no)]),
         [ac_with_smtp=$withval],
         [ac_with_smtp=no])
 case "$ac_with_smtp" in
-    CDO)
-        AC_MSG_RESULT(CDO)
-        AC_DEFINE(HAVE_CDO_SMTP, 1, SMTP support through Microsoft CDO.)
-        AC_DEFINE(HAVE_SMTP, 1, SMTP support)
-        ;;
-    libsmtp)
-        AC_MSG_RESULT(libsmtp)
-        AC_CHECK_LIB([smtp_mime], [libsmtp_session_initialize],,
-                AC_MSG_ERROR(libsmtp library not found !),
-                `glib-config --libs` -lsmtp)
-        AC_DEFINE(HAVE_LIBSMTP, 1, SMTP support through libsmtp library.)
-        AC_DEFINE(HAVE_SMTP, 1, SMTP support)
-        LIBS="`glib-config --libs` -lsmtp $LIBS"
-        CPPFLAGS="`glib-config --cflags` $CPPFLAGS"
+    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.)
+        LIBS="-lesmtp $LIBS"
         ;;
         no)
         AC_MSG_RESULT(no)
+        AC_SUBST(HAS_LIBESMTP, 0, SMTP support through libesmtp library.)
         ;;
     *)
         AC_MSG_RESULT(???)
         AC_MSG_ERROR(Unknown option : $ac_with_smtp)
         ;;
 esac
-
-#for _T
-
-case "$host" in
-        *apple-darwin*)
-        AC_DEFINE(MUST_UNDEF_T, 1, Defined to 1 if macro _T has to be undefined)
-        ;;
-esac
-
-CPPFLAGS="-DLOG4CXX $CPPFLAGS"
 
 #for wchar_t
 AC_ARG_ENABLE(wchar_t,

Added: logging/log4cxx/trunk/src/dependencies/esmtp/build.xml
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/dependencies/esmtp/build.xml?rev=603118&view=auto
==============================================================================
--- logging/log4cxx/trunk/src/dependencies/esmtp/build.xml (added)
+++ logging/log4cxx/trunk/src/dependencies/esmtp/build.xml Mon Dec 10 18:11:34 2007
@@ -0,0 +1,233 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<!--
+
+This file builds libesmtp using Apache Ant (http://ant.apache.org)
+and the C++ compilation tasks from http://ant-contrib.sourceforge.net.
+
+
+-->
+<project name="esmtp" default="build">
+
+<property name="debug" value="true"/>
+<property name="esmtp.version" value="1.0.4"/>
+<property name="esmtp.dir" location="${ant.file}/../../../../../libesmtp-${esmtp.version}"/>
+<property name="esmtp.include.dir" location="${esmtp.dir}"/>
+<property name="build.dir" location="${user.dir}/target"/>
+<property name="src.dir" location="${esmtp.dir}"/>
+<property name="esmtp.lib.type" value="shared"/>
+<property name="project.dir" location="${build.dir}"/>
+
+<taskdef resource="cpptasks.tasks"/>
+<typedef resource="cpptasks.types"/>
+
+<target name="usage" description="Displays usage notes on build">
+        <echo>
+        </echo>
+</target>
+
+<target name="os-detect">
+        <condition property="is-mac" value="true">
+             <and>
+                 <os family="mac"/>
+                 <not><isset property="is-windows"/></not>
+             </and>
+        </condition>
+        <condition property="is-unix" value="true">
+             <and>
+                  <not>
+                      <or>
+                          <isset property="is-windows"/>
+                          <equals arg1="${os.family}" arg2="windows"/>
+                      </or>
+                  </not>
+                  <or>
+                       <os family="unix"/>
+                       <equals arg1="${os.family}" arg2="cygwin"/>
+                       <equals arg1="${os.family}" arg2="unix"/>
+                  </or>
+             </and>
+        </condition>
+        <condition property="is-windows" value="true">
+             <and>
+                  <not><isset property="is-unix"/></not>
+                  <or>
+                      <os family="windows"/>
+                      <equals arg1="${os.family}" arg2="windows"/>
+                  </or>
+             </and>
+        </condition>
+</target>
+
+
+<target name="win-init" depends="os-detect" if="is-windows">
+    <property name="compiler" value="msvc"/>
+    <property name="arch" value="win32"/>
+    <property name="project.type" value="msvc6"/>
+</target>
+
+<target name="unix-init" depends="os-detect" if="is-unix">
+    <property name="compiler" value="gcc"/>
+    <condition property="is-gcc" value="true">
+        <or>
+            <equals arg1="${compiler}" arg2="gcc"/>
+            <equals arg1="${compiler}" arg2="g++"/>
+        </or>
+    </condition>
+    <property name="arch" value="unix"/>
+    <property name="project.type" value="cbuilderx"/>
+</target>
+
+<target name="init" depends="win-init, unix-init">
+        <property environment="env"/>
+        <condition property="pic-option" value="-fPIC">
+                <and>
+                        <isset property="is-gcc"/>
+                        <istrue value="${use-pic}"/>
+                </and>
+        </condition>
+
+        <condition property="is-debug" value="true">
+            <istrue value="${debug}"/>
+        </condition>
+
+        <condition property="esmtp.lib.dir" value="${build.dir}/debug/${esmtp.lib.type}">
+            <isset property="is-debug"/>
+        </condition>
+        <property name="esmtp.lib.dir" location="${build.dir}/release/${esmtp.lib.type}"/>
+        <mkdir dir="${esmtp.lib.dir}"/>
+
+        <condition property="lib-suffix" value="d">
+            <isset property="is-debug"/>
+        </condition>
+        <property name="lib-suffix" value=""/>
+
+        <condition property="is-esmtp-shared" value="true">
+            <equals arg1="${esmtp.lib.type}" arg2="shared"/>
+        </condition>
+
+        <condition property="is-bcc" value="true">
+            <equals arg1="${compiler}" arg2="bcc"/>
+        </condition>
+        <condition property="project.if" value="true">
+            <istrue value="${project.if.value}"/>
+        </condition>
+</target>
+
+<target name="clean" description="Removes build product files">
+        <delete dir="${build.dir}"/>
+</target>
+
+
+<target name="configure-check" depends="init">
+        <condition property="esmtp-configure-available" value="true">
+              <available file="${esmtp.include.dir}/libesmtp.h"/>
+        </condition>
+</target>
+
+
+<target name="win-configure" depends="configure-check" if="is-windows" unless="esmtp-configure-available">
+    <copy tofile="${esmtp.include.dir}/libesmtp.h" file="${esmtp.include.dir}/libesmtp.hw"/>
+</target>
+
+<target name="unix-configure" depends="configure-check" if="is-unix" unless="esmtp-configure-available">
+         <!--  shelling to configure allows cygwin to work  -->
+        <exec executable="sh" dir="${esmtp.dir}">
+            <arg value="./configure"/>
+        </exec>
+</target>
+
+
+<target name="configure" depends="unix-configure, win-configure"/>
+
+
+<target name="build" depends="configure" description="Build library">
+    <mkdir dir="${esmtp.lib.dir}/esmtp_obj"/>
+    <property name="project.compiler" value="${compiler}"/>
+    <cc name="${project.compiler}"
+        outfile="${esmtp.lib.dir}/esmtp${lib-suffix}"
+        subsystem="console"
+        multithreaded="true"
+        outtype="${esmtp.lib.type}"
+        objdir="${esmtp.lib.dir}/esmtp_obj"
+        outputfileproperty="esmtp.dll"
+        debug="${debug}"
+        projectsOnly="${projectsOnly}">
+        <fileset dir="${src.dir}" includes="*.c" excludes="getaddrinfo.c"/>
+        <includepath path="${esmtp.include.dir}"/>
+        <defineset define="HAVE_CONFIG_H"/>
+        <defineset>
+             <define name="VERSION" value='"${esmtp.version}"'/>
+        </defineset>
+        <compilerarg value="${pic-option}" if="pic-option"/>
+        <libset libs="advapi32 ws2_32 mswsock rpcrt4" if="is-windows"/>
+        <libset libs="ssl crypto" if="is-unix"/>
+        <libset libs="cw32mt" if="is-bcc"/>
+        <project type="${project.type}" outfile="${project.dir}/esmtp" if="project.if"/>
+    </cc>
+</target>
+
+
+<target name="build-projects">
+        <mkdir dir="${project.dir}"/>
+        <antcall target="build">
+                <param name="project.if" value="true"/>
+                <param name="project.type" value="${project.type}"/>
+                <param name="project.compiler" value="${project.compiler}"/>
+                <param name="projects.dir" value="${project.dir}"/>
+                <param name="projectsOnly" value="true"/>
+        </antcall>
+</target>
+
+<target name="build-projects-vc6" description="Builds project files for Microsoft Visual C++ 6">
+    <antcall target="build-projects">
+        <param name="project.dir" value="msvc"/>
+        <param name="project.type" value="msvc6"/>
+        <param name="project.compiler" value="msvc"/>
+    </antcall>
+</target>
+
+<target name="build-projects-vc8" description="Builds project files for Microsoft Visual C++ 2005">
+  <antcall target="build-projects">
+    <param name="project.dir" value="msvc"/>
+    <param name="project.type" value="msvc8"/>
+    <param name="project.compiler" value="msvc"/>
+  </antcall>
+</target>
+
+<target name="build-projects-xcode" description="Builds project files for Apple Xcode">
+    <antcall target="build-projects">
+        <param name="project.dir" value="xcode"/>
+        <param name="project.type" value="xcode"/>
+        <param name="project.compiler" value="${compiler}"/>
+    </antcall>
+</target>
+
+<target name="build-projects-cbx" description="Builds project files for Borland CBuilderX">
+    <antcall target="build-projects">
+        <param name="project.dir" value="cbx"/>
+        <param name="project.type" value="cbuilderx"/>
+        <param name="project.compiler" value="${compiler}"/>
+    </antcall>
+</target>
+
+
+
+</project>

Propchange: logging/log4cxx/trunk/src/dependencies/esmtp/build.xml
------------------------------------------------------------------------------
    svn:executable = *

Modified: logging/log4cxx/trunk/src/main/cpp/class.cpp
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/class.cpp?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/class.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/class.cpp Mon Dec 10 18:11:34 2007
@@ -114,7 +114,7 @@
         //
         const Class* clazz = getRegistry()[lowerName];
         if (clazz == 0) {
-            LogString::size_type pos = className.find_last_of(LOG4CXX_STR('.'));
+            LogString::size_type pos = className.find_last_of(LOG4CXX_STR(".$"));
             if (pos != LogString::npos) {
                 LogString terminalName(lowerName, pos + 1, LogString::npos);
                 clazz = getRegistry()[terminalName];

Modified: logging/log4cxx/trunk/src/main/cpp/domconfigurator.cpp
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/domconfigurator.cpp?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/domconfigurator.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/domconfigurator.cpp Mon Dec 10 18:11:34 2007
@@ -46,6 +46,7 @@
 #include <apr_xml.h>
 #include <log4cxx/helpers/bytebuffer.h>
 #include <log4cxx/helpers/charsetdecoder.h>
+#include <log4cxx/net/smtpappender.h>
 
 using namespace log4cxx;
 using namespace log4cxx::xml;
@@ -224,10 +225,16 @@
                                 }
                                 else if (tagName == TRIGGERING_POLICY_TAG)
                                 {
-                                        TriggeringPolicyPtr triggerPolicy(parseTriggeringPolicy(p, utf8Decoder, currentElement));
+                                        ObjectPtr policy(parseTriggeringPolicy(p, utf8Decoder, currentElement));
                                         RollingFileAppenderPtr rfa(appender);
                                         if (rfa != NULL) {
-                                           rfa->setTriggeringPolicy(triggerPolicy);
+                                           rfa->setTriggeringPolicy(policy);
+                                        } else {
+                                            log4cxx::net::SMTPAppenderPtr smtpa(appender);
+                                            if (smtpa != NULL) {
+                                                log4cxx::spi::TriggeringEventEvaluatorPtr evaluator(policy);
+                                                smtpa->setEvaluator(evaluator);
+                                            }
                                         }
                                 }
                                 else if (tagName == APPENDER_REF_TAG)
@@ -521,7 +528,7 @@
 /**
  Used internally to parse a triggering policy
 */
-TriggeringPolicyPtr DOMConfigurator::parseTriggeringPolicy (
+ObjectPtr DOMConfigurator::parseTriggeringPolicy (
                                   log4cxx::helpers::Pool& p,
                                   log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
                                   apr_xml_elem* layout_element)
@@ -531,8 +538,7 @@
         try
         {
                 ObjectPtr instance = Loader::loadClass(className).newInstance();
-                TriggeringPolicyPtr layout = instance;
-                PropertySetter propSetter(layout);
+                PropertySetter propSetter(instance);
 
                 for (apr_xml_elem* currentElement = layout_element->first_child;
                      currentElement;
@@ -557,7 +563,7 @@
                 }
 
                 propSetter.activate(p);
-                return layout;
+                return instance;
         }
         catch (Exception& oops)
         {

Modified: logging/log4cxx/trunk/src/main/cpp/propertysetter.cpp
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/propertysetter.cpp?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/propertysetter.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/propertysetter.cpp Mon Dec 10 18:11:34 2007
@@ -69,6 +69,7 @@
                         LogString value = OptionConverter::findAndSubst(key, properties);
                         key = key.substr(len);
                         if (key == LOG4CXX_STR("layout")
+                                && obj != 0
                                 && obj->instanceof(Appender::getStaticClass()))
                         {
                                 continue;
@@ -86,7 +87,7 @@
         if (value.empty())
                 return;
 
-        if (obj->instanceof(OptionHandler::getStaticClass()))
+        if (obj != 0 && obj->instanceof(OptionHandler::getStaticClass()))
         {
                 LogLog::debug(LOG4CXX_STR("Setting option name=[") +
                         option + LOG4CXX_STR("], value=[") + value + LOG4CXX_STR("]"));
@@ -96,7 +97,7 @@
 
 void PropertySetter::activate(Pool& p)
 {
-        if (obj->instanceof(OptionHandler::getStaticClass()))
+        if (obj != 0 && obj->instanceof(OptionHandler::getStaticClass()))
         {
                 OptionHandlerPtr(obj)->activateOptions(p);
         }

Modified: logging/log4cxx/trunk/src/main/cpp/smtpappender.cpp
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/smtpappender.cpp?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/smtpappender.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/smtpappender.cpp Mon Dec 10 18:11:34 2007
@@ -16,7 +16,6 @@
  */
 
 #include <log4cxx/private/log4cxx_private.h>
-#if LOG4CXX_HAVE_SMTP
 
 #include <log4cxx/net/smtpappender.h>
 #include <log4cxx/level.h>
@@ -28,14 +27,280 @@
 #include <log4cxx/helpers/transcoder.h>
 #include <log4cxx/helpers/synchronized.h>
 
-#include <libsmtp.h>
-#include <libsmtp_mime.h>
+
+#include <apr_strings.h>
+#include <vector>
 
 using namespace log4cxx;
 using namespace log4cxx::helpers;
 using namespace log4cxx::net;
 using namespace log4cxx::spi;
 
+#if LOG4CXX_HAVE_LIBESMTP
+#include <auth-client.h>
+#include <libesmtp.h>
+#endif
+
+namespace log4cxx {
+    namespace net {
+        //
+        //   The following two classes implement an C++ SMTP wrapper over libesmtp.
+        //   The same signatures could be implemented over different SMTP implementations
+        //   or libesmtp could be combined with libgmime to enable support for non-ASCII
+        //   content.  
+
+#if LOG4CXX_HAVE_LIBESMTP        
+        /**
+         *   SMTP Session.
+         */
+        class SMTPSession {
+        public:
+           /**
+           *   Create new instance.
+           */
+            SMTPSession(const LogString& smtpHost,
+                        int smtpPort,
+                        const LogString& smtpUsername,
+                        const LogString& smtpPassword,
+                        Pool& p) : session(0), authctx(0), 
+                        user(toAscii(smtpUsername, p)), 
+                        pwd(toAscii(smtpPassword, p)) {
+                auth_client_init();
+                session = smtp_create_session();
+                if (session == 0) {
+                    throw Exception("Could not initialize session.");
+                }
+                std::string host(toAscii(smtpHost, p));
+                host.append(1, ':');
+                host.append(apr_itoa((apr_pool_t*) p.getAPRPool(), smtpPort));
+                smtp_set_server(session, host.c_str());
+   
+                authctx = auth_create_context();
+                auth_set_mechanism_flags(authctx, AUTH_PLUGIN_PLAIN, 0);
+                auth_set_interact_cb(authctx, authinteract, (void*) this);
+   
+                if (*user || *pwd) {
+                    smtp_auth_set_context(session, authctx);
+                }
+            }
+            
+            ~SMTPSession() {
+                 smtp_destroy_session(session);
+                 auth_destroy_context(authctx);
+            }
+            
+            void send(Pool& p) {
+                 int status = smtp_start_session(session);
+                 if (!status) {
+                     size_t bufSize = 128;
+                     char* buf = (char*) apr_palloc((apr_pool_t*) p.getAPRPool(), bufSize);
+                     smtp_strerror(smtp_errno(), buf, bufSize);
+                     throw Exception(buf);
+                 }
+            }
+            
+            operator smtp_session_t() {
+                return session;
+            }
+
+            static char* toAscii(const LogString& str, Pool& p) {
+                char* buf = (char*) apr_palloc((apr_pool_t*) p.getAPRPool(), str.length() + 1);
+                char* current = buf;
+                for(LogString::const_iterator iter = str.begin();
+                    iter != str.end();
+                    iter++) {
+                    unsigned int c = *iter;
+                    if (c > 0x7F) {
+                       c = '?';
+                    }
+                    *current++ = c;
+                }
+                *current = 0;
+                return buf;
+            }
+                        
+            private:
+            SMTPSession(SMTPSession&);
+            SMTPSession& operator=(SMTPSession&);
+            smtp_session_t session;
+            auth_context_t authctx;
+            char* user;
+            char* pwd;
+
+            /**
+             *   This method is called if the SMTP server requests authentication.
+             */
+            static int authinteract(auth_client_request_t request, char **result, int fields,
+              void *arg) {
+              SMTPSession* pThis = (SMTPSession*) arg;
+              for (int i = 0; i < fields; i++) {
+                int flag = request[i].flags & 0x07;
+                if (flag == AUTH_USER) {
+                   result[i] = pThis->user;
+                } else if(flag == AUTH_PASS) {
+                   result[i] = pThis->pwd;
+                }
+              }
+              return 1;
+            }
+            
+
+        };
+        
+        /**
+         *  A message in an SMTP session.
+         */
+        class SMTPMessage {
+        public:
+            SMTPMessage(SMTPSession& session, 
+                        const LogString& from, 
+                        const LogString& to,
+                        const LogString& cc,
+                        const LogString& bcc,
+                        const LogString& subject,
+                        const LogString msg, Pool& p) {
+                 message = smtp_add_message(session);
+                 body = current = toMessage(msg, p);
+                 smtp_set_reverse_path(message, toAscii(from, p));
+                 addRecipients(to, "To", p);
+                 addRecipients(cc, "Cc", p);
+                 addRecipients(bcc, "Bcc", p);
+                 if (!subject.empty()) {
+                    smtp_set_header(message, "Subject", toAscii(subject, p));
+                 }
+                 smtp_set_messagecb(message, messagecb, this); 
+            }
+            ~SMTPMessage() {
+            }
+            
+        private:
+           SMTPMessage(const SMTPMessage&);
+           SMTPMessage& operator=(const SMTPMessage&);
+           smtp_message_t message;
+           const char* body;
+           const char* current;
+           void addRecipients(const LogString& addresses, const char* field, Pool& p) {
+              if (!addresses.empty()) {
+                char* str = apr_pstrdup((apr_pool_t*) p.getAPRPool(), toAscii(addresses, p));;
+                smtp_set_header(message, field, NULL, str);
+                char* last;
+                for(char* next = apr_strtok(str, ",", &last);
+                    next;
+                    next = apr_strtok(NULL, ",", &last)) {
+                    smtp_add_recipient(message, next);
+                }
+              }
+          }
+           static const char* toAscii(const LogString& str, Pool& p) {
+               return SMTPSession::toAscii(str, p);
+           }
+           
+           /**
+            *   Message bodies can only contain US-ASCII characters and 
+            *   CR and LFs can only occur together.
+            */
+           static const char* toMessage(const LogString& str, Pool& p) {
+               //
+               //    count the number of carriage returns and line feeds
+               //
+               int feedCount = 0;
+               for(size_t pos = str.find_first_of(LOG4CXX_STR("\n\r"));
+                   pos != LogString::npos;
+                   pos = str.find_first_of(LOG4CXX_STR("\n\r"), ++pos)) {
+                   feedCount++;
+               }
+               //
+               //   allocate sufficient space for the modified message
+               char* retval = (char*) apr_palloc((apr_pool_t*) p.getAPRPool(), str.length() + feedCount + 1);
+               char* current = retval;
+               char* startOfLine = current;
+               //
+               //    iterator through message
+               //
+               for(LogString::const_iterator iter = str.begin();
+                   iter != str.end();
+                   iter++) {
+                   unsigned int c = *iter;
+                   //
+                   //   replace non-ASCII characters with '?'
+                   //
+                   if (c > 0x7F) {
+                      *current++ = '?';
+                   } else if (c == '\n' || c == '\r') {
+                      //
+                      //   replace any stray CR or LF with CRLF
+                      //      reset start of line
+                      *current++ = '\r';
+                      *current++ = '\n';
+                      startOfLine = current;
+                      LogString::const_iterator next = iter + 1;
+                      if (next != str.end() && (*next == '\n' || *next == '\r')) {
+                         iter++;
+                      }
+                   } else {
+                      //
+                      //    truncate any lines to 1000 characters (including CRLF)
+                      //       as required by RFC.
+                      if (current < startOfLine + 998) {
+                        *current++ = (char) c;
+                      }
+                   }
+               }
+               *current = 0;
+               return retval;
+           }
+           
+           /**
+            *  Callback for message.
+            */
+           static const char* messagecb(void** ctx, int* len, void* arg) {
+               *ctx = 0;
+               const char* retval = 0;
+               SMTPMessage* pThis = (SMTPMessage*) arg;
+               //   rewind message
+               if (len == NULL) {
+                   pThis->current = pThis->body;
+               } else {
+                  if (pThis->current) {
+                    *len = strlen(pThis->current);
+                  }
+                  retval = pThis->current;
+                  pThis->current = 0;
+               }
+               return retval;
+           }
+           
+        };
+#endif        
+        
+                class LOG4CXX_EXPORT DefaultEvaluator :
+                        public virtual spi::TriggeringEventEvaluator,
+                        public virtual helpers::ObjectImpl
+                {
+                public:
+                        DECLARE_LOG4CXX_OBJECT(DefaultEvaluator)
+                        BEGIN_LOG4CXX_CAST_MAP()
+                                LOG4CXX_CAST_ENTRY(DefaultEvaluator)
+                                LOG4CXX_CAST_ENTRY(spi::TriggeringEventEvaluator)
+                        END_LOG4CXX_CAST_MAP()
+
+                        DefaultEvaluator();
+
+                        /**
+                        Is this <code>event</code> the e-mail triggering event?
+                        <p>This method returns <code>true</code>, if the event level
+                        has ERROR level or higher. Otherwise it returns
+                        <code>false</code>.
+                        */
+                        virtual bool isTriggeringEvent(const spi::LoggingEventPtr& event);
+                private:
+                         DefaultEvaluator(const DefaultEvaluator&);
+                         DefaultEvaluator& operator=(const DefaultEvaluator&);
+                }; // class DefaultEvaluator
+        
+    }
+}
+
 IMPLEMENT_LOG4CXX_OBJECT(DefaultEvaluator)
 IMPLEMENT_LOG4CXX_OBJECT(SMTPAppender)
 
@@ -49,8 +314,7 @@
 
 SMTPAppender::SMTPAppender()
 : bufferSize(512), locationInfo(false), cb(bufferSize),
-evaluator(new DefaultEvaluator()), session(0),
-encoding(LOG4CXX_STR("7bit")), charset(LOG4CXX_STR("us-ascii"))
+evaluator(new DefaultEvaluator()), smtpPort(25)
 {
 }
 
@@ -59,8 +323,7 @@
 TriggeringEventEvaluator for this SMTPAppender.  */
 SMTPAppender::SMTPAppender(spi::TriggeringEventEvaluatorPtr evaluator)
 : bufferSize(512), locationInfo(false), cb(bufferSize),
-evaluator(evaluator), session(0),
-encoding(LOG4CXX_STR("7bit")), charset(LOG4CXX_STR("us-ascii"))
+evaluator(evaluator), smtpPort(25)
 {
 }
 
@@ -69,6 +332,72 @@
    finalize();
 }
 
+bool SMTPAppender::requiresLayout() const { 
+    return true; 
+}
+
+
+LogString SMTPAppender::getFrom() const {
+    return from;
+}
+
+void SMTPAppender::setFrom(const LogString& newVal) {
+    from = newVal;
+}
+
+
+LogString SMTPAppender::getSubject() const {
+    return subject;
+}
+
+void SMTPAppender::setSubject(const LogString& newVal) {
+    subject = newVal;
+}
+
+LogString SMTPAppender::getSMTPHost() const {
+    return smtpHost;
+}
+
+void SMTPAppender::setSMTPHost(const LogString& newVal) {
+    smtpHost = newVal;
+}
+
+int SMTPAppender::getSMTPPort() const {
+    return smtpPort;
+}
+
+void SMTPAppender::setSMTPPort(int newVal) {
+    smtpPort = newVal;
+}
+
+bool SMTPAppender::getLocationInfo() const {
+   return locationInfo;
+}
+
+void SMTPAppender::setLocationInfo(bool newVal) { 
+    locationInfo = newVal; 
+}
+
+LogString SMTPAppender::getSMTPUsername() const {
+    return smtpUsername;
+}
+
+void SMTPAppender::setSMTPUsername(const LogString& newVal) {
+    smtpUsername = newVal;
+}
+
+LogString SMTPAppender::getSMTPPassword() const {
+    return smtpPassword;
+}
+
+void SMTPAppender::setSMTPPassword(const LogString& newVal) {
+    smtpPassword = newVal;
+}
+
+
+
+
+
 void SMTPAppender::setOption(const LogString& option,
    const LogString& value)
 {
@@ -88,6 +417,14 @@
    {
       setSMTPHost(value);
    }
+   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPUSERNAME"), LOG4CXX_STR("smtpusername")))
+   {
+      setSMTPUsername(value);
+   }
+   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPPASSWORD"), LOG4CXX_STR("smtppassword")))
+   {
+      setSMTPPassword(value);
+   }
    else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SUBJECT"), LOG4CXX_STR("subject")))
    {
       setSubject(value);
@@ -96,13 +433,17 @@
    {
       setTo(value);
    }
-   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("CHARSET"), LOG4CXX_STR("charset")))
+   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("CC"), LOG4CXX_STR("cc")))
    {
-      setCharset(value);
+      setCc(value);
    }
-   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ENCODING"), LOG4CXX_STR("encoding")))
+   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BCC"), LOG4CXX_STR("bcc")))
    {
-      setEncoding(value);
+      setBcc(value);
+   }
+   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPPORT"), LOG4CXX_STR("smtpport")))
+   {
+      setSMTPPort(OptionConverter::toInt(value, 25));
    }
    else
    {
@@ -110,126 +451,55 @@
    }
 }
 
+
+bool SMTPAppender::asciiCheck(const LogString& value, const logchar* field) {
+     for(LogString::const_iterator iter = value.begin();
+         iter != value.end();
+         iter++) {
+         if (0x7F < (unsigned int) *iter) {
+            LogLog::warn(LogString(field) + LOG4CXX_STR(" contains non-ASCII character"));
+            return false;
+         } 
+     }
+     return true;
+}
+
 /**
 Activate the specified options, such as the smtp host, the
 recipient, from, etc. */
 void SMTPAppender::activateOptions(Pool& p)
 {
-   session = ::libsmtp_session_initialize();
-   if (session == 0)
-   {
-      LogLog::error(LOG4CXX_STR("Could not intialize session."));
-      return;
-   }
-
-   LOG4CXX_ENCODE_CHAR(ansiFrom, from);
-   LOG4CXX_ENCODE_CHAR(ansiSubject, subject);
-   ::libsmtp_set_environment(
-      const_cast<char*>(ansiFrom.c_str()),
-      const_cast<char*>(ansiSubject.c_str()),
-      0,
-      (libsmtp_session_struct *)session);
-
-   std::vector<LogString> recipients = parseAddress(to);
-   std::vector<LogString>::iterator i;
-   for (i = recipients.begin(); i != recipients.end(); i++)
-   {
-      LOG4CXX_ENCODE_CHAR(ansiTo, *i);
-      if (::libsmtp_add_recipient(LIBSMTP_REC_TO,
-         const_cast<char*>(ansiTo.c_str()),
-         (libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Could not add recipient ")+ *i + LOG4CXX_STR("."));
-         return;
-      }
-   }
-
-   // MIMEPART
-   if (layout != 0)
-   {
-      int mimeType = 0;
-      LogString contentType(layout->getContentType());
-      if (contentType == LOG4CXX_STR("text/plain"))
-      {
-         mimeType = LIBSMTP_MIME_SUB_PLAIN;
-      }
-      else if (contentType == LOG4CXX_STR("text/html"))
-      {
-         mimeType = LIBSMTP_MIME_SUB_HTML;
-      }
-      else
-      {
-         LogLog::error(LOG4CXX_STR("invalid layout content type: ")+contentType+LOG4CXX_STR("."));
-         return;
-      }
-
-      int charset = 0;
-      if (this->charset == LOG4CXX_STR("us-ascii"))
-      {
-          charset = LIBSMTP_CHARSET_USASCII;
-      }
-      else if (this->charset == LOG4CXX_STR("iso8859_1"))
-      {
-          charset = LIBSMTP_CHARSET_ISO8859_1;
-      }
-      else if (this->charset == LOG4CXX_STR("iso8859_2"))
-      {
-          charset = LIBSMTP_CHARSET_ISO8859_2;
-      }
-      else if (this->charset == LOG4CXX_STR("iso8859_3"))
-      {
-          charset = LIBSMTP_CHARSET_ISO8859_3;
-      }
-      else
-      {
-         LogLog::error(LOG4CXX_STR("invalid charset: ")+this->charset+LOG4CXX_STR("."));
-         return;
-      }
-
-      int encoding = 0;
-      if (this->encoding == LOG4CXX_STR("7bit"))
-      {
-         encoding = LIBSMTP_ENC_7BIT;
-      }
-      else if (this->encoding == LOG4CXX_STR("8bit"))
-      {
-         encoding = LIBSMTP_ENC_8BIT;
-      }
-      else if (this->encoding == LOG4CXX_STR("binary"))
-      {
-         encoding = LIBSMTP_ENC_BINARY;
-      }
-      else if (this->encoding == LOG4CXX_STR("base64"))
-      {
-         encoding = LIBSMTP_ENC_BASE64;
-      }
-      else if (this->encoding == LOG4CXX_STR("quoted"))
-      {
-         encoding = LIBSMTP_ENC_QUOTED;
-      }
-      else
-      {
-         LogLog::error(LOG4CXX_STR("invalid encoding: ")+this->encoding+LOG4CXX_STR("."));
-         return;
-      }
-
-      libsmtp_part_struct * part = 0;
-      part = ::libsmtp_part_new(
-         0,
-         LIBSMTP_MIME_TEXT,
-         mimeType,
-         encoding,
-         charset,
-         "content",
-         (libsmtp_session_struct *)session);
-      if (part == 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error adding part."));
-      }
-   }
-   else
-   {
-      LogLog::error(LOG4CXX_STR("Layout not set !"));
+   bool activate = true;
+   if (layout == 0) {
+      LogLog::error(LOG4CXX_STR("No layout set for appender named [") +name+ LOG4CXX_STR("]."));
+      activate = false;
+   }
+   if(evaluator == 0) {
+      LogLog::error(LOG4CXX_STR("No TriggeringEventEvaluator is set for appender [")+
+			 name+LOG4CXX_STR("]."));
+      activate = false;
+   }
+   if(smtpHost.empty()) {
+      LogLog::error(LOG4CXX_STR("No smtpHost is set for appender [")+
+			 name+LOG4CXX_STR("]."));
+      activate = false;
+   }
+   if(to.empty() && cc.empty() && bcc.empty()) {
+      LogLog::error(LOG4CXX_STR("No recipient address is set for appender [")+
+			 name+LOG4CXX_STR("]."));
+      activate = false;
+   }
+   activate &= asciiCheck(to, LOG4CXX_STR("to"));
+   activate &= asciiCheck(cc, LOG4CXX_STR("cc"));
+   activate &= asciiCheck(bcc, LOG4CXX_STR("bcc"));
+   activate &= asciiCheck(from, LOG4CXX_STR("from"));
+ 
+#if !LOG4CXX_HAS_LIBESMTP
+   LogLog::error(LOG4CXX_STR("log4cxx built without SMTP support."));
+   activate = false;
+#endif     
+   if (activate) {
+        AppenderSkeleton::activateOptions(p);
    }
 }
 
@@ -244,12 +514,11 @@
       return;
    }
 
-   event->getNDC();
-
-/* if(locationInfo)
-   {
-      event.getLocationInformation();
-   }*/
+   LogString ndc;
+   event->getNDC(ndc);
+   event->getThreadName();
+   // Get a copy of this thread's MDC.
+   event->getMDCCopy();
 
    cb.add(event);
 
@@ -266,7 +535,8 @@
 value <code>false</code> is returned. */
 bool SMTPAppender::checkEntryConditions()
 {
-   if(to.empty() || from.empty() || subject.empty() || smtpHost.empty())
+#if LOG4CXX_HAVE_LIBESMTP
+   if((to.empty() && cc.empty() && bcc.empty()) || from.empty() || smtpHost.empty())
    {
       errorHandler->error(LOG4CXX_STR("Message not configured."));
       return false;
@@ -286,31 +556,39 @@
       return false;
    }
    return true;
+#else
+   return false;
+#endif   
 }
 
-void SMTPAppender::close()
-{
-   synchronized sync(this);
-   if (!this->closed && session != 0)
-   {
-      ::libsmtp_free((libsmtp_session_struct *)session);
-      session = 0;
-   }
 
+
+void SMTPAppender::close() {
    this->closed = true;
 }
 
-std::vector<LogString> SMTPAppender::parseAddress(const LogString& addressStr)
-{
-   std::vector<LogString> addresses;
+LogString SMTPAppender::getTo() const{
+   return to;
+}
 
-   StringTokenizer st(addressStr, LOG4CXX_STR(","));
-   while (st.hasMoreTokens())
-   {
-      addresses.push_back(st.nextToken());
-   }
+void SMTPAppender::setTo(const LogString& addressStr) {
+     to = addressStr;
+}
 
-   return addresses;
+LogString SMTPAppender::getCc() const{
+   return cc;
+}
+
+void SMTPAppender::setCc(const LogString& addressStr) {
+     cc = addressStr;
+}
+
+LogString SMTPAppender::getBcc() const{
+   return bcc;
+}
+
+void SMTPAppender::setBcc(const LogString& addressStr) {
+     bcc = addressStr;
 }
 
 /**
@@ -318,6 +596,7 @@
 */
 void SMTPAppender::sendBuffer(Pool& p)
 {
+#if LOG4CXX_HAS_LIBESMTP
    // Note: this code already owns the monitor for this
    // appender. This frees us from needing to synchronize on 'cb'.
    try
@@ -328,75 +607,25 @@
       int len = cb.length();
       for(int i = 0; i < len; i++)
       {
-            //sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
          LoggingEventPtr event = cb.get();
          layout->format(sbuf, event, p);
       }
 
       layout->appendFooter(sbuf, p);
 
-      LOG4CXX_ENCODE_CHAR(aSmtpHost, smtpHost);
-
-      /* This starts the SMTP connection */
-      if (::libsmtp_connect(
-         const_cast<char*>(aSmtpHost.c_str()),
-         0,
-         0,
-         (libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while starting the SMTP connection."));
-         return;
-      }
-
-      /* This will conduct the SMTP dialogue */
-      if (::libsmtp_dialogue((libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while conducting the SMTP dialogue."));
-         return;
-      }
-
-      /* Now lets send the headers */
-      if (::libsmtp_headers((libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while sending the headers."));
-         return;
-      }
-
-      /* Now lets send the MIME headers */
-      if (::libsmtp_mime_headers((libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while sending the MIME headers."));
-         return;
-      }
-
-      LOG4CXX_ENCODE_CHAR(s, sbuf);
-      if (::libsmtp_part_send(
-         const_cast<char*>(s.c_str()),
-         s.length(),
-         (libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while sending the message body."));
-      }
-
-      /* This ends the body part */
-      if (::libsmtp_body_end((libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while ending the body part."));
-         return;
-      }
-
-      /* This ends the connection gracefully */
-      if (::libsmtp_quit((libsmtp_session_struct *)session) != 0)
-      {
-         LogLog::error(LOG4CXX_STR("Error occured while ending the connection."));
-         return;
-      }
+      SMTPSession session(smtpHost, smtpPort, smtpUsername, smtpPassword, p);
+      
+      SMTPMessage message(session, from, to, cc, 
+          bcc, subject, sbuf, p);
+      
+      session.send(p);
 
    }
    catch(std::exception& e)
    {
       LogLog::error(LOG4CXX_STR("Error occured while sending e-mail notification."), e);
    }
+#endif   
 }
 
 /**
@@ -407,6 +636,14 @@
    return evaluator == 0 ? LogString() : evaluator->getClass().getName();
 }
 
+log4cxx::spi::TriggeringEventEvaluatorPtr SMTPAppender::getEvaluator() const {
+   return evaluator;
+}
+
+void SMTPAppender::setEvaluator(log4cxx::spi::TriggeringEventEvaluatorPtr& trigger) {
+    evaluator = trigger;
+}
+
 /**
 The <b>BufferSize</b> option takes a positive integer
 representing the maximum number of logging events to collect in a
@@ -432,6 +669,4 @@
    evaluator = OptionConverter::instantiateByClassName(value,
       TriggeringEventEvaluator::getStaticClass(), evaluator);
 }
-
-#endif //LOG4CXX_HAVE_SMTP
 

Modified: logging/log4cxx/trunk/src/main/include/log4cxx/net/smtpappender.h
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/include/log4cxx/net/smtpappender.h?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/include/log4cxx/net/smtpappender.h (original)
+++ logging/log4cxx/trunk/src/main/include/log4cxx/net/smtpappender.h Mon Dec 10 18:11:34 2007
@@ -23,14 +23,10 @@
 #include <log4cxx/helpers/cyclicbuffer.h>
 #include <log4cxx/spi/triggeringeventevaluator.h>
 
-
 namespace log4cxx
 {
         namespace net
         {
-                class SMTPAppender;
-                typedef helpers::ObjectPtrT<SMTPAppender> SMTPAppenderPtr;
-
                 /**
                 Send an e-mail when a specific logging event occurs, typically on
                 errors or fatal errors.
@@ -44,18 +40,30 @@
                 class LOG4CXX_EXPORT SMTPAppender : public AppenderSkeleton
                 {
                 private:
+
+                private:
+                        SMTPAppender(const SMTPAppender&);
+                        SMTPAppender& operator=(const SMTPAppender&);
+                        static bool asciiCheck(const LogString&, const logchar*);
+                        /**
+                        This method determines if there is a sense in attempting to append.
+                        <p>It checks whether there is a set output target and also if
+                        there is a set layout. If these checks fail, then the boolean
+                        value <code>false</code> is returned. */
+                        bool checkEntryConditions();
+
                         LogString to;
+                        LogString cc;
+                        LogString bcc;
                         LogString from;
                         LogString subject;
                         LogString smtpHost;
+                        LogString smtpUsername;
+                        LogString smtpPassword;
+                        int smtpPort;
                         int bufferSize; // 512
                         bool locationInfo;
                         helpers::CyclicBuffer cb;
-                        void * session;
-                        LogString encoding;
-                        LogString charset;
-
-                protected:
                         spi::TriggeringEventEvaluatorPtr evaluator;
 
                 public:
@@ -97,45 +105,35 @@
                         an e-mail to be sent. */
                         virtual void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p);
 
-                        /**
-                        This method determines if there is a sense in attempting to append.
-                        <p>It checks whether there is a set output target and also if
-                        there is a set layout. If these checks fail, then the boolean
-                        value <code>false</code> is returned. */
-                        bool checkEntryConditions();
 
                         virtual void close();
 
-                        std::vector<LogString> parseAddress(const LogString& addressStr);
-
                         /**
                         Returns value of the <b>To</b> option.
                         */
-                        inline const LogString& getTo() const
-                                { return to; }
+                        LogString getTo() const;
 
                         /**
-                        The <code>SMTPAppender</code> requires a {@link
-                        Layout layout}.  */
-                        virtual bool requiresLayout() const
-                                { return true; }
+                        Returns value of the <b>cc</b> option.
+                        */
+                        LogString getCc() const;
 
                         /**
-                        Send the contents of the cyclic buffer as an e-mail message.
+                        Returns value of the <b>bcc</b> option.
                         */
-                        void sendBuffer(log4cxx::helpers::Pool& p);
+                        LogString getBcc() const;
+
 
                         /**
-                        Returns value of the <b>Charset</b> option.
-                        */
-                        inline const LogString& getCharset() const
-                                { return charset; }
+                        The <code>SMTPAppender</code> requires a {@link
+                        Layout layout}.  */
+                        virtual bool requiresLayout() const;
 
                         /**
-                        Returns value of the <b>Encoding</b> option.
+                        Send the contents of the cyclic buffer as an e-mail message.
                         */
-                        inline const LogString& getEncoding() const
-                                { return encoding; }
+                        void sendBuffer(log4cxx::helpers::Pool& p);
+
 
                         /**
                         Returns value of the <b>EvaluatorClass</b> option.
@@ -145,44 +143,25 @@
                         /**
                         Returns value of the <b>From</b> option.
                         */
-                        inline const LogString& getFrom() const
-                                { return from; }
+                        LogString getFrom() const;
 
                         /**
                         Returns value of the <b>Subject</b> option.
                         */
-                        inline const LogString& getSubject() const
-                                { return subject; }
+                        LogString getSubject() const;
 
-                        /**
-                        The <b>Charset</b> option takes a string value which should be the
-                        charset of the mail (<code>us-ascii</code>, <code>iso8859_1</code>,
-                        <code>iso8859_2</code>, <code>iso8859_3</code>).
-                        */
-                        inline void setCharset(const LogString& charset)
-                                { this->charset.assign(charset); }
-
-                        /**
-                        The <b>Encoding</b> option takes a string value which should be the
-                        encoding type of the mail (<code>7bit</code>, <code>8bit</code>,
-                        <code>base64</code>, <code>binary</code>, <code>quoted</code>).
-                        */
-                        inline void setEncoding(const LogString& charset)
-                                { this->encoding.assign(encoding); }
 
                         /**
                         The <b>From</b> option takes a string value which should be a
                         e-mail address of the sender.
                         */
-                        inline void setFrom(const LogString& from)
-                                { this->from.assign(from); }
+                        void setFrom(const LogString& from);
 
                         /**
                         The <b>Subject</b> option takes a string value which should be a
                         the subject of the e-mail message.
                         */
-                        inline void setSubject(const LogString& subject)
-                                { this->subject.assign(subject); }
+                        void setSubject(const LogString& subject);
 
                         /**
                         The <b>BufferSize</b> option takes a positive integer
@@ -197,21 +176,64 @@
                         The <b>SMTPHost</b> option takes a string value which should be a
                         the host name of the SMTP server that will send the e-mail message.
                         */
-                        inline void setSMTPHost(const LogString& smtpHost)
-                                { this->smtpHost.assign(smtpHost); }
+                        void setSMTPHost(const LogString& smtpHost);
+
+                        /**
+                        Returns value of the <b>SMTPHost</b> option.
+                        */
+                        LogString getSMTPHost() const;
+
+                        /**
+                        The <b>SMTPPort</b> option takes a string value which should be a
+                        the port of the SMTP server that will send the e-mail message.
+                        */
+                        void setSMTPPort(int port);
 
                         /**
                         Returns value of the <b>SMTPHost</b> option.
                         */
-                        inline const LogString& getSMTPHost() const
-                                { return smtpHost; }
+                        int getSMTPPort() const;
 
                         /**
                         The <b>To</b> option takes a string value which should be a
                         comma separated list of e-mail address of the recipients.
                         */
-                        inline void setTo(const LogString& to)
-                                { this->to.assign(to); }
+                        void setTo(const LogString& to);
+
+                        /**
+                        The <b>Cc</b> option takes a string value which should be a
+                        comma separated list of e-mail address of the cc'd recipients.
+                        */
+                        void setCc(const LogString& to);
+
+                        /**
+                        The <b>Bcc</b> option takes a string value which should be a
+                        comma separated list of e-mail address of the bcc'd recipients.
+                        */
+                        void setBcc(const LogString& to);
+
+
+                        /**
+                        The <b>SMTPUsername</b> option takes a string value which should be a
+                        the user name for the SMTP server.
+                        */
+                        void setSMTPUsername(const LogString& newVal);
+
+                        /**
+                        Returns value of the <b>SMTPUsername</b> option.
+                        */
+                        LogString getSMTPUsername() const;
+
+                        /**
+                        The <b>SMTPPassword</b> option takes a string value which should be a
+                        the password for the SMTP server.
+                        */
+                        void setSMTPPassword(const LogString& newVal);
+
+                        /**
+                        Returns value of the <b>SMTPPassword</b> option.
+                        */
+                        LogString getSMTPPassword() const;
 
                         /**
                         Returns value of the <b>BufferSize</b> option.
@@ -219,6 +241,19 @@
                         inline int getBufferSize() const
                                 { return bufferSize; }
 
+                   
+                        /**
+                         *   Gets the current triggering evaluator.
+                         *   @return triggering evaluator.
+                         */     
+                        log4cxx::spi::TriggeringEventEvaluatorPtr getEvaluator() const;
+
+                        /**
+                         *   Sets the triggering evaluator.
+                         *   @param trigger triggering evaluator.
+                         */     
+                        void setEvaluator(log4cxx::spi::TriggeringEventEvaluatorPtr& trigger);
+
                         /**
                         The <b>EvaluatorClass</b> option takes a string value
                         representing the name of the class implementing the
@@ -227,56 +262,21 @@
                         for the SMTPAppender.
                         */
                         void setEvaluatorClass(const LogString& value);
-
+                 
                         /**
-                        The <b>LocationInfo</b> option takes a boolean value. By
-                        default, it is set to false which means there will be no effort
-                        to extract the location information related to the event. As a
-                        result, the layout that formats the events as they are sent out
-                        in an e-mail is likely to place the wrong location information
-                        (if present in the format).
-
-                        <p>Location information extraction is comparatively very slow and
-                        should be avoided unless performance is not a concern.
+                        The <b>LocationInfo</b> option is provided for compatibility with log4j
+                        and has no effect in log4cxx.
                         */
-                        inline void setLocationInfo(bool locationInfo)
-                                { this->locationInfo = locationInfo; }
+                        void setLocationInfo(bool locationInfo);
 
                         /**
                         Returns value of the <b>LocationInfo</b> option.
                         */
-                        inline bool getLocationInfo() const
-                                { return locationInfo; }
-
-                private:
-                        SMTPAppender(const SMTPAppender&);
-                        SMTPAppender& operator=(const SMTPAppender&);
-
+                        bool getLocationInfo() const;
                 }; // class SMTPAppender
+                
+                typedef helpers::ObjectPtrT<SMTPAppender> SMTPAppenderPtr;                
 
-                class LOG4CXX_EXPORT DefaultEvaluator :
-                        public virtual spi::TriggeringEventEvaluator,
-                        public virtual helpers::ObjectImpl
-                {
-                public:
-                        DECLARE_LOG4CXX_OBJECT(DefaultEvaluator)
-                        BEGIN_LOG4CXX_CAST_MAP()
-                                LOG4CXX_CAST_ENTRY(spi::TriggeringEventEvaluator)
-                        END_LOG4CXX_CAST_MAP()
-
-                        DefaultEvaluator();
-
-                        /**
-                        Is this <code>event</code> the e-mail triggering event?
-                        <p>This method returns <code>true</code>, if the event level
-                        has ERROR level or higher. Otherwise it returns
-                        <code>false</code>.
-                        */
-                        virtual bool isTriggeringEvent(const spi::LoggingEventPtr& event);
-                private:
-                         DefaultEvaluator(const DefaultEvaluator&);
-                         DefaultEvaluator& operator=(const DefaultEvaluator&);
-                }; // class DefaultEvaluator
         }  // namespace net
 } // namespace log4cxx
 

Modified: logging/log4cxx/trunk/src/main/include/log4cxx/private/log4cxx_private.h.in
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/include/log4cxx/private/log4cxx_private.h.in?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/include/log4cxx/private/log4cxx_private.h.in (original)
+++ logging/log4cxx/trunk/src/main/include/log4cxx/private/log4cxx_private.h.in Mon Dec 10 18:11:34 2007
@@ -54,7 +54,7 @@
 //   Capabilities should be checked in client code by
 //       attempting creation of the corresponding appender.
 //
-#define LOG4CXX_HAVE_SMTP 0
+#define LOG4CXX_HAVE_LIBESMTP @HAS_LIBESMTP@
 #define LOG4CXX_HAVE_SYSLOG @HAS_SYSLOG@
 
 #endif

Modified: logging/log4cxx/trunk/src/main/include/log4cxx/xml/domconfigurator.h
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/include/log4cxx/xml/domconfigurator.h?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/include/log4cxx/xml/domconfigurator.h (original)
+++ logging/log4cxx/trunk/src/main/include/log4cxx/xml/domconfigurator.h Mon Dec 10 18:11:34 2007
@@ -168,7 +168,7 @@
                         /**
                          Used internally to parse the logger factory element.
                         */
-                        log4cxx::rolling::TriggeringPolicyPtr parseTriggeringPolicy(
+                        log4cxx::helpers::ObjectPtr parseTriggeringPolicy(
                             log4cxx::helpers::Pool& p,
                             log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
                             apr_xml_elem* factoryElement);

Modified: logging/log4cxx/trunk/src/test/cpp/net/smtpappendertestcase.cpp
URL: http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/test/cpp/net/smtpappendertestcase.cpp?rev=603118&r1=603117&r2=603118&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/test/cpp/net/smtpappendertestcase.cpp (original)
+++ logging/log4cxx/trunk/src/test/cpp/net/smtpappendertestcase.cpp Mon Dec 10 18:11:34 2007
@@ -24,9 +24,45 @@
 #include <cppunit/extensions/HelperMacros.h>
 #include <log4cxx/net/smtpappender.h>
 #include "../appenderskeletontestcase.h"
+#include <log4cxx/xml/domconfigurator.h>
+#include <log4cxx/logmanager.h>
+#include <log4cxx/ttcclayout.h>
 
 using namespace log4cxx;
 using namespace log4cxx::helpers;
+using namespace log4cxx::net;
+using namespace log4cxx::xml;
+using namespace log4cxx::spi;
+
+namespace log4cxx {
+    namespace net {
+
+                class MockTriggeringEventEvaluator :
+                        public virtual spi::TriggeringEventEvaluator,
+                        public virtual helpers::ObjectImpl
+                {
+                public:
+                        DECLARE_LOG4CXX_OBJECT(MockTriggeringEventEvaluator)
+                        BEGIN_LOG4CXX_CAST_MAP()
+                                LOG4CXX_CAST_ENTRY(MockTriggeringEventEvaluator)
+                                LOG4CXX_CAST_ENTRY(spi::TriggeringEventEvaluator)
+                        END_LOG4CXX_CAST_MAP()
+
+                        MockTriggeringEventEvaluator() {
+                        }
+
+                        virtual bool isTriggeringEvent(const spi::LoggingEventPtr& event) {
+                            return true;
+                        }
+                private:
+                         MockTriggeringEventEvaluator(const MockTriggeringEventEvaluator&);
+                         MockTriggeringEventEvaluator& operator=(const MockTriggeringEventEvaluator&);
+                };
+    }
+}
+
+IMPLEMENT_LOG4CXX_OBJECT(MockTriggeringEventEvaluator)
+
 
 /**
    Unit tests of log4cxx::SocketAppender
@@ -39,7 +75,8 @@
                 //
                 CPPUNIT_TEST(testDefaultThreshold);
                 CPPUNIT_TEST(testSetOptionThreshold);
-
+                CPPUNIT_TEST(testTrigger);
+                CPPUNIT_TEST(testInvalid);
    CPPUNIT_TEST_SUITE_END();
 
 
@@ -48,6 +85,38 @@
         AppenderSkeleton* createAppenderSkeleton() const {
           return new log4cxx::net::SMTPAppender();
         }
+        
+   void setUp() {
+   }
+   
+   void tearDown() {
+       LogManager::resetConfiguration();
+   }
+
+    /**
+     * Tests that triggeringPolicy element will set evaluator.
+     */
+  void testTrigger() {
+      DOMConfigurator::configure("input/xml/smtpAppender1.xml");
+      SMTPAppenderPtr appender(Logger::getRootLogger()->getAppender(LOG4CXX_STR("A1")));
+      TriggeringEventEvaluatorPtr evaluator(appender->getEvaluator());
+      CPPUNIT_ASSERT_EQUAL(true, evaluator->instanceof(MockTriggeringEventEvaluator::getStaticClass()));
+  }
+  
+  void testInvalid() {
+      SMTPAppenderPtr appender(new SMTPAppender());
+      appender->setSMTPHost(LOG4CXX_STR("smtp.invalid"));
+      appender->setTo(LOG4CXX_STR("you@example.invalid"));
+      appender->setFrom(LOG4CXX_STR("me@example.invalid"));
+      appender->setLayout(new TTCCLayout());
+      Pool p;
+      appender->activateOptions(p);
+      LoggerPtr root(Logger::getRootLogger());
+      root->addAppender(appender);
+      LOG4CXX_INFO(root, "Hello, World.");
+      LOG4CXX_ERROR(root, "Sending Message");
+  }
+
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SMTPAppenderTestCase);