/src/logging-log4cxx/src/main/cpp/smtpappender.cpp
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
| 3 |  |  * contributor license agreements.  See the NOTICE file distributed with | 
| 4 |  |  * this work for additional information regarding copyright ownership. | 
| 5 |  |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
| 6 |  |  * (the "License"); you may not use this file except in compliance with | 
| 7 |  |  * the License.  You may obtain a copy of the License at | 
| 8 |  |  * | 
| 9 |  |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  |  * | 
| 11 |  |  * Unless required by applicable law or agreed to in writing, software | 
| 12 |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 13 |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 14 |  |  * See the License for the specific language governing permissions and | 
| 15 |  |  * limitations under the License. | 
| 16 |  |  */ | 
| 17 |  | #include <log4cxx/net/smtpappender.h> | 
| 18 |  | #include <log4cxx/level.h> | 
| 19 |  | #include <log4cxx/helpers/loglog.h> | 
| 20 |  | #include <log4cxx/helpers/optionconverter.h> | 
| 21 |  | #include <log4cxx/spi/loggingevent.h> | 
| 22 |  | #include <log4cxx/private/string_c11.h> | 
| 23 |  | #include <log4cxx/helpers/stringhelper.h> | 
| 24 |  | #include <log4cxx/helpers/stringtokenizer.h> | 
| 25 |  | #include <log4cxx/helpers/transcoder.h> | 
| 26 |  | #include <log4cxx/helpers/loader.h> | 
| 27 |  | #if !defined(LOG4CXX) | 
| 28 |  |   #define LOG4CXX 1 | 
| 29 |  | #endif | 
| 30 |  | #include <log4cxx/private/log4cxx_private.h> | 
| 31 |  | #include <log4cxx/private/appenderskeleton_priv.h> | 
| 32 |  |  | 
| 33 |  |  | 
| 34 |  | #include <apr_strings.h> | 
| 35 |  | #include <vector> | 
| 36 |  |  | 
| 37 |  | using namespace LOG4CXX_NS; | 
| 38 |  | using namespace LOG4CXX_NS::helpers; | 
| 39 |  | using namespace LOG4CXX_NS::net; | 
| 40 |  | using namespace LOG4CXX_NS::spi; | 
| 41 |  |  | 
| 42 |  | #if LOG4CXX_HAVE_LIBESMTP | 
| 43 |  |   #include <auth-client.h> | 
| 44 |  |   #include <libesmtp.h> | 
| 45 |  | #endif | 
| 46 |  |  | 
| 47 |  | namespace LOG4CXX_NS | 
| 48 |  | { | 
| 49 |  | namespace net | 
| 50 |  | { | 
| 51 |  | // | 
| 52 |  | //   The following two classes implement an C++ SMTP wrapper over libesmtp. | 
| 53 |  | //   The same signatures could be implemented over different SMTP implementations | 
| 54 |  | //   or libesmtp could be combined with libgmime to enable support for non-ASCII | 
| 55 |  | //   content. | 
| 56 |  |  | 
| 57 |  | #if LOG4CXX_HAVE_LIBESMTP | 
| 58 |  | /** | 
| 59 |  |  *   SMTP Session. | 
| 60 |  |  */ | 
| 61 |  | class SMTPSession | 
| 62 |  | { | 
| 63 |  |   public: | 
| 64 |  |     /** | 
| 65 |  |     *   Create new instance. | 
| 66 |  |     */ | 
| 67 |  |     SMTPSession(const LogString& smtpHost, | 
| 68 |  |       int smtpPort, | 
| 69 |  |       const LogString& smtpUsername, | 
| 70 |  |       const LogString& smtpPassword, | 
| 71 |  |       Pool& p) : session(0), authctx(0), | 
| 72 |  |       user(toAscii(smtpUsername, p)), | 
| 73 |  |       pwd(toAscii(smtpPassword, p)) | 
| 74 |  |     { | 
| 75 |  |       auth_client_init(); | 
| 76 |  |       session = smtp_create_session(); | 
| 77 |  |  | 
| 78 |  |       if (session == 0) | 
| 79 |  |       { | 
| 80 |  |         throw Exception("Could not initialize session."); | 
| 81 |  |       } | 
| 82 |  |  | 
| 83 |  |       std::string host(toAscii(smtpHost, p)); | 
| 84 |  |       host.append(1, ':'); | 
| 85 |  |       host.append(p.itoa(smtpPort)); | 
| 86 |  |       smtp_set_server(session, host.c_str()); | 
| 87 |  |  | 
| 88 |  |       authctx = auth_create_context(); | 
| 89 |  |       auth_set_mechanism_flags(authctx, AUTH_PLUGIN_PLAIN, 0); | 
| 90 |  |       auth_set_interact_cb(authctx, authinteract, (void*) this); | 
| 91 |  |  | 
| 92 |  |       if (*user || *pwd) | 
| 93 |  |       { | 
| 94 |  |         smtp_auth_set_context(session, authctx); | 
| 95 |  |       } | 
| 96 |  |     } | 
| 97 |  |  | 
| 98 |  |     ~SMTPSession() | 
| 99 |  |     { | 
| 100 |  |       smtp_destroy_session(session); | 
| 101 |  |       auth_destroy_context(authctx); | 
| 102 |  |     } | 
| 103 |  |  | 
| 104 |  |     void send(Pool& p) | 
| 105 |  |     { | 
| 106 |  |       int status = smtp_start_session(session); | 
| 107 |  |  | 
| 108 |  |       if (!status) | 
| 109 |  |       { | 
| 110 |  |         size_t bufSize = 128; | 
| 111 |  |         char* buf = p.pstralloc(bufSize); | 
| 112 |  |         smtp_strerror(smtp_errno(), buf, bufSize); | 
| 113 |  |         throw Exception(buf); | 
| 114 |  |       } | 
| 115 |  |     } | 
| 116 |  |  | 
| 117 |  |     operator smtp_session_t() | 
| 118 |  |     { | 
| 119 |  |       return session; | 
| 120 |  |     } | 
| 121 |  |  | 
| 122 |  |     static char* toAscii(const LogString& str, Pool& p) | 
| 123 |  |     { | 
| 124 |  |       char* buf = p.pstralloc(str.length() + 1); | 
| 125 |  |       char* current = buf; | 
| 126 |  |  | 
| 127 |  |       for (unsigned int c : str) | 
| 128 |  |       { | 
| 129 |  |         if (c > 0x7F) | 
| 130 |  |         { | 
| 131 |  |           c = '?'; | 
| 132 |  |         } | 
| 133 |  |  | 
| 134 |  |         *current++ = c; | 
| 135 |  |       } | 
| 136 |  |  | 
| 137 |  |       *current = 0; | 
| 138 |  |       return buf; | 
| 139 |  |     } | 
| 140 |  |  | 
| 141 |  |   private: | 
| 142 |  |     SMTPSession(SMTPSession&); | 
| 143 |  |     SMTPSession& operator=(SMTPSession&); | 
| 144 |  |     smtp_session_t session; | 
| 145 |  |     auth_context_t authctx; | 
| 146 |  |     char* user; | 
| 147 |  |     char* pwd; | 
| 148 |  |  | 
| 149 |  |     /** | 
| 150 |  |      *   This method is called if the SMTP server requests authentication. | 
| 151 |  |      */ | 
| 152 |  |     static int authinteract(auth_client_request_t request, char** result, int fields, | 
| 153 |  |       void* arg) | 
| 154 |  |     { | 
| 155 |  |       SMTPSession* pThis = (SMTPSession*) arg; | 
| 156 |  |  | 
| 157 |  |       for (int i = 0; i < fields; i++) | 
| 158 |  |       { | 
| 159 |  |         int flag = request[i].flags & 0x07; | 
| 160 |  |  | 
| 161 |  |         if (flag == AUTH_USER) | 
| 162 |  |         { | 
| 163 |  |           result[i] = pThis->user; | 
| 164 |  |         } | 
| 165 |  |         else if (flag == AUTH_PASS) | 
| 166 |  |         { | 
| 167 |  |           result[i] = pThis->pwd; | 
| 168 |  |         } | 
| 169 |  |       } | 
| 170 |  |  | 
| 171 |  |       return 1; | 
| 172 |  |     } | 
| 173 |  |  | 
| 174 |  |  | 
| 175 |  | }; | 
| 176 |  |  | 
| 177 |  | /** | 
| 178 |  |  *  A message in an SMTP session. | 
| 179 |  |  */ | 
| 180 |  | class SMTPMessage | 
| 181 |  | { | 
| 182 |  |   public: | 
| 183 |  |     SMTPMessage(SMTPSession& session, | 
| 184 |  |       const LogString& from, | 
| 185 |  |       const LogString& to, | 
| 186 |  |       const LogString& cc, | 
| 187 |  |       const LogString& bcc, | 
| 188 |  |       const LogString& subject, | 
| 189 |  |       const LogString msg, Pool& p) | 
| 190 |  |     { | 
| 191 |  |       message = smtp_add_message(session); | 
| 192 |  |       current_len = msg.length(); | 
| 193 |  |       body = current = toMessage(msg, p); | 
| 194 |  |       messagecbState = 0; | 
| 195 |  |       smtp_set_reverse_path(message, toAscii(from, p)); | 
| 196 |  |       addRecipients(to, "To", p); | 
| 197 |  |       addRecipients(cc, "Cc", p); | 
| 198 |  |       addRecipients(bcc, "Bcc", p); | 
| 199 |  |  | 
| 200 |  |       if (!subject.empty()) | 
| 201 |  |       { | 
| 202 |  |         smtp_set_header(message, "Subject", toAscii(subject, p)); | 
| 203 |  |       } | 
| 204 |  |  | 
| 205 |  |       smtp_set_messagecb(message, messagecb, this); | 
| 206 |  |     } | 
| 207 |  |     ~SMTPMessage() | 
| 208 |  |     { | 
| 209 |  |     } | 
| 210 |  |  | 
| 211 |  |   private: | 
| 212 |  |     SMTPMessage(const SMTPMessage&); | 
| 213 |  |     SMTPMessage& operator=(const SMTPMessage&); | 
| 214 |  |     smtp_message_t message; | 
| 215 |  |     const char* body; | 
| 216 |  |     const char* current; | 
| 217 |  |     size_t current_len; | 
| 218 |  |     int messagecbState; | 
| 219 |  |     void addRecipients(const LogString& addresses, const char* field, Pool& p) | 
| 220 |  |     { | 
| 221 |  |       if (!addresses.empty()) | 
| 222 |  |       { | 
| 223 |  |         char* str = p.pstrdup(toAscii(addresses, p));; | 
| 224 |  |         smtp_set_header(message, field, NULL, str); | 
| 225 |  |         char* last; | 
| 226 |  |  | 
| 227 |  |         for (char* next = apr_strtok(str, ",", &last); | 
| 228 |  |           next; | 
| 229 |  |           next = apr_strtok(NULL, ",", &last)) | 
| 230 |  |         { | 
| 231 |  |           smtp_add_recipient(message, next); | 
| 232 |  |         } | 
| 233 |  |       } | 
| 234 |  |     } | 
| 235 |  |     static const char* toAscii(const LogString& str, Pool& p) | 
| 236 |  |     { | 
| 237 |  |       return SMTPSession::toAscii(str, p); | 
| 238 |  |     } | 
| 239 |  |  | 
| 240 |  |     /** | 
| 241 |  |      *   Message bodies can only contain US-ASCII characters and | 
| 242 |  |      *   CR and LFs can only occur together. | 
| 243 |  |      */ | 
| 244 |  |     static const char* toMessage(const LogString& str, Pool& p) | 
| 245 |  |     { | 
| 246 |  |       // | 
| 247 |  |       //    count the number of carriage returns and line feeds | 
| 248 |  |       // | 
| 249 |  |       int feedCount = 0; | 
| 250 |  |  | 
| 251 |  |       for (size_t pos = str.find_first_of(LOG4CXX_STR("\n\r")); | 
| 252 |  |         pos != LogString::npos; | 
| 253 |  |         pos = str.find_first_of(LOG4CXX_STR("\n\r"), ++pos)) | 
| 254 |  |       { | 
| 255 |  |         feedCount++; | 
| 256 |  |       } | 
| 257 |  |  | 
| 258 |  |       // | 
| 259 |  |       //   allocate sufficient space for the modified message | 
| 260 |  |       char* retval = p.pstralloc(str.length() + feedCount + 1); | 
| 261 |  |       char* current = retval; | 
| 262 |  |       char* startOfLine = current; | 
| 263 |  |       unsigned int ignoreChar = 0; | 
| 264 |  |  | 
| 265 |  |       // | 
| 266 |  |       //    iterator through message | 
| 267 |  |       // | 
| 268 |  |       for (unsigned int c : str) | 
| 269 |  |       { | 
| 270 |  |         // | 
| 271 |  |         //   replace non-ASCII characters with '?' | 
| 272 |  |         // | 
| 273 |  |         if (c > 0x7F) | 
| 274 |  |         { | 
| 275 |  |           *current++ = 0x3F; // '?' | 
| 276 |  |         } | 
| 277 |  |         else if (c == 0x0A || c == 0x0D) | 
| 278 |  |         { | 
| 279 |  |           // | 
| 280 |  |           //   replace any stray CR or LF with CRLF | 
| 281 |  |           //      reset start of line | 
| 282 |  |           if (c == ignoreChar && current == startOfLine) | 
| 283 |  |             ignoreChar = 0; | 
| 284 |  |           else | 
| 285 |  |           { | 
| 286 |  |             *current++ = 0x0D; | 
| 287 |  |             *current++ = 0x0A; | 
| 288 |  |             startOfLine = current; | 
| 289 |  |             ignoreChar = (c == 0x0A ? 0x0D : 0x0A); | 
| 290 |  |           } | 
| 291 |  |         } | 
| 292 |  |         else | 
| 293 |  |         { | 
| 294 |  |           // | 
| 295 |  |           //    truncate any lines to 1000 characters (including CRLF) | 
| 296 |  |           //       as required by RFC. | 
| 297 |  |           if (current < startOfLine + 998) | 
| 298 |  |           { | 
| 299 |  |             *current++ = (char) c; | 
| 300 |  |           } | 
| 301 |  |         } | 
| 302 |  |       } | 
| 303 |  |  | 
| 304 |  |       *current = 0; | 
| 305 |  |       return retval; | 
| 306 |  |     } | 
| 307 |  |  | 
| 308 |  |     /** | 
| 309 |  |      *  Callback for message. | 
| 310 |  |      */ | 
| 311 |  |     static const char* messagecb(void** ctx, int* len, void* arg) | 
| 312 |  |     { | 
| 313 |  |       *ctx = 0; | 
| 314 |  |       const char* retval = 0; | 
| 315 |  |       SMTPMessage* pThis = (SMTPMessage*) arg; | 
| 316 |  |  | 
| 317 |  |       //   rewind message | 
| 318 |  |       if (len == NULL) | 
| 319 |  |       { | 
| 320 |  |         pThis->current = pThis->body; | 
| 321 |  |       } | 
| 322 |  |       else | 
| 323 |  |       { | 
| 324 |  |         // we are asked for headers, but we don't have any | 
| 325 |  |         if ((pThis->messagecbState)++ == 0) | 
| 326 |  |         { | 
| 327 |  |           return NULL; | 
| 328 |  |         } | 
| 329 |  |  | 
| 330 |  |         if (pThis->current) | 
| 331 |  |         { | 
| 332 |  |           *len = strnlen_s(pThis->current, pThis->current_len); | 
| 333 |  |         } | 
| 334 |  |  | 
| 335 |  |         retval = pThis->current; | 
| 336 |  |         pThis->current = 0; | 
| 337 |  |       } | 
| 338 |  |  | 
| 339 |  |       return retval; | 
| 340 |  |     } | 
| 341 |  |  | 
| 342 |  | }; | 
| 343 |  | #endif | 
| 344 |  |  | 
| 345 |  | class LOG4CXX_EXPORT DefaultEvaluator : | 
| 346 |  |   public virtual spi::TriggeringEventEvaluator, | 
| 347 |  |   public virtual helpers::Object | 
| 348 |  | { | 
| 349 |  |   public: | 
| 350 |  |     DECLARE_LOG4CXX_OBJECT(DefaultEvaluator) | 
| 351 | 0 |     BEGIN_LOG4CXX_CAST_MAP() | 
| 352 | 0 |     LOG4CXX_CAST_ENTRY(DefaultEvaluator) | 
| 353 | 0 |     LOG4CXX_CAST_ENTRY(spi::TriggeringEventEvaluator) | 
| 354 | 0 |     END_LOG4CXX_CAST_MAP() | 
| 355 |  |  | 
| 356 |  |     DefaultEvaluator(); | 
| 357 |  |  | 
| 358 |  |     /** | 
| 359 |  |     Is this <code>event</code> the e-mail triggering event? | 
| 360 |  |     <p>This method returns <code>true</code>, if the event level | 
| 361 |  |     has ERROR level or higher. Otherwise it returns | 
| 362 |  |     <code>false</code>. | 
| 363 |  |     */ | 
| 364 |  |     bool isTriggeringEvent(const spi::LoggingEventPtr& event) override; | 
| 365 |  |   private: | 
| 366 |  |     DefaultEvaluator(const DefaultEvaluator&); | 
| 367 |  |     DefaultEvaluator& operator=(const DefaultEvaluator&); | 
| 368 |  | }; // class DefaultEvaluator | 
| 369 |  |  | 
| 370 |  | } | 
| 371 |  | } | 
| 372 |  |  | 
| 373 |  | IMPLEMENT_LOG4CXX_OBJECT(DefaultEvaluator) | 
| 374 |  | IMPLEMENT_LOG4CXX_OBJECT(SMTPAppender) | 
| 375 |  |  | 
| 376 |  | struct SMTPAppender::SMTPPriv : public AppenderSkeletonPrivate | 
| 377 |  | { | 
| 378 |  |   SMTPPriv() : | 
| 379 | 0 |     AppenderSkeletonPrivate(), | 
| 380 | 0 |     smtpPort(25), | 
| 381 | 0 |     bufferSize(512), | 
| 382 | 0 |     locationInfo(false), | 
| 383 | 0 |     cb(bufferSize), | 
| 384 | 0 |     evaluator(new DefaultEvaluator()) {} | 
| 385 |  |  | 
| 386 |  |   SMTPPriv(spi::TriggeringEventEvaluatorPtr evaluator) : | 
| 387 | 0 |     AppenderSkeletonPrivate(), | 
| 388 | 0 |     smtpPort(25), | 
| 389 | 0 |     bufferSize(512), | 
| 390 | 0 |     locationInfo(false), | 
| 391 | 0 |     cb(bufferSize), | 
| 392 | 0 |     evaluator(evaluator) {} | 
| 393 |  |  | 
| 394 |  |   LogString to; | 
| 395 |  |   LogString cc; | 
| 396 |  |   LogString bcc; | 
| 397 |  |   LogString from; | 
| 398 |  |   LogString subject; | 
| 399 |  |   LogString smtpHost; | 
| 400 |  |   LogString smtpUsername; | 
| 401 |  |   LogString smtpPassword; | 
| 402 |  |   int smtpPort; | 
| 403 |  |   int bufferSize; // 512 | 
| 404 |  |   bool locationInfo; | 
| 405 |  |   helpers::CyclicBuffer cb; | 
| 406 |  |   spi::TriggeringEventEvaluatorPtr evaluator; | 
| 407 |  | }; | 
| 408 |  |  | 
| 409 | 0 | #define _priv static_cast<SMTPPriv*>(m_priv.get()) | 
| 410 |  |  | 
| 411 |  | DefaultEvaluator::DefaultEvaluator() | 
| 412 | 0 | { | 
| 413 | 0 | } Unexecuted instantiation: log4cxx::net::DefaultEvaluator::DefaultEvaluator()Unexecuted instantiation: log4cxx::net::DefaultEvaluator::DefaultEvaluator() | 
| 414 |  |  | 
| 415 |  | bool DefaultEvaluator::isTriggeringEvent(const spi::LoggingEventPtr& event) | 
| 416 | 0 | { | 
| 417 | 0 |   return event->getLevel()->isGreaterOrEqual(Level::getError()); | 
| 418 | 0 | } | 
| 419 |  |  | 
| 420 |  | SMTPAppender::SMTPAppender() | 
| 421 | 0 |   : AppenderSkeleton (std::make_unique<SMTPPriv>()) | 
| 422 | 0 | { | 
| 423 | 0 | } Unexecuted instantiation: log4cxx::net::SMTPAppender::SMTPAppender()Unexecuted instantiation: log4cxx::net::SMTPAppender::SMTPAppender() | 
| 424 |  |  | 
| 425 |  | /** | 
| 426 |  | Use <code>evaluator</code> passed as parameter as the | 
| 427 |  | TriggeringEventEvaluator for this SMTPAppender.  */ | 
| 428 |  | SMTPAppender::SMTPAppender(spi::TriggeringEventEvaluatorPtr evaluator) | 
| 429 | 0 |   : AppenderSkeleton (std::make_unique<SMTPPriv>(evaluator)) | 
| 430 | 0 | { | 
| 431 | 0 | } Unexecuted instantiation: log4cxx::net::SMTPAppender::SMTPAppender(std::__1::shared_ptr<log4cxx::spi::TriggeringEventEvaluator>)Unexecuted instantiation: log4cxx::net::SMTPAppender::SMTPAppender(std::__1::shared_ptr<log4cxx::spi::TriggeringEventEvaluator>) | 
| 432 |  |  | 
| 433 |  | SMTPAppender::~SMTPAppender() | 
| 434 | 0 | { | 
| 435 | 0 |   finalize(); | 
| 436 | 0 | } | 
| 437 |  |  | 
| 438 |  | bool SMTPAppender::requiresLayout() const | 
| 439 | 0 | { | 
| 440 | 0 |   return true; | 
| 441 | 0 | } | 
| 442 |  |  | 
| 443 |  | LogString SMTPAppender::getFrom() const | 
| 444 | 0 | { | 
| 445 | 0 |   return _priv->from; | 
| 446 | 0 | } | 
| 447 |  |  | 
| 448 |  | void SMTPAppender::setFrom(const LogString& newVal) | 
| 449 | 0 | { | 
| 450 | 0 |   _priv->from = newVal; | 
| 451 | 0 | } | 
| 452 |  |  | 
| 453 |  |  | 
| 454 |  | LogString SMTPAppender::getSubject() const | 
| 455 | 0 | { | 
| 456 | 0 |   return _priv->subject; | 
| 457 | 0 | } | 
| 458 |  |  | 
| 459 |  | void SMTPAppender::setSubject(const LogString& newVal) | 
| 460 | 0 | { | 
| 461 | 0 |   _priv->subject = newVal; | 
| 462 | 0 | } | 
| 463 |  |  | 
| 464 |  | LogString SMTPAppender::getSMTPHost() const | 
| 465 | 0 | { | 
| 466 | 0 |   return _priv->smtpHost; | 
| 467 | 0 | } | 
| 468 |  |  | 
| 469 |  | void SMTPAppender::setSMTPHost(const LogString& newVal) | 
| 470 | 0 | { | 
| 471 | 0 |   _priv->smtpHost = newVal; | 
| 472 | 0 | } | 
| 473 |  |  | 
| 474 |  | int SMTPAppender::getSMTPPort() const | 
| 475 | 0 | { | 
| 476 | 0 |   return _priv->smtpPort; | 
| 477 | 0 | } | 
| 478 |  |  | 
| 479 |  | void SMTPAppender::setSMTPPort(int newVal) | 
| 480 | 0 | { | 
| 481 | 0 |   _priv->smtpPort = newVal; | 
| 482 | 0 | } | 
| 483 |  |  | 
| 484 |  | bool SMTPAppender::getLocationInfo() const | 
| 485 | 0 | { | 
| 486 | 0 |   return _priv->locationInfo; | 
| 487 | 0 | } | 
| 488 |  |  | 
| 489 |  | void SMTPAppender::setLocationInfo(bool newVal) | 
| 490 | 0 | { | 
| 491 | 0 |   _priv->locationInfo = newVal; | 
| 492 | 0 | } | 
| 493 |  |  | 
| 494 |  | LogString SMTPAppender::getSMTPUsername() const | 
| 495 | 0 | { | 
| 496 | 0 |   return _priv->smtpUsername; | 
| 497 | 0 | } | 
| 498 |  |  | 
| 499 |  | void SMTPAppender::setSMTPUsername(const LogString& newVal) | 
| 500 | 0 | { | 
| 501 | 0 |   _priv->smtpUsername = newVal; | 
| 502 | 0 | } | 
| 503 |  |  | 
| 504 |  | LogString SMTPAppender::getSMTPPassword() const | 
| 505 | 0 | { | 
| 506 | 0 |   return _priv->smtpPassword; | 
| 507 | 0 | } | 
| 508 |  |  | 
| 509 |  | void SMTPAppender::setSMTPPassword(const LogString& newVal) | 
| 510 | 0 | { | 
| 511 | 0 |   _priv->smtpPassword = newVal; | 
| 512 | 0 | } | 
| 513 |  |  | 
| 514 |  |  | 
| 515 |  |  | 
| 516 |  |  | 
| 517 |  |  | 
| 518 |  | void SMTPAppender::setOption(const LogString& option, | 
| 519 |  |   const LogString& value) | 
| 520 | 0 | { | 
| 521 | 0 |   if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFERSIZE"), LOG4CXX_STR("buffersize"))) | 
| 522 | 0 |   { | 
| 523 | 0 |     setBufferSize(OptionConverter::toInt(value, 512)); | 
| 524 | 0 |   } | 
| 525 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("EVALUATORCLASS"), LOG4CXX_STR("evaluatorclass"))) | 
| 526 | 0 |   { | 
| 527 | 0 |     setEvaluatorClass(value); | 
| 528 | 0 |   } | 
| 529 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FROM"), LOG4CXX_STR("from"))) | 
| 530 | 0 |   { | 
| 531 | 0 |     setFrom(value); | 
| 532 | 0 |   } | 
| 533 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPHOST"), LOG4CXX_STR("smtphost"))) | 
| 534 | 0 |   { | 
| 535 | 0 |     setSMTPHost(value); | 
| 536 | 0 |   } | 
| 537 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPUSERNAME"), LOG4CXX_STR("smtpusername"))) | 
| 538 | 0 |   { | 
| 539 | 0 |     setSMTPUsername(value); | 
| 540 | 0 |   } | 
| 541 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPPASSWORD"), LOG4CXX_STR("smtppassword"))) | 
| 542 | 0 |   { | 
| 543 | 0 |     setSMTPPassword(value); | 
| 544 | 0 |   } | 
| 545 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SUBJECT"), LOG4CXX_STR("subject"))) | 
| 546 | 0 |   { | 
| 547 | 0 |     setSubject(value); | 
| 548 | 0 |   } | 
| 549 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("TO"), LOG4CXX_STR("to"))) | 
| 550 | 0 |   { | 
| 551 | 0 |     setTo(value); | 
| 552 | 0 |   } | 
| 553 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("CC"), LOG4CXX_STR("cc"))) | 
| 554 | 0 |   { | 
| 555 | 0 |     setCc(value); | 
| 556 | 0 |   } | 
| 557 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BCC"), LOG4CXX_STR("bcc"))) | 
| 558 | 0 |   { | 
| 559 | 0 |     setBcc(value); | 
| 560 | 0 |   } | 
| 561 | 0 |   else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SMTPPORT"), LOG4CXX_STR("smtpport"))) | 
| 562 | 0 |   { | 
| 563 | 0 |     setSMTPPort(OptionConverter::toInt(value, 25)); | 
| 564 | 0 |   } | 
| 565 | 0 |   else | 
| 566 | 0 |   { | 
| 567 | 0 |     AppenderSkeleton::setOption(option, value); | 
| 568 | 0 |   } | 
| 569 | 0 | } | 
| 570 |  |  | 
| 571 |  |  | 
| 572 |  | bool SMTPAppender::asciiCheck(const LogString& value, const LogString& field) | 
| 573 | 0 | { | 
| 574 | 0 |   for (unsigned int item : value) | 
| 575 | 0 |   { | 
| 576 | 0 |     if (0x7F < item) | 
| 577 | 0 |     { | 
| 578 | 0 |       LogLog::warn(field + LOG4CXX_STR(" contains non-ASCII character")); | 
| 579 | 0 |       return false; | 
| 580 | 0 |     } | 
| 581 | 0 |   } | 
| 582 |  |  | 
| 583 | 0 |   return true; | 
| 584 | 0 | } | 
| 585 |  |  | 
| 586 |  | /** | 
| 587 |  | Activate the specified options, such as the smtp host, the | 
| 588 |  | recipient, from, etc. */ | 
| 589 |  | void SMTPAppender::activateOptions(Pool& p) | 
| 590 | 0 | { | 
| 591 | 0 |   bool activate = true; | 
| 592 |  | 
 | 
| 593 | 0 |   if (_priv->layout == 0) | 
| 594 | 0 |   { | 
| 595 | 0 |     _priv->errorHandler->error(LOG4CXX_STR("No layout set for appender named [") + _priv->name + LOG4CXX_STR("].")); | 
| 596 | 0 |     activate = false; | 
| 597 | 0 |   } | 
| 598 |  | 
 | 
| 599 | 0 |   if (_priv->evaluator == 0) | 
| 600 | 0 |   { | 
| 601 | 0 |     _priv->errorHandler->error(LOG4CXX_STR("No TriggeringEventEvaluator is set for appender [") + | 
| 602 | 0 |       _priv->name + LOG4CXX_STR("].")); | 
| 603 | 0 |     activate = false; | 
| 604 | 0 |   } | 
| 605 |  | 
 | 
| 606 | 0 |   if (_priv->smtpHost.empty()) | 
| 607 | 0 |   { | 
| 608 | 0 |     _priv->errorHandler->error(LOG4CXX_STR("No smtpHost is set for appender [") + | 
| 609 | 0 |       _priv->name + LOG4CXX_STR("].")); | 
| 610 | 0 |     activate = false; | 
| 611 | 0 |   } | 
| 612 |  | 
 | 
| 613 | 0 |   if (_priv->to.empty() && _priv->cc.empty() && _priv->bcc.empty()) | 
| 614 | 0 |   { | 
| 615 | 0 |     _priv->errorHandler->error(LOG4CXX_STR("No recipient address is set for appender [") + | 
| 616 | 0 |       _priv->name + LOG4CXX_STR("].")); | 
| 617 | 0 |     activate = false; | 
| 618 | 0 |   } | 
| 619 |  | 
 | 
| 620 | 0 |   activate &= asciiCheck(_priv->to, LOG4CXX_STR("to")); | 
| 621 | 0 |   activate &= asciiCheck(_priv->cc, LOG4CXX_STR("cc")); | 
| 622 | 0 |   activate &= asciiCheck(_priv->bcc, LOG4CXX_STR("bcc")); | 
| 623 | 0 |   activate &= asciiCheck(_priv->from, LOG4CXX_STR("from")); | 
| 624 |  | 
 | 
| 625 | 0 | #if !LOG4CXX_HAVE_LIBESMTP | 
| 626 | 0 |   _priv->errorHandler->error(LOG4CXX_STR("log4cxx built without SMTP support.")); | 
| 627 | 0 |   activate = false; | 
| 628 | 0 | #endif | 
| 629 |  | 
 | 
| 630 | 0 |   if (activate) | 
| 631 | 0 |   { | 
| 632 | 0 |     AppenderSkeleton::activateOptions(p); | 
| 633 | 0 |   } | 
| 634 | 0 | } | 
| 635 |  |  | 
| 636 |  | /** | 
| 637 |  | Perform SMTPAppender specific appending actions, mainly adding | 
| 638 |  | the event to a cyclic buffer and checking if the event triggers | 
| 639 |  | an e-mail to be sent. */ | 
| 640 |  | void SMTPAppender::append(const spi::LoggingEventPtr& event, Pool& p) | 
| 641 | 0 | { | 
| 642 | 0 |   if (!checkEntryConditions()) | 
| 643 | 0 |   { | 
| 644 | 0 |     return; | 
| 645 | 0 |   } | 
| 646 |  |  | 
| 647 |  |   // Get a copy of this thread's diagnostic context | 
| 648 | 0 |   event->LoadDC(); | 
| 649 |  | 
 | 
| 650 | 0 |   _priv->cb.add(event); | 
| 651 |  | 
 | 
| 652 | 0 |   if (_priv->evaluator->isTriggeringEvent(event)) | 
| 653 | 0 |   { | 
| 654 | 0 |     sendBuffer(p); | 
| 655 | 0 |   } | 
| 656 | 0 | } | 
| 657 |  |  | 
| 658 |  | /** | 
| 659 |  | This method determines if there is a sense in attempting to append. | 
| 660 |  | <p>It checks whether there is a set output target and also if | 
| 661 |  | there is a set layout. If these checks fail, then the boolean | 
| 662 |  | value <code>false</code> is returned. */ | 
| 663 |  | bool SMTPAppender::checkEntryConditions() | 
| 664 | 0 | { | 
| 665 |  | #if LOG4CXX_HAVE_LIBESMTP | 
| 666 |  |  | 
| 667 |  |   if ((_priv->to.empty() && _priv->cc.empty() && _priv->bcc.empty()) || _priv->from.empty() || _priv->smtpHost.empty()) | 
| 668 |  |   { | 
| 669 |  |     _priv->errorHandler->error(LOG4CXX_STR("Message not configured.")); | 
| 670 |  |     return false; | 
| 671 |  |   } | 
| 672 |  |  | 
| 673 |  |   if (_priv->evaluator == 0) | 
| 674 |  |   { | 
| 675 |  |     _priv->errorHandler->error(LOG4CXX_STR("No TriggeringEventEvaluator is set for appender [") + | 
| 676 |  |       _priv->name + LOG4CXX_STR("].")); | 
| 677 |  |     return false; | 
| 678 |  |   } | 
| 679 |  |  | 
| 680 |  |  | 
| 681 |  |   if (_priv->layout == 0) | 
| 682 |  |   { | 
| 683 |  |     _priv->errorHandler->error(LOG4CXX_STR("No layout set for appender named [") + _priv->name + LOG4CXX_STR("].")); | 
| 684 |  |     return false; | 
| 685 |  |   } | 
| 686 |  |  | 
| 687 |  |   return true; | 
| 688 |  | #else | 
| 689 | 0 |   return false; | 
| 690 | 0 | #endif | 
| 691 | 0 | } | 
| 692 |  |  | 
| 693 |  |  | 
| 694 |  |  | 
| 695 |  | void SMTPAppender::close() | 
| 696 | 0 | { | 
| 697 | 0 |   _priv->closed = true; | 
| 698 | 0 | } | 
| 699 |  |  | 
| 700 |  | LogString SMTPAppender::getTo() const | 
| 701 | 0 | { | 
| 702 | 0 |   return _priv->to; | 
| 703 | 0 | } | 
| 704 |  |  | 
| 705 |  | void SMTPAppender::setTo(const LogString& addressStr) | 
| 706 | 0 | { | 
| 707 | 0 |   _priv->to = addressStr; | 
| 708 | 0 | } | 
| 709 |  |  | 
| 710 |  | LogString SMTPAppender::getCc() const | 
| 711 | 0 | { | 
| 712 | 0 |   return _priv->cc; | 
| 713 | 0 | } | 
| 714 |  |  | 
| 715 |  | void SMTPAppender::setCc(const LogString& addressStr) | 
| 716 | 0 | { | 
| 717 | 0 |   _priv->cc = addressStr; | 
| 718 | 0 | } | 
| 719 |  |  | 
| 720 |  | LogString SMTPAppender::getBcc() const | 
| 721 | 0 | { | 
| 722 | 0 |   return _priv->bcc; | 
| 723 | 0 | } | 
| 724 |  |  | 
| 725 |  | void SMTPAppender::setBcc(const LogString& addressStr) | 
| 726 | 0 | { | 
| 727 | 0 |   _priv->bcc = addressStr; | 
| 728 | 0 | } | 
| 729 |  |  | 
| 730 |  | /** | 
| 731 |  | Send the contents of the cyclic buffer as an e-mail message. | 
| 732 |  | */ | 
| 733 |  | void SMTPAppender::sendBuffer(Pool& p) | 
| 734 | 0 | { | 
| 735 |  | #if LOG4CXX_HAVE_LIBESMTP | 
| 736 |  |  | 
| 737 |  |   // Note: this code already owns the monitor for this | 
| 738 |  |   // appender. This frees us from needing to synchronize on 'cb'. | 
| 739 |  |   try | 
| 740 |  |   { | 
| 741 |  |     LogString sbuf; | 
| 742 |  |     _priv->layout->appendHeader(sbuf, p); | 
| 743 |  |  | 
| 744 |  |     int len = _priv->cb.length(); | 
| 745 |  |  | 
| 746 |  |     for (int i = 0; i < len; i++) | 
| 747 |  |     { | 
| 748 |  |       LoggingEventPtr event = _priv->cb.get(); | 
| 749 |  |       _priv->layout->format(sbuf, event, p); | 
| 750 |  |     } | 
| 751 |  |  | 
| 752 |  |     _priv->layout->appendFooter(sbuf, p); | 
| 753 |  |  | 
| 754 |  |     SMTPSession session(_priv->smtpHost, _priv->smtpPort, _priv->smtpUsername, _priv->smtpPassword, p); | 
| 755 |  |  | 
| 756 |  |     SMTPMessage message(session, _priv->from, _priv->to, _priv->cc, | 
| 757 |  |       _priv->bcc, _priv->subject, sbuf, p); | 
| 758 |  |  | 
| 759 |  |     session.send(p); | 
| 760 |  |  | 
| 761 |  |   } | 
| 762 |  |   catch (std::exception& e) | 
| 763 |  |   { | 
| 764 |  |     _priv->errorHandler->error(LOG4CXX_STR("Error occured while sending e-mail to [") + _priv->smtpHost + LOG4CXX_STR("]."), e, 0); | 
| 765 |  |   } | 
| 766 |  |  | 
| 767 |  | #endif | 
| 768 | 0 | } | 
| 769 |  |  | 
| 770 |  | /** | 
| 771 |  | Returns value of the <b>EvaluatorClass</b> option. | 
| 772 |  | */ | 
| 773 |  | LogString SMTPAppender::getEvaluatorClass() | 
| 774 | 0 | { | 
| 775 | 0 |   return _priv->evaluator == 0 ? LogString() : _priv->evaluator->getClass().getName(); | 
| 776 | 0 | } | 
| 777 |  |  | 
| 778 |  | LOG4CXX_NS::spi::TriggeringEventEvaluatorPtr SMTPAppender::getEvaluator() const | 
| 779 | 0 | { | 
| 780 | 0 |   return _priv->evaluator; | 
| 781 | 0 | } | 
| 782 |  |  | 
| 783 |  | void SMTPAppender::setEvaluator(LOG4CXX_NS::spi::TriggeringEventEvaluatorPtr& trigger) | 
| 784 | 0 | { | 
| 785 | 0 |   _priv->evaluator = trigger; | 
| 786 | 0 | } | 
| 787 |  |  | 
| 788 |  | /** | 
| 789 |  | The <b>BufferSize</b> option takes a positive integer | 
| 790 |  | representing the maximum number of logging events to collect in a | 
| 791 |  | cyclic buffer. When the <code>BufferSize</code> is reached, | 
| 792 |  | oldest events are deleted as new events are added to the | 
| 793 |  | buffer. By default the size of the cyclic buffer is 512 events. | 
| 794 |  | */ | 
| 795 |  | void SMTPAppender::setBufferSize(int sz) | 
| 796 | 0 | { | 
| 797 | 0 |   _priv->bufferSize = sz; | 
| 798 | 0 |   _priv->cb.resize(sz); | 
| 799 | 0 | } | 
| 800 |  |  | 
| 801 |  | /** | 
| 802 |  | The <b>EvaluatorClass</b> option takes a string value | 
| 803 |  | representing the name of the class implementing the {@link | 
| 804 |  | TriggeringEventEvaluator} interface. A corresponding object will | 
| 805 |  | be instantiated and assigned as the triggering event evaluator | 
| 806 |  | for the SMTPAppender. | 
| 807 |  | */ | 
| 808 |  | void SMTPAppender::setEvaluatorClass(const LogString& value) | 
| 809 | 0 | { | 
| 810 | 0 |   ObjectPtr obj = ObjectPtr(Loader::loadClass(value).newInstance()); | 
| 811 | 0 |   _priv->evaluator = LOG4CXX_NS::cast<TriggeringEventEvaluator>(obj); | 
| 812 | 0 | } | 
| 813 |  |  | 
| 814 |  | int SMTPAppender::getBufferSize() const | 
| 815 | 0 | { | 
| 816 | 0 |   return _priv->bufferSize; | 
| 817 | 0 | } |