Coverage Report

Created: 2026-05-30 06:57

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