summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-08-04 14:55:02 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2008-08-04 14:55:02 +0200
commit103ccc18016d80b9aef3774521770b86f8672184 (patch)
treea6bb7a1ab65cc92f7bdad30cb171065e6d52de8d
parentcaede8f6216a27d06c755698fb0056c32e60bcdb (diff)
downloadrsyslog-103ccc18016d80b9aef3774521770b86f8672184.tar.gz
rsyslog-103ccc18016d80b9aef3774521770b86f8672184.tar.xz
rsyslog-103ccc18016d80b9aef3774521770b86f8672184.zip
enhanced ommail to support multiple email recipients.
This is done by specifying $ActionMailTo multiple times. Note that this introduces a small incompatibility to previous config file syntax: the recipient list is now reset for each action (we honestly believe that will not cause any problem - apologies if it does).
-rw-r--r--ChangeLog5
-rw-r--r--doc/ommail.html23
-rw-r--r--plugins/ommail/ommail.c111
3 files changed, 118 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 44b72632..eac07f36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,11 @@ Version 3.21.2 [DEVEL] (rgerhards), 2008-08-??
override the hostname being used on a local unix socket. This is useful
for differentiating "hosts" running in several jails. Feature was
suggested by David Darville, thanks for the suggestion.
+- enhanced ommail to support multiple email recipients. This is done by
+ specifying $ActionMailTo multiple times. Note that this introduces a
+ small incompatibility to previous config file syntax: the recipient
+ list is now reset for each action (we honestly believe that will
+ not cause any problem - apologies if it does).
---------------------------------------------------------------------------
Version 3.21.1 [DEVEL] (rgerhards), 2008-07-30
- bugfix: no error was reported if the target of a $IncludeConfig
diff --git a/doc/ommail.html b/doc/ommail.html
index 62ded6d0..c18cf3f8 100644
--- a/doc/ommail.html
+++ b/doc/ommail.html
@@ -50,7 +50,10 @@ standard SMTP port.</li>
<li><span style="font-weight: bold;">$ActionMailFrom</span><br>
The email address used as the senders address. There is no default.</li>
<li><span style="font-weight: bold;">$ActionMailTo</span><br>
-The recipients email address. There is no default.</li>
+The recipient email addresses. There is no default. To specify multiple
+recpients, repeat this directive as often as needed. Note: <b>This directive
+must be specified for each new action and is automatically reset.</b>
+[Multiple recipients are supported for 3.21.2 and above.]</li>
<li><span style="font-weight: bold;">$ActionMailSubject</span><br>
The name of the <span style="font-weight: bold;">template</span>
to be used as the mail subject. If this is not specified, a more or
@@ -112,14 +115,28 @@ $ActionExecOnlyOnceEveryInterval 21600
# the if ... then ... mailBody mus be on one line!
if $msg contains 'hard disk fatal failure' then :ommail:;mailBody
</textarea>
+<p>The sample below is the same, but sends mail to two recipients:</p>
+<textarea rows="15" cols="80">$ModLoad ommail
+$ActionMailSMTPServer mail.example.net
+$ActionMailFrom rsyslog@example.net
+$ActionMailTo operator@example.net
+$ActionMailTo admin@example.net
+$template mailSubject,"disk problem on %hostname%"
+$template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'"
+$ActionMailSubject mailSubject
+# make sure we receive a mail only once in six
+# hours (21,600 seconds ;))
+$ActionExecOnlyOnceEveryInterval 21600
+# the if ... then ... mailBody mus be on one line!
+if $msg contains 'hard disk fatal failure' then :ommail:;mailBody
+</textarea>
<p>A more advanced example plus a discussion on using the email feature
inside a reliable system can be found in Rainer's blogpost
"<a style="font-style: italic;" href="http://rgerhards.blogspot.com/2008/04/why-is-native-email-capability.html">Why
is native email capability an advantage for a syslogd?</a>"
<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
-<p><font size="2">This documentation is part of the
-<a href="http://www.rsyslog.com/">rsyslog</a>
+<p><font size="2">This documentation is part of the <a href="http://www.rsyslog.com/">rsyslog</a>
project.<br>
Copyright &copy; 2008 by <a href="http://www.gerhards.net/rainer">Rainer
Gerhards</a> and
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 4bbb844a..39c2d21f 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -60,10 +60,18 @@ DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
+/* we add a little support for multiple recipients. We do this via a
+ * singly-linked list, enqueued from the top. -- rgerhards, 2008-08-04
+ */
+typedef struct toRcpt_s toRcpt_t;
+struct toRcpt_s {
+ uchar *pszTo;
+ toRcpt_t *pNext;
+};
+static toRcpt_t *lstRcpt = NULL;
static uchar *pszSrv = NULL;
static uchar *pszSrvPort = NULL;
static uchar *pszFrom = NULL;
-static uchar *pszTo = NULL;
static uchar *pszSubject = NULL;
static int bEnableBody = 1; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
@@ -76,7 +84,7 @@ typedef struct _instanceData {
uchar *pszSrv;
uchar *pszSrvPort;
uchar *pszFrom;
- uchar *pszTo;
+ toRcpt_t *lstRcpt;
char RcvBuf[1024]; /* buffer for receiving server responses */
size_t lenRcvBuf;
size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */
@@ -85,6 +93,80 @@ typedef struct _instanceData {
} md; /* mode-specific data */
} instanceData;
+/* forward definitions (as few as possible) */
+static rsRetVal Send(int sock, char *msg, size_t len);
+static rsRetVal readResponse(instanceData *pData, int *piState, int iExpected);
+
+
+/* helpers for handling the recipient lists */
+
+/* destroy a complete recipient list */
+static void lstRcptDestruct(toRcpt_t *pRoot)
+{
+ toRcpt_t *pDel;
+
+ while(pRoot != NULL) {
+ pDel = pRoot;
+ pRoot = pRoot->pNext;
+ /* ready to disalloc */
+ free(pDel->pszTo);
+ free(pDel);
+ }
+}
+
+/* This function is called when a new recipient email address is to be
+ * added. rgerhards, 2008-08-04
+ */
+static rsRetVal
+addRcpt(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+ toRcpt_t *pNew = NULL;
+
+ CHKmalloc(pNew = calloc(1, sizeof(toRcpt_t)));
+
+ pNew->pszTo = pNewVal;
+ pNew->pNext = lstRcpt;
+ lstRcpt = pNew;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pNew != NULL)
+ free(pNew);
+ free(pNewVal); /* in any case, this is no longer needed */
+ }
+
+ RETiRet;
+}
+
+
+/* output the recipient list to the mail server
+ * iStatusToCheck < 0 means no checking should happen
+ */
+static rsRetVal
+WriteRcpts(instanceData *pData, uchar *pszOp, size_t lenOp, int iStatusToCheck)
+{
+ toRcpt_t *pRcpt;
+ int iState;
+ DEFiRet;
+
+ assert(pData != NULL);
+ assert(pszOp != NULL);
+ assert(lenOp != 0);
+
+ for(pRcpt = pData->md.smtp.lstRcpt ; pRcpt != NULL ; pRcpt = pRcpt->pNext) {
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pszOp, lenOp));
+ CHKiRet(Send(pData->md.smtp.sock, ": <", sizeof(": <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pRcpt->pszTo, strlen((char*)pRcpt->pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ if(iStatusToCheck >= 0)
+ CHKiRet(readResponse(pData, &iState, iStatusToCheck));
+ }
+
+finalize_it:
+ RETiRet;
+}
+/* end helpers for handling the recipient lists */
BEGINcreateInstance
CODESTARTcreateInstance
@@ -107,8 +189,7 @@ CODESTARTfreeInstance
free(pData->md.smtp.pszSrvPort);
if(pData->md.smtp.pszFrom != NULL)
free(pData->md.smtp.pszFrom);
- if(pData->md.smtp.pszTo != NULL)
- free(pData->md.smtp.pszTo);
+ lstRcptDestruct(pData->md.smtp.lstRcpt);
}
ENDfreeInstance
@@ -426,10 +507,7 @@ sendSMTP(instanceData *pData, uchar *body, uchar *subject)
CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
CHKiRet(readResponse(pData, &iState, 250));
- CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: <", sizeof("RCPT TO: <") - 1));
- CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
- CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
- CHKiRet(readResponse(pData, &iState, 250));
+ CHKiRet(WriteRcpts(pData, (uchar*)"RCPT TO", sizeof("RCPT TO") - 1, 250));
CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1));
CHKiRet(readResponse(pData, &iState, 354));
@@ -443,9 +521,7 @@ sendSMTP(instanceData *pData, uchar *body, uchar *subject)
CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszFrom, strlen((char*)pData->md.smtp.pszFrom)));
CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
- CHKiRet(Send(pData->md.smtp.sock, "To: <", sizeof("To: <") - 1));
- CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
- CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ CHKiRet(WriteRcpts(pData, (uchar*)"To", sizeof("To") - 1, -1));
CHKiRet(Send(pData->md.smtp.sock, "Subject: ", sizeof("Subject: ") - 1));
CHKiRet(Send(pData->md.smtp.sock, (char*)subject, strlen((char*)subject)));
@@ -531,13 +607,14 @@ CODESTARTparseSelectorAct
errmsg.LogError(0, RS_RET_MAIL_NO_FROM, "no sender address given - specify $ActionMailFrom");
ABORT_FINALIZE(RS_RET_MAIL_NO_FROM);
}
- if(pszTo == NULL) {
+ if(lstRcpt == NULL) {
errmsg.LogError(0, RS_RET_MAIL_NO_TO, "no recipient address given - specify $ActionMailTo");
ABORT_FINALIZE(RS_RET_MAIL_NO_TO);
}
pData->md.smtp.pszFrom = (uchar*) strdup((char*)pszFrom);
- pData->md.smtp.pszTo = (uchar*) strdup((char*)pszTo);
+ pData->md.smtp.lstRcpt = lstRcpt; /* we "hand over" this memory */
+ lstRcpt = NULL; /* note: this is different from pre-3.21.2 versions! */
if(pszSubject == NULL) {
/* if no subject is configured, we need just one template string */
@@ -576,10 +653,8 @@ static rsRetVal freeConfigVariables(void)
free(pszFrom);
pszFrom = NULL;
}
- if(pszTo != NULL) {
- free(pszTo);
- pszTo = NULL;
- }
+ lstRcptDestruct(lstRcpt);
+ lstRcpt = NULL;
RETiRet;
}
@@ -624,7 +699,7 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpserver", 0, eCmdHdlrGetWord, NULL, &pszSrv, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpport", 0, eCmdHdlrGetWord, NULL, &pszSrvPort, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailfrom", 0, eCmdHdlrGetWord, NULL, &pszFrom, STD_LOADABLE_MODULE_ID));
- CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailto", 0, eCmdHdlrGetWord, NULL, &pszTo, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailto", 0, eCmdHdlrGetWord, addRcpt, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsubject", 0, eCmdHdlrGetWord, NULL, &pszSubject, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailenablebody", 0, eCmdHdlrBinary, NULL, &bEnableBody, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));