2
* The msg object. Implementation of all msg-related functions
4
* File begun on 2007-07-13 by RGerhards (extracted from syslogd.c)
5
* This file is under development and has not yet arrived at being fully
6
* self-contained and a real object. So far, it is mostly an excerpt
7
* of the "old" message code without any modifications. However, it
8
* helps to have things at the right place one we go to the meat of it.
10
* Copyright 2007 Rainer Gerhards and Adiscon GmbH.
12
* This program is free software; you can redistribute it and/or
13
* modify it under the terms of the GNU General Public License
14
* as published by the Free Software Foundation; either version 2
15
* of the License, or (at your option) any later version.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
* A copy of the GPL can be found in the file "COPYING" in this distribution.
34
#include <sys/syslog.h>
43
/* The following functions will support advanced output module
44
* multithreading, once this is implemented. Currently, we
45
* include them as hooks only. The idea is that we need to guard
46
* some msg objects data fields against concurrent access if
47
* we run on multiple threads. Please note that in any case this
48
* is not necessary for calls from INPUT modules, because they
49
* construct the message object and do this serially. Only when
50
* the message is in the processing queue, multiple threads may
51
* access a single object. Consequently, there are no guard functions
52
* for "set" methods, as these are called during input. Only "get"
53
* functions that modify important structures have them.
54
* rgerhards, 2007-07-20
57
#define MsgUnlock(pMsg)
60
/* "Constructor" for a msg "object". Returns a pointer to
61
* the new object or NULL if no such object could be allocated.
62
* An object constructed via this function should only be destroyed
63
* via "MsgDestruct()".
65
msg_t* MsgConstruct(void)
69
if((pM = calloc(1, sizeof(msg_t))) != NULL)
70
{ /* initialize members that are non-zero */
75
getCurrTime(&(pM->tRcvdAt));
78
/* DEV debugging only! dbgprintf("MsgConstruct\t0x%x, ref 1\n", (int)pM);*/
84
/* Destructor for a msg "object". Must be called to dispose
87
void MsgDestruct(msg_t * pM)
90
/* DEV Debugging only ! dbgprintf("MsgDestruct\t0x%x, Ref now: %d\n", (int)pM, pM->iRefCount - 1); */
91
if(--pM->iRefCount == 0)
93
/* DEV Debugging Only! dbgprintf("MsgDestruct\t0x%x, RefCount now 0, doing DESTROY\n", (int)pM); */
94
if(pM->pszUxTradMsg != NULL)
95
free(pM->pszUxTradMsg);
96
if(pM->pszRawMsg != NULL)
98
if(pM->pszTAG != NULL)
100
if(pM->pszHOSTNAME != NULL)
101
free(pM->pszHOSTNAME);
102
if(pM->pszRcvFrom != NULL)
103
free(pM->pszRcvFrom);
104
if(pM->pszMSG != NULL)
106
if(pM->pszFacility != NULL)
107
free(pM->pszFacility);
108
if(pM->pszFacilityStr != NULL)
109
free(pM->pszFacilityStr);
110
if(pM->pszSeverity != NULL)
111
free(pM->pszSeverity);
112
if(pM->pszSeverityStr != NULL)
113
free(pM->pszSeverityStr);
114
if(pM->pszRcvdAt3164 != NULL)
115
free(pM->pszRcvdAt3164);
116
if(pM->pszRcvdAt3339 != NULL)
117
free(pM->pszRcvdAt3339);
118
if(pM->pszRcvdAt_MySQL != NULL)
119
free(pM->pszRcvdAt_MySQL);
120
if(pM->pszTIMESTAMP3164 != NULL)
121
free(pM->pszTIMESTAMP3164);
122
if(pM->pszTIMESTAMP3339 != NULL)
123
free(pM->pszTIMESTAMP3339);
124
if(pM->pszTIMESTAMP_MySQL != NULL)
125
free(pM->pszTIMESTAMP_MySQL);
126
if(pM->pszPRI != NULL)
128
if(pM->pCSProgName != NULL)
129
rsCStrDestruct(pM->pCSProgName);
130
if(pM->pCSStrucData != NULL)
131
rsCStrDestruct(pM->pCSStrucData);
132
if(pM->pCSAPPNAME != NULL)
133
rsCStrDestruct(pM->pCSAPPNAME);
134
if(pM->pCSPROCID != NULL)
135
rsCStrDestruct(pM->pCSPROCID);
136
if(pM->pCSMSGID != NULL)
137
rsCStrDestruct(pM->pCSMSGID);
143
/* The macros below are used in MsgDup(). I use macros
144
* to keep the fuction code somewhat more readyble. It is my
145
* replacement for inline functions in CPP
147
#define tmpCOPYSZ(name) \
148
if(pOld->psz##name != NULL) { \
149
if((pNew->psz##name = srUtilStrDup(pOld->psz##name, pOld->iLen##name)) == NULL) {\
153
pNew->iLen##name = pOld->iLen##name;\
156
/* copy the CStr objects.
157
* if the old value is NULL, we do not need to do anything because we
158
* initialized the new value to NULL via calloc().
160
#define tmpCOPYCSTR(name) \
161
if(pOld->pCS##name != NULL) {\
162
if(rsCStrConstructFromCStr(&(pNew->pCS##name), pOld->pCS##name) != RS_RET_OK) {\
167
/* Constructs a message object by duplicating another one.
168
* Returns NULL if duplication failed. We do not need to lock the
169
* message object here, because a fully-created msg object is never
170
* allowed to be manipulated. For this, MsgDup() must be used, so MsgDup()
171
* can never run into a situation where the message object is being
172
* modified while its content is copied - it's forbidden by definition.
173
* rgerhards, 2007-07-10
175
msg_t* MsgDup(msg_t* pOld)
179
assert(pOld != NULL);
181
if((pNew = (msg_t*) calloc(1, sizeof(msg_t))) == NULL) {
182
glblHadMemShortage = 1;
186
/* now copy the message properties */
188
pNew->iSyslogVers = pOld->iSyslogVers;
189
pNew->bParseHOSTNAME = pOld->bParseHOSTNAME;
190
pNew->iSeverity = pOld->iSeverity;
191
pNew->iFacility = pOld->iFacility;
192
pNew->bParseHOSTNAME = pOld->bParseHOSTNAME;
193
pNew->msgFlags = pOld->msgFlags;
194
pNew->iProtocolVersion = pOld->iProtocolVersion;
195
memcpy(&pNew->tRcvdAt, &pOld->tRcvdAt, sizeof(struct syslogTime));
196
memcpy(&pNew->tTIMESTAMP, &pOld->tTIMESTAMP, sizeof(struct syslogTime));
198
tmpCOPYSZ(SeverityStr);
200
tmpCOPYSZ(FacilityStr);
204
tmpCOPYSZ(UxTradMsg);
209
tmpCOPYCSTR(ProgName);
210
tmpCOPYCSTR(StrucData);
211
tmpCOPYCSTR(APPNAME);
215
/* we do not copy all other cache properties, as we do not even know
216
* if they are needed once again. So we let them re-create if needed.
225
/* Increment reference count - see description of the "msg"
226
* structure for details. As a convenience to developers,
227
* this method returns the msg pointer that is passed to it.
228
* It is recommended that it is called as follows:
230
* pSecondMsgPointer = MsgAddRef(pOrgMsgPointer);
232
msg_t *MsgAddRef(msg_t *pM)
238
/* DEV debugging only! dbgprintf("MsgAddRef\t0x%x done, Ref now: %d\n", (int)pM, pM->iRefCount);*/
243
/* This functions tries to aquire the PROCID from TAG. Its primary use is
244
* when a legacy syslog message has been received and should be forwarded as
245
* syslog-protocol (or the PROCID is requested for any other reason).
246
* In legacy syslog, the PROCID is considered to be the character sequence
247
* between the first [ and the first ]. This usually are digits only, but we
248
* do not check that. However, if there is no closing ], we do not assume we
249
* can obtain a PROCID. Take in mind that not every legacy syslog message
250
* actually has a PROCID.
251
* rgerhards, 2005-11-24
253
static rsRetVal aquirePROCIDFromTAG(msg_t *pM)
259
if(pM->pCSPROCID != NULL)
260
return RS_RET_OK; /* we are already done ;) */
262
if(getProtocolVersion(pM) != 0)
263
return RS_RET_OK; /* we can only emulate if we have legacy format */
265
/* find first '['... */
267
while((i < pM->iLenTAG) && (pM->pszTAG[i] != '['))
269
if(!(i < pM->iLenTAG))
270
return RS_RET_OK; /* no [, so can not emulate... */
274
/* now obtain the PROCID string... */
275
if((pM->pCSPROCID = rsCStrConstruct()) == NULL)
276
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
277
rsCStrSetAllocIncrement(pM->pCSPROCID, 16);
278
while((i < pM->iLenTAG) && (pM->pszTAG[i] != ']')) {
279
if((iRet = rsCStrAppendChar(pM->pCSPROCID, pM->pszTAG[i])) != RS_RET_OK)
284
if(!(i < pM->iLenTAG)) {
285
/* oops... it looked like we had a PROCID, but now it has
286
* turned out this is not true. In this case, we need to free
287
* the buffer and simply return. Note that this is NOT an error
290
rsCStrDestruct(pM->pCSPROCID);
291
pM->pCSPROCID = NULL;
295
/* OK, finaally we could obtain a PROCID. So let's use it ;) */
296
if((iRet = rsCStrFinish(pM->pCSPROCID)) != RS_RET_OK)
303
/* Parse and set the "programname" for a given MSG object. Programname
304
* is a BSD concept, it is the tag without any instance-specific information.
305
* Precisely, the programname is terminated by either (whichever occurs first):
307
* - nonprintable character
311
* The above definition has been taken from the FreeBSD syslogd sources.
313
* The program name is not parsed by default, because it is infrequently-used.
314
* If it is needed, this function should be called first. It checks if it is
315
* already set and extracts it, if not.
316
* A message object must be provided, else a crash will occur.
317
* rgerhards, 2005-10-19
319
static rsRetVal aquireProgramName(msg_t *pM)
325
if(pM->pCSProgName == NULL) {
326
/* ok, we do not yet have it. So let's parse the TAG
329
if((pM->pCSProgName = rsCStrConstruct()) == NULL)
330
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
331
rsCStrSetAllocIncrement(pM->pCSProgName, 33);
333
; (i < pM->iLenTAG) && isprint((int) pM->pszTAG[i])
334
&& (pM->pszTAG[i] != '\0') && (pM->pszTAG[i] != ':')
335
&& (pM->pszTAG[i] != '[') && (pM->pszTAG[i] != '/')
337
if((iRet = rsCStrAppendChar(pM->pCSProgName, pM->pszTAG[i])) != RS_RET_OK)
340
if((iRet = rsCStrFinish(pM->pCSProgName)) != RS_RET_OK)
347
/* This function moves the HOSTNAME inside the message object to the
348
* TAG. It is a specialised function used to handle the condition when
349
* a message without HOSTNAME is being processed. The missing HOSTNAME
350
* is only detected at a later stage, during TAG processing, so that
351
* we already had set the HOSTNAME property and now need to move it to
352
* the TAG. Of course, we could do this via a couple of get/set methods,
353
* but it is far more efficient to do it via this specialised method.
354
* This is especially important as this can be a very common case, e.g.
355
* when BSD syslog is acting as a sender.
356
* rgerhards, 2005-11-10.
358
void moveHOSTNAMEtoTAG(msg_t *pM)
361
if(pM->pszTAG != NULL)
363
pM->pszTAG = pM->pszHOSTNAME;
364
pM->iLenTAG = pM->iLenHOSTNAME;
365
pM->pszHOSTNAME = NULL;
366
pM->iLenHOSTNAME = 0;
369
/* Access methods - dumb & easy, not a comment for each ;)
371
void setProtocolVersion(msg_t *pM, int iNewVersion)
374
if(iNewVersion != 0 && iNewVersion != 1) {
375
dbgprintf("Tried to set unsupported protocol version %d - changed to 0.\n", iNewVersion);
378
pM->iProtocolVersion = iNewVersion;
381
int getProtocolVersion(msg_t *pM)
384
return(pM->iProtocolVersion);
387
/* note: string is taken from constant pool, do NOT free */
388
char *getProtocolVersionString(msg_t *pM)
391
return(pM->iProtocolVersion ? "1" : "0");
394
int getMSGLen(msg_t *pM)
396
return((pM == NULL) ? 0 : pM->iLenMSG);
400
char *getRawMsg(msg_t *pM)
405
if(pM->pszRawMsg == NULL)
408
return (char*)pM->pszRawMsg;
411
char *getUxTradMsg(msg_t *pM)
416
if(pM->pszUxTradMsg == NULL)
419
return (char*)pM->pszUxTradMsg;
422
char *getMSG(msg_t *pM)
427
if(pM->pszMSG == NULL)
430
return (char*)pM->pszMSG;
434
/* Get PRI value in text form */
435
char *getPRI(msg_t *pM)
441
if(pM->pszPRI == NULL) {
442
/* OK, we need to construct it...
443
* we use a 5 byte buffer - as of
444
* RFC 3164, it can't be longer. Should it
445
* still be, snprintf will truncate...
447
if((pM->pszPRI = malloc(5)) == NULL) return "";
448
pM->iLenPRI = snprintf((char*)pM->pszPRI, 5, "%d",
449
LOG_MAKEPRI(pM->iFacility, pM->iSeverity));
453
return (char*)pM->pszPRI;
457
/* Get PRI value as integer */
458
int getPRIi(msg_t *pM)
461
return (pM->iFacility << 3) + (pM->iSeverity);
465
char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
473
if(pM->pszTIMESTAMP3164 == NULL) {
474
if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
475
glblHadMemShortage = 1;
479
formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
482
return(pM->pszTIMESTAMP3164);
483
case tplFmtMySQLDate:
485
if(pM->pszTIMESTAMP_MySQL == NULL) {
486
if((pM->pszTIMESTAMP_MySQL = malloc(15)) == NULL) {
487
glblHadMemShortage = 1;
491
formatTimestampToMySQL(&pM->tTIMESTAMP, pM->pszTIMESTAMP_MySQL, 15);
494
return(pM->pszTIMESTAMP_MySQL);
495
case tplFmtRFC3164Date:
497
if(pM->pszTIMESTAMP3164 == NULL) {
498
if((pM->pszTIMESTAMP3164 = malloc(16)) == NULL) {
499
glblHadMemShortage = 1;
503
formatTimestamp3164(&pM->tTIMESTAMP, pM->pszTIMESTAMP3164, 16);
506
return(pM->pszTIMESTAMP3164);
507
case tplFmtRFC3339Date:
509
if(pM->pszTIMESTAMP3339 == NULL) {
510
if((pM->pszTIMESTAMP3339 = malloc(33)) == NULL) {
511
glblHadMemShortage = 1;
515
formatTimestamp3339(&pM->tTIMESTAMP, pM->pszTIMESTAMP3339, 33);
518
return(pM->pszTIMESTAMP3339);
520
return "INVALID eFmt OPTION!";
523
char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
531
if(pM->pszRcvdAt3164 == NULL) {
532
if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
533
glblHadMemShortage = 1;
537
formatTimestamp3164(&pM->tRcvdAt, pM->pszRcvdAt3164, 16);
540
return(pM->pszRcvdAt3164);
541
case tplFmtMySQLDate:
543
if(pM->pszRcvdAt_MySQL == NULL) {
544
if((pM->pszRcvdAt_MySQL = malloc(15)) == NULL) {
545
glblHadMemShortage = 1;
549
formatTimestampToMySQL(&pM->tRcvdAt, pM->pszRcvdAt_MySQL, 15);
552
return(pM->pszRcvdAt_MySQL);
553
case tplFmtRFC3164Date:
555
if(pM->pszRcvdAt3164 == NULL) {
556
if((pM->pszRcvdAt3164 = malloc(16)) == NULL) {
557
glblHadMemShortage = 1;
561
formatTimestamp3164(&pM->tRcvdAt, pM->pszRcvdAt3164, 16);
564
return(pM->pszRcvdAt3164);
565
case tplFmtRFC3339Date:
567
if(pM->pszRcvdAt3339 == NULL) {
568
if((pM->pszRcvdAt3339 = malloc(33)) == NULL) {
569
glblHadMemShortage = 1;
573
formatTimestamp3339(&pM->tRcvdAt, pM->pszRcvdAt3339, 33);
576
return(pM->pszRcvdAt3339);
578
return "INVALID eFmt OPTION!";
582
char *getSeverity(msg_t *pM)
588
if(pM->pszSeverity == NULL) {
589
/* we use a 2 byte buffer - can only be one digit */
590
if((pM->pszSeverity = malloc(2)) == NULL) { MsgUnlock() ; return ""; }
592
snprintf((char*)pM->pszSeverity, 2, "%d", pM->iSeverity);
595
return((char*)pM->pszSeverity);
599
char *getSeverityStr(msg_t *pM)
609
if(pM->pszSeverityStr == NULL) {
610
for(c = rs_prioritynames, val = pM->iSeverity; c->c_name; c++)
611
if(c->c_val == val) {
616
/* we use a 2 byte buffer - can only be one digit */
617
if((pM->pszSeverityStr = malloc(2)) == NULL) { MsgUnlock() ; return ""; }
618
pM->iLenSeverityStr =
619
snprintf((char*)pM->pszSeverityStr, 2, "%d", pM->iSeverity);
621
if((pM->pszSeverityStr = (uchar*) strdup(name)) == NULL) { MsgUnlock() ; return ""; }
622
pM->iLenSeverityStr = strlen((char*)name);
626
return((char*)pM->pszSeverityStr);
629
char *getFacility(msg_t *pM)
635
if(pM->pszFacility == NULL) {
636
/* we use a 12 byte buffer - as of
637
* syslog-protocol, facility can go
640
if((pM->pszFacility = malloc(12)) == NULL) { MsgUnlock() ; return ""; }
642
snprintf((char*)pM->pszFacility, 12, "%d", pM->iFacility);
645
return((char*)pM->pszFacility);
648
char *getFacilityStr(msg_t *pM)
658
if(pM->pszFacilityStr == NULL) {
659
for(c = rs_facilitynames, val = pM->iFacility << 3; c->c_name; c++)
660
if(c->c_val == val) {
665
/* we use a 12 byte buffer - as of
666
* syslog-protocol, facility can go
669
if((pM->pszFacilityStr = malloc(12)) == NULL) { MsgUnlock() ; return ""; }
670
pM->iLenFacilityStr =
671
snprintf((char*)pM->pszFacilityStr, 12, "%d", val >> 3);
673
if((pM->pszFacilityStr = (uchar*)strdup(name)) == NULL) { MsgUnlock() ; return ""; }
674
pM->iLenFacilityStr = strlen((char*)name);
678
return((char*)pM->pszFacilityStr);
682
/* rgerhards 2004-11-24: set APP-NAME in msg object
684
rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME)
686
assert(pMsg != NULL);
687
if(pMsg->pCSAPPNAME == NULL) {
688
/* we need to obtain the object first */
689
if((pMsg->pCSAPPNAME = rsCStrConstruct()) == NULL)
690
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
691
rsCStrSetAllocIncrement(pMsg->pCSAPPNAME, 128);
693
/* if we reach this point, we have the object */
694
return rsCStrSetSzStr(pMsg->pCSAPPNAME, (uchar*) pszAPPNAME);
698
/* This function tries to emulate APPNAME if it is not present. Its
699
* main use is when we have received a log record via legacy syslog and
700
* now would like to send out the same one via syslog-protocol.
702
static void tryEmulateAPPNAME(msg_t *pM)
705
if(pM->pCSAPPNAME != NULL)
706
return; /* we are already done */
708
if(getProtocolVersion(pM) == 0) {
709
/* only then it makes sense to emulate */
710
MsgSetAPPNAME(pM, getProgramName(pM));
715
/* rgerhards, 2005-11-24
717
int getAPPNAMELen(msg_t *pM)
721
if(pM->pCSAPPNAME == NULL)
722
tryEmulateAPPNAME(pM);
724
return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME);
728
/* rgerhards, 2005-11-24
730
char *getAPPNAME(msg_t *pM)
734
if(pM->pCSAPPNAME == NULL)
735
tryEmulateAPPNAME(pM);
737
return (pM->pCSAPPNAME == NULL) ? "" : (char*) rsCStrGetSzStrNoNULL(pM->pCSAPPNAME);
743
/* rgerhards 2004-11-24: set PROCID in msg object
745
rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID)
747
assert(pMsg != NULL);
748
if(pMsg->pCSPROCID == NULL) {
749
/* we need to obtain the object first */
750
if((pMsg->pCSPROCID = rsCStrConstruct()) == NULL)
751
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
752
rsCStrSetAllocIncrement(pMsg->pCSPROCID, 128);
754
/* if we reach this point, we have the object */
755
return rsCStrSetSzStr(pMsg->pCSPROCID, (uchar*) pszPROCID);
758
/* rgerhards, 2005-11-24
760
int getPROCIDLen(msg_t *pM)
764
if(pM->pCSPROCID == NULL)
765
aquirePROCIDFromTAG(pM);
767
return (pM->pCSPROCID == NULL) ? 1 : rsCStrLen(pM->pCSPROCID);
771
/* rgerhards, 2005-11-24
773
char *getPROCID(msg_t *pM)
777
if(pM->pCSPROCID == NULL)
778
aquirePROCIDFromTAG(pM);
780
return (pM->pCSPROCID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSPROCID);
784
/* rgerhards 2004-11-24: set MSGID in msg object
786
rsRetVal MsgSetMSGID(msg_t *pMsg, char* pszMSGID)
788
assert(pMsg != NULL);
789
if(pMsg->pCSMSGID == NULL) {
790
/* we need to obtain the object first */
791
if((pMsg->pCSMSGID = rsCStrConstruct()) == NULL)
792
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
793
rsCStrSetAllocIncrement(pMsg->pCSMSGID, 128);
795
/* if we reach this point, we have the object */
796
return rsCStrSetSzStr(pMsg->pCSMSGID, (uchar*) pszMSGID);
799
/* rgerhards, 2005-11-24
801
#if 0 /* This method is currently not called, be we like to preserve it */
802
static int getMSGIDLen(msg_t *pM)
804
return (pM->pCSMSGID == NULL) ? 1 : rsCStrLen(pM->pCSMSGID);
809
/* rgerhards, 2005-11-24
811
char *getMSGID(msg_t *pM)
813
return (pM->pCSMSGID == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSMSGID);
817
/* Set the TAG to a caller-provided string. This is thought
818
* to be a heap buffer that the caller will no longer use. This
819
* function is a performance optimization over MsgSetTAG().
820
* rgerhards 2004-11-19
822
void MsgAssignTAG(msg_t *pMsg, uchar *pBuf)
824
assert(pMsg != NULL);
825
pMsg->iLenTAG = (pBuf == NULL) ? 0 : strlen((char*)pBuf);
826
pMsg->pszTAG = (uchar*) pBuf;
830
/* rgerhards 2004-11-16: set TAG in msg object
832
void MsgSetTAG(msg_t *pMsg, char* pszTAG)
834
assert(pMsg != NULL);
835
if(pMsg->pszTAG != NULL)
837
pMsg->iLenTAG = strlen(pszTAG);
838
if((pMsg->pszTAG = malloc(pMsg->iLenTAG + 1)) != NULL)
839
memcpy(pMsg->pszTAG, pszTAG, pMsg->iLenTAG + 1);
841
dbgprintf("Could not allocate memory in MsgSetTAG()\n");
845
/* This function tries to emulate the TAG if none is
846
* set. Its primary purpose is to provide an old-style TAG
847
* when a syslog-protocol message has been received. Then,
848
* the tag is APP-NAME "[" PROCID "]". The function first checks
849
* if there is a TAG and, if not, if it can emulate it.
850
* rgerhards, 2005-11-24
852
static void tryEmulateTAG(msg_t *pM)
858
if(pM->pszTAG != NULL)
859
return; /* done, no need to emulate */
861
if(getProtocolVersion(pM) == 1) {
862
if(!strcmp(getPROCID(pM), "-")) {
863
/* no process ID, use APP-NAME only */
864
MsgSetTAG(pM, getAPPNAME(pM));
866
/* now we can try to emulate */
867
iTAGLen = getAPPNAMELen(pM) + getPROCIDLen(pM) + 3;
868
if((pBuf = malloc(iTAGLen * sizeof(char))) == NULL)
869
return; /* nothing we can do */
870
snprintf((char*)pBuf, iTAGLen, "%s[%s]", getAPPNAME(pM), getPROCID(pM));
871
MsgAssignTAG(pM, pBuf);
877
#if 0 /* This method is currently not called, be we like to preserve it */
878
static int getTAGLen(msg_t *pM)
884
if(pM->pszTAG == NULL)
893
char *getTAG(msg_t *pM)
902
if(pM->pszTAG == NULL)
905
ret = (char*) pM->pszTAG;
912
int getHOSTNAMELen(msg_t *pM)
917
if(pM->pszHOSTNAME == NULL)
920
return pM->iLenHOSTNAME;
924
char *getHOSTNAME(msg_t *pM)
929
if(pM->pszHOSTNAME == NULL)
932
return (char*) pM->pszHOSTNAME;
936
char *getRcvFrom(msg_t *pM)
941
if(pM->pszRcvFrom == NULL)
944
return (char*) pM->pszRcvFrom;
947
/* rgerhards 2004-11-24: set STRUCTURED DATA in msg object
949
rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData)
951
assert(pMsg != NULL);
952
if(pMsg->pCSStrucData == NULL) {
953
/* we need to obtain the object first */
954
if((pMsg->pCSStrucData = rsCStrConstruct()) == NULL)
955
return RS_RET_OBJ_CREATION_FAILED; /* best we can do... */
956
rsCStrSetAllocIncrement(pMsg->pCSStrucData, 128);
958
/* if we reach this point, we have the object */
959
return rsCStrSetSzStr(pMsg->pCSStrucData, (uchar*) pszStrucData);
962
/* get the length of the "STRUCTURED-DATA" sz string
963
* rgerhards, 2005-11-24
965
#if 0 /* This method is currently not called, be we like to preserve it */
966
static int getStructuredDataLen(msg_t *pM)
968
return (pM->pCSStrucData == NULL) ? 1 : rsCStrLen(pM->pCSStrucData);
973
/* get the "STRUCTURED-DATA" as sz string
974
* rgerhards, 2005-11-24
976
char *getStructuredData(msg_t *pM)
978
return (pM->pCSStrucData == NULL) ? "-" : (char*) rsCStrGetSzStrNoNULL(pM->pCSStrucData);
983
/* get the length of the "programname" sz string
984
* rgerhards, 2005-10-19
986
int getProgramNameLen(msg_t *pM)
992
if((iRet = aquireProgramName(pM)) != RS_RET_OK) {
993
dbgprintf("error %d returned by aquireProgramName() in getProgramNameLen()\n", iRet);
995
return 0; /* best we can do (consistent wiht what getProgramName() returns) */
999
return (pM->pCSProgName == NULL) ? 0 : rsCStrLen(pM->pCSProgName);
1003
/* get the "programname" as sz string
1004
* rgerhards, 2005-10-19
1006
char *getProgramName(msg_t *pM)
1012
if((iRet = aquireProgramName(pM)) != RS_RET_OK) {
1013
dbgprintf("error %d returned by aquireProgramName() in getProgramName()\n", iRet);
1015
return ""; /* best we can do */
1019
return (pM->pCSProgName == NULL) ? "" : (char*) rsCStrGetSzStrNoNULL(pM->pCSProgName);
1023
/* rgerhards 2004-11-16: set pszRcvFrom in msg object
1025
void MsgSetRcvFrom(msg_t *pMsg, char* pszRcvFrom)
1027
assert(pMsg != NULL);
1028
if(pMsg->pszRcvFrom != NULL)
1029
free(pMsg->pszRcvFrom);
1031
pMsg->iLenRcvFrom = strlen(pszRcvFrom);
1032
if((pMsg->pszRcvFrom = malloc(pMsg->iLenRcvFrom + 1)) != NULL) {
1033
memcpy(pMsg->pszRcvFrom, pszRcvFrom, pMsg->iLenRcvFrom + 1);
1038
/* Set the HOSTNAME to a caller-provided string. This is thought
1039
* to be a heap buffer that the caller will no longer use. This
1040
* function is a performance optimization over MsgSetHOSTNAME().
1041
* rgerhards 2004-11-19
1043
void MsgAssignHOSTNAME(msg_t *pMsg, char *pBuf)
1045
assert(pMsg != NULL);
1046
assert(pBuf != NULL);
1047
pMsg->iLenHOSTNAME = strlen(pBuf);
1048
pMsg->pszHOSTNAME = (uchar*) pBuf;
1052
/* rgerhards 2004-11-09: set HOSTNAME in msg object
1053
* rgerhards, 2007-06-21:
1054
* Does not return anything. If an error occurs, the hostname is
1055
* simply not set. I have changed this behaviour. The only problem
1056
* we can run into is memory shortage. If we have such, it is better
1057
* to loose the hostname than the full message. So we silently ignore
1058
* that problem and hope that memory will be available the next time
1059
* we need it. The rest of the code already knows how to handle an
1062
void MsgSetHOSTNAME(msg_t *pMsg, char* pszHOSTNAME)
1064
assert(pMsg != NULL);
1065
if(pMsg->pszHOSTNAME != NULL)
1066
free(pMsg->pszHOSTNAME);
1068
pMsg->iLenHOSTNAME = strlen(pszHOSTNAME);
1069
if((pMsg->pszHOSTNAME = malloc(pMsg->iLenHOSTNAME + 1)) != NULL)
1070
memcpy(pMsg->pszHOSTNAME, pszHOSTNAME, pMsg->iLenHOSTNAME + 1);
1072
dbgprintf("Could not allocate memory in MsgSetHOSTNAME()\n");
1076
/* Set the UxTradMsg to a caller-provided string. This is thought
1077
* to be a heap buffer that the caller will no longer use. This
1078
* function is a performance optimization over MsgSetUxTradMsg().
1079
* rgerhards 2004-11-19
1081
#if 0 /* This method is currently not called, be we like to preserve it */
1082
static void MsgAssignUxTradMsg(msg_t *pMsg, char *pBuf)
1084
assert(pMsg != NULL);
1085
assert(pBuf != NULL);
1086
pMsg->iLenUxTradMsg = strlen(pBuf);
1087
pMsg->pszUxTradMsg = pBuf;
1092
/* rgerhards 2004-11-17: set the traditional Unix message in msg object
1094
int MsgSetUxTradMsg(msg_t *pMsg, char* pszUxTradMsg)
1096
assert(pMsg != NULL);
1097
assert(pszUxTradMsg != NULL);
1098
pMsg->iLenUxTradMsg = strlen(pszUxTradMsg);
1099
if(pMsg->pszUxTradMsg != NULL)
1100
free(pMsg->pszUxTradMsg);
1101
if((pMsg->pszUxTradMsg = malloc(pMsg->iLenUxTradMsg + 1)) != NULL)
1102
memcpy(pMsg->pszUxTradMsg, pszUxTradMsg, pMsg->iLenUxTradMsg + 1);
1104
dbgprintf("Could not allocate memory for pszUxTradMsg buffer.");
1110
/* rgerhards 2004-11-09: set MSG in msg object
1112
void MsgSetMSG(msg_t *pMsg, char* pszMSG)
1114
assert(pMsg != NULL);
1115
assert(pszMSG != NULL);
1117
if(pMsg->pszMSG != NULL)
1120
pMsg->iLenMSG = strlen(pszMSG);
1121
if((pMsg->pszMSG = malloc(pMsg->iLenMSG + 1)) != NULL)
1122
memcpy(pMsg->pszMSG, pszMSG, pMsg->iLenMSG + 1);
1124
dbgprintf("MsgSetMSG could not allocate memory for pszMSG buffer.");
1127
/* rgerhards 2004-11-11: set RawMsg in msg object
1129
void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg)
1131
assert(pMsg != NULL);
1132
if(pMsg->pszRawMsg != NULL)
1133
free(pMsg->pszRawMsg);
1135
pMsg->iLenRawMsg = strlen(pszRawMsg);
1136
if((pMsg->pszRawMsg = malloc(pMsg->iLenRawMsg + 1)) != NULL)
1137
memcpy(pMsg->pszRawMsg, pszRawMsg, pMsg->iLenRawMsg + 1);
1139
dbgprintf("Could not allocate memory for pszRawMsg buffer.");
1143
/* Decode a priority into textual information like auth.emerg.
1144
* The variable pRes must point to a user-supplied buffer and
1145
* pResLen must contain its size. The pointer to the buffer
1146
* is also returned, what makes this functiona suitable for
1147
* use in printf-like functions.
1148
* Note: a buffer size of 20 characters is always sufficient.
1149
* Interface to this function changed 2007-06-15 by RGerhards
1151
char *textpri(char *pRes, size_t pResLen, int pri)
1153
syslogCODE *c_pri, *c_fac;
1155
assert(pRes != NULL);
1156
assert(pResLen > 0);
1158
for (c_fac = rs_facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
1159
for (c_pri = rs_prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
1161
snprintf (pRes, pResLen, "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
1167
/* This function returns the current date in different
1168
* variants. It is used to construct the $NOW series of
1169
* system properties. The returned buffer must be freed
1170
* by the caller when no longer needed. If the function
1171
* can not allocate memory, it returns a NULL pointer.
1172
* Added 2007-07-10 rgerhards
1174
typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType;
1175
#define tmpBUFSIZE 16 /* size of formatting buffer */
1176
static uchar *getNOW(eNOWType eNow)
1179
struct syslogTime t;
1181
if((pBuf = (uchar*) malloc(sizeof(uchar) * tmpBUFSIZE)) == NULL) {
1182
glblHadMemShortage = 1;
1189
snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
1192
snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d", t.year);
1195
snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.month);
1198
snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.day);
1201
snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.hour);
1204
snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.minute);
1210
#undef tmpBUFSIZE /* clean up */
1213
/* This function returns a string-representation of the
1214
* requested message property. This is a generic function used
1215
* to abstract properties so that these can be easier
1216
* queried. Returns NULL if property could not be found.
1217
* Actually, this function is a big if..elseif. What it does
1218
* is simply to map property names (from MonitorWare) to the
1219
* message object data fields.
1221
* In case we need string forms of propertis we do not
1222
* yet have in string form, we do a memory allocation that
1223
* is sufficiently large (in all cases). Once the string
1224
* form has been obtained, it is saved until the Msg object
1225
* is finally destroyed. This is so that we save the processing
1226
* time in the (likely) case that this property is requested
1227
* again. It also saves us a lot of dynamic memory management
1228
* issues in the upper layers, because we so can guarantee that
1229
* the buffer will remain static AND available during the lifetime
1230
* of the object. Please note that both the max size allocation as
1231
* well as keeping things in memory might like look like a
1232
* waste of memory (some might say it actually is...) - we
1233
* deliberately accept this because performance is more important
1235
* rgerhards 2004-11-18
1236
* Parameter "bMustBeFreed" is set by this function. It tells the
1237
* caller whether or not the string returned must be freed by the
1238
* caller itself. It is is 0, the caller MUST NOT free it. If it is
1239
* 1, the caller MUST free 1. Handling this wrongly leads to either
1240
* a memory leak of a program abort (do to double-frees or frees on
1241
* the constant memory pool). So be careful to do it right.
1242
* rgerhards 2004-11-23
1243
* regular expression support contributed by Andres Riancho merged
1245
* changed so that it now an be called without a template entry (NULL).
1246
* In this case, only the (unmodified) property is returned. This will
1247
* be used in selector line processing.
1248
* rgerhards 2005-09-15
1250
char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
1251
rsCStrObj *pCSPropName, unsigned short *pbMustBeFreed)
1254
char *pRes; /* result pointer */
1259
#ifdef FEATURE_REGEXP
1260
/* Variables necessary for regular expression matching */
1262
regmatch_t pmatch[2];
1265
assert(pMsg != NULL);
1266
assert(pbMustBeFreed != NULL);
1268
if(pCSPropName == NULL) {
1269
assert(pTpe != NULL);
1270
pName = pTpe->data.field.pPropRepl;
1272
pName = rsCStrGetSzStrNoNULL(pCSPropName);
1276
/* sometimes there are aliases to the original MonitoWare
1277
* property names. These come after || in the ifs below. */
1278
if(!strcmp((char*) pName, "msg")) {
1279
pRes = getMSG(pMsg);
1280
} else if(!strcmp((char*) pName, "rawmsg")) {
1281
pRes = getRawMsg(pMsg);
1282
} else if(!strcmp((char*) pName, "UxTradMsg")) {
1283
pRes = getUxTradMsg(pMsg);
1284
} else if(!strcmp((char*) pName, "FROMHOST")) {
1285
pRes = getRcvFrom(pMsg);
1286
} else if(!strcmp((char*) pName, "source")
1287
|| !strcmp((char*) pName, "HOSTNAME")) {
1288
pRes = getHOSTNAME(pMsg);
1289
} else if(!strcmp((char*) pName, "syslogtag")) {
1290
pRes = getTAG(pMsg);
1291
} else if(!strcmp((char*) pName, "PRI")) {
1292
pRes = getPRI(pMsg);
1293
} else if(!strcmp((char*) pName, "PRI-text")) {
1294
pBuf = malloc(20 * sizeof(char));
1297
return "**OUT OF MEMORY**";
1300
pRes = textpri(pBuf, 20, getPRIi(pMsg));
1302
} else if(!strcmp((char*) pName, "iut")) {
1303
pRes = "1"; /* always 1 for syslog messages (a MonitorWare thing;)) */
1304
} else if(!strcmp((char*) pName, "syslogfacility")) {
1305
pRes = getFacility(pMsg);
1306
} else if(!strcmp((char*) pName, "syslogfacility-text")) {
1307
pRes = getFacilityStr(pMsg);
1308
} else if(!strcmp((char*) pName, "syslogseverity") || !strcmp((char*) pName, "syslogpriority")) {
1309
pRes = getSeverity(pMsg);
1310
} else if(!strcmp((char*) pName, "syslogseverity-text") || !strcmp((char*) pName, "syslogpriority-text")) {
1311
pRes = getSeverityStr(pMsg);
1312
} else if(!strcmp((char*) pName, "timegenerated")) {
1313
pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
1314
} else if(!strcmp((char*) pName, "timereported")
1315
|| !strcmp((char*) pName, "TIMESTAMP")) {
1316
pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
1317
} else if(!strcmp((char*) pName, "programname")) {
1318
pRes = getProgramName(pMsg);
1319
} else if(!strcmp((char*) pName, "PROTOCOL-VERSION")) {
1320
pRes = getProtocolVersionString(pMsg);
1321
} else if(!strcmp((char*) pName, "STRUCTURED-DATA")) {
1322
pRes = getStructuredData(pMsg);
1323
} else if(!strcmp((char*) pName, "APP-NAME")) {
1324
pRes = getAPPNAME(pMsg);
1325
} else if(!strcmp((char*) pName, "PROCID")) {
1326
pRes = getPROCID(pMsg);
1327
} else if(!strcmp((char*) pName, "MSGID")) {
1328
pRes = getMSGID(pMsg);
1329
/* here start system properties (those, that do not relate to the message itself */
1330
} else if(!strcmp((char*) pName, "$NOW")) {
1331
if((pRes = (char*) getNOW(NOW_NOW)) == NULL) {
1332
return "***OUT OF MEMORY***";
1334
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1335
} else if(!strcmp((char*) pName, "$YEAR")) {
1336
if((pRes = (char*) getNOW(NOW_YEAR)) == NULL) {
1337
return "***OUT OF MEMORY***";
1339
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1340
} else if(!strcmp((char*) pName, "$MONTH")) {
1341
if((pRes = (char*) getNOW(NOW_MONTH)) == NULL) {
1342
return "***OUT OF MEMORY***";
1344
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1345
} else if(!strcmp((char*) pName, "$DAY")) {
1346
if((pRes = (char*) getNOW(NOW_DAY)) == NULL) {
1347
return "***OUT OF MEMORY***";
1349
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1350
} else if(!strcmp((char*) pName, "$HOUR")) {
1351
if((pRes = (char*) getNOW(NOW_HOUR)) == NULL) {
1352
return "***OUT OF MEMORY***";
1354
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1355
} else if(!strcmp((char*) pName, "$MINUTE")) {
1356
if((pRes = (char*) getNOW(NOW_MINUTE)) == NULL) {
1357
return "***OUT OF MEMORY***";
1359
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
1361
/* there is no point in continuing, we may even otherwise render the
1362
* error message unreadable. rgerhards, 2007-07-10
1364
return "**INVALID PROPERTY NAME**";
1367
/* If we did not receive a template pointer, we are already done... */
1372
/* Now check if we need to make "temporary" transformations (these
1373
* are transformations that do not go back into the message -
1374
* memory must be allocated for them!).
1377
/* substring extraction */
1378
/* first we check if we need to extract by field number
1379
* rgerhards, 2005-12-22
1381
if(pTpe->data.field.has_fields == 1) {
1385
/* first, skip to the field in question. The field separator
1386
* is always one character and is stored in the template entry.
1390
while(*pFld && iCurrFld < pTpe->data.field.iToPos) {
1391
/* skip fields until the requested field or end of string is found */
1392
while(*pFld && (uchar) *pFld != pTpe->data.field.field_delim)
1393
++pFld; /* skip to field terminator */
1394
if(*pFld == pTpe->data.field.field_delim) {
1395
++pFld; /* eat it */
1399
dbgprintf("field requested %d, field found %d\n", pTpe->data.field.iToPos, iCurrFld);
1401
if(iCurrFld == pTpe->data.field.iToPos) {
1402
/* field found, now extract it */
1403
/* first of all, we need to find the end */
1405
while(*pFldEnd && *pFldEnd != pTpe->data.field.field_delim)
1407
--pFldEnd; /* we are already at the delimiter - so we need to
1408
* step back a little not to copy it as part of the field. */
1409
/* we got our end pointer, now do the copy */
1410
/* TODO: code copied from below, this is a candidate for a separate function */
1411
iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
1412
pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
1414
if(*pbMustBeFreed == 1)
1417
return "**OUT OF MEMORY**";
1420
memcpy(pBuf, pFld, iLen);
1421
pBuf[iLen] = '\0'; /* terminate it */
1422
if(*pbMustBeFreed == 1)
1426
if(*(pFldEnd+1) != '\0')
1427
++pFldEnd; /* OK, skip again over delimiter char */
1429
/* field not found, return error */
1430
if(*pbMustBeFreed == 1)
1433
return "**FIELD NOT FOUND**";
1435
} else if(pTpe->data.field.iFromPos != 0 || pTpe->data.field.iToPos != 0) {
1436
/* we need to obtain a private copy */
1439
iFrom = pTpe->data.field.iFromPos;
1440
iTo = pTpe->data.field.iToPos;
1441
/* need to zero-base to and from (they are 1-based!) */
1446
iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */
1447
pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
1449
if(*pbMustBeFreed == 1)
1452
return "**OUT OF MEMORY**";
1456
/* skip to the start of the substring (can't do pointer arithmetic
1457
* because the whole string might be smaller!!)
1459
while(*pSb && iFrom) {
1464
/* OK, we are at the begin - now let's copy... */
1465
while(*pSb && iLen) {
1471
if(*pbMustBeFreed == 1)
1475
#ifdef FEATURE_REGEXP
1477
/* Check for regular expressions */
1478
if (pTpe->data.field.has_regex != 0) {
1479
if (pTpe->data.field.has_regex == 2)
1480
/* Could not compile regex before! */
1482
"**NO MATCH** **BAD REGULAR EXPRESSION**";
1484
dbgprintf("debug: String to match for regex is: %s\n",
1487
if (0 != regexec(&pTpe->data.field.re, pRes, nmatch,
1489
/* we got no match! */
1490
return "**NO MATCH**";
1493
/* I need to malloc pB */
1497
iLenBuf = pmatch[1].rm_eo - pmatch[1].rm_so;
1498
pB = (char *) malloc((iLenBuf + 1) * sizeof(char));
1501
if (*pbMustBeFreed == 1)
1504
return "**OUT OF MEMORY ALLOCATING pBuf**";
1507
/* Lets copy the matched substring to the buffer */
1508
memcpy(pB, pRes + pmatch[1].rm_so, iLenBuf);
1509
pB[iLenBuf] = '\0';/* terminate string, did not happen before */
1511
if (*pbMustBeFreed == 1)
1517
#endif /* #ifdef FEATURE_REGEXP */
1521
/* case conversations (should go after substring, because so we are able to
1522
* work on the smallest possible buffer).
1524
if(pTpe->data.field.eCaseConv != tplCaseConvNo) {
1525
/* we need to obtain a private copy */
1526
int iBufLen = strlen(pRes);
1530
pBStart = pB = malloc((iBufLen + 1) * sizeof(char));
1532
if(*pbMustBeFreed == 1)
1535
return "**OUT OF MEMORY**";
1539
*pB++ = (pTpe->data.field.eCaseConv == tplCaseConvUpper) ?
1540
toupper(*pSrc) : tolower(*pSrc);
1541
/* currently only these two exist */
1545
if(*pbMustBeFreed == 1)
1551
/* now do control character dropping/escaping/replacement
1552
* Only one of these can be used. If multiple options are given, the
1553
* result is random (though currently there obviously is an order of
1554
* preferrence, see code below. But this is NOT guaranteed.
1555
* RGerhards, 2006-11-17
1556
* We must copy the strings if we modify them, because they may either
1557
* point to static memory or may point into the message object, in which
1558
* case we would actually modify the original property (which of course
1560
* This was found and fixed by varmojefkoj on 2007-09-11
1562
if(pTpe->data.field.options.bDropCC) {
1570
if(!iscntrl((int) *pSrc++))
1577
pDst = pDstStart = malloc(iLenBuf + 1);
1579
if(*pbMustBeFreed == 1)
1582
return "**OUT OF MEMORY**";
1584
for(pSrc = pRes; *pSrc; pSrc++) {
1585
if(!iscntrl((int) *pSrc))
1589
if(*pbMustBeFreed == 1)
1594
} else if(pTpe->data.field.options.bSpaceCC) {
1599
if(*pbMustBeFreed == 1) {
1600
/* in this case, we already work on dynamic
1601
* memory, so there is no need to copy it - we can
1602
* modify it in-place without any harm. This is a
1603
* performance optiomization.
1605
for(pDst = pRes; *pDst; pDst++) {
1606
if(iscntrl((int) *pDst))
1610
pDst = pDstStart = malloc(strlen(pRes) + 1);
1612
if(*pbMustBeFreed == 1)
1615
return "**OUT OF MEMORY**";
1617
for(pSrc = pRes; *pSrc; pSrc++) {
1618
if(iscntrl((int) *pSrc))
1627
} else if(pTpe->data.field.options.bEscapeCC) {
1628
/* we must first count how many control charactes are
1629
* present, because we need this to compute the new string
1630
* buffer length. While doing so, we also compute the string
1637
for(pB = pRes ; *pB ; ++pB) {
1639
if(iscntrl((int) *pB))
1643
if(iNumCC > 0) { /* if 0, there is nothing to escape, so we are done */
1644
/* OK, let's do the escaping... */
1646
char szCCEsc[8]; /* buffer for escape sequence */
1649
iLenBuf += iNumCC * 4;
1650
pBStart = pB = malloc((iLenBuf + 1) * sizeof(char));
1652
if(*pbMustBeFreed == 1)
1655
return "**OUT OF MEMORY**";
1658
if(iscntrl((int) *pRes)) {
1659
snprintf(szCCEsc, sizeof(szCCEsc), "#%3.3d", *pRes);
1660
for(i = 0 ; i < 4 ; ++i)
1668
if(*pbMustBeFreed == 1)
1676
/* Take care of spurious characters to make the property safe
1677
* for a path definition
1679
if(pTpe->data.field.options.bSecPathDrop || pTpe->data.field.options.bSecPathReplace) {
1680
if(pTpe->data.field.options.bSecPathDrop) {
1695
pDst = pDstStart = malloc(iLenBuf + 1);
1697
if(*pbMustBeFreed == 1)
1700
return "**OUT OF MEMORY**";
1702
for(pSrc = pRes; *pSrc; pSrc++) {
1707
if(*pbMustBeFreed == 1)
1717
if(*pbMustBeFreed == 1) {
1718
/* here, again, we can modify the string as we already obtained
1719
* a private buffer. As we do not change the size of that buffer,
1720
* in-place modification is possible. This is a performance
1723
for(pDst = pRes; *pDst; pDst++) {
1728
pDst = pDstStart = malloc(strlen(pRes) + 1);
1730
if(*pbMustBeFreed == 1)
1733
return "**OUT OF MEMORY**";
1735
for(pSrc = pRes; *pSrc; pSrc++) {
1742
/* we must NOT check if it needs to be freed, because we have done
1743
* this in the if above. So if we come to hear, the pSrc string needs
1744
* not to be freed (and we do not need to care about it).
1751
/* check for "." and ".." (note the parenthesis in the if condition!) */
1752
if((*pRes == '.') && (*(pRes + 1) == '\0' || (*(pRes + 1) == '.' && *(pRes + 2) == '\0'))) {
1755
if(*(pRes + 1) == '\0')
1759
if(*pbMustBeFreed == 1)
1762
} else if(*pRes == '\0') {
1763
if(*pbMustBeFreed == 1)
1770
/* Now drop last LF if present (pls note that this must not be done
1771
* if bEscapeCC was set!
1773
if(pTpe->data.field.options.bDropLastLF && !pTpe->data.field.options.bEscapeCC) {
1774
int iLn = strlen(pRes);
1776
if(iLn > 0 && *(pRes + iLn - 1) == '\n') {
1778
/* check if we need to obtain a private copy */
1779
if(*pbMustBeFreed == 0) {
1780
/* ok, original copy, need a private one */
1781
pB = malloc((iLn + 1) * sizeof(char));
1784
return "**OUT OF MEMORY**";
1786
memcpy(pB, pRes, iLn - 1);
1790
*(pRes + iLn - 1) = '\0'; /* drop LF ;) */
1794
/*dbgprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); only for verbose debug logging */