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