Coverage Report

Created: 2025-07-01 06:08

/src/logging-log4cxx/src/main/cpp/smtpappender.cpp
Line
Count
Source (jump to first uncovered line)
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
}