Projekt

Allgemein

Profil

Herunterladen (100 KB) Statistiken
| Zweig: | Markierung: | Revision:
/***************************************************************************
$RCSfile$
-------------------
cvs : $Id$
begin : Fri Jul 04 2003
copyright : (C) 2003 by Martin Preuss
email : martin@libchipcard.de

***************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
* *
***************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#define DISABLE_DEBUGLOG

#include <gwenhywfar/gwenhywfarapi.h>
#include <msgengine_p.h>
#include <gwenhywfar/xml.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/misc.h>
#include <gwenhywfar/path.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/buffer.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>


GWEN_INHERIT_FUNCTIONS(GWEN_MSGENGINE)


GWEN_MSGENGINE *GWEN_MsgEngine_new(){
GWEN_MSGENGINE *e;

GWEN_NEW_OBJECT(GWEN_MSGENGINE, e);
GWEN_INHERIT_INIT(GWEN_MSGENGINE, e);
e->charsToEscape=strdup(GWEN_MSGENGINE_CHARSTOESCAPE);
e->delimiters=strdup(GWEN_MSGENGINE_DEFAULT_DELIMITERS);
e->globalValues=GWEN_DB_Group_new("globalvalues");
e->escapeChar='\\';

e->usage=1;
return e;
}


void GWEN_MsgEngine_free(GWEN_MSGENGINE *e){
if (e) {
assert(e->usage);
if (--(e->usage)==0) {
GWEN_INHERIT_FINI(GWEN_MSGENGINE, e);

if (e->inheritorData && e->freeDataPtr)
e->freeDataPtr(e);
if (e->ownDefs)
GWEN_XMLNode_free(e->defs);
free(e->charsToEscape);
free(e->delimiters);
GWEN_DB_Group_free(e->globalValues);
if (e->trustInfos) {
/* free trustInfos */
GWEN_MSGENGINE_TRUSTEDDATA *td, *tdn;

td=e->trustInfos;
while(td) {
tdn=td->next;
GWEN_MsgEngine_TrustedData_free(td);
td=tdn;
} /* while */
}
GWEN_FREE_OBJECT(e);
}
}
}



void GWEN_MsgEngine_Attach(GWEN_MSGENGINE *e){
assert(e);
e->usage++;
}


void GWEN_MsgEngine_SetEscapeChar(GWEN_MSGENGINE *e, char c){
assert(e);
e->escapeChar=c;
}



char GWEN_MsgEngine_GetEscapeChar(GWEN_MSGENGINE *e){
assert(e);
return e->escapeChar;
}



void GWEN_MsgEngine_SetCharsToEscape(GWEN_MSGENGINE *e, const char *c){
assert(e);
free(e->charsToEscape);
e->charsToEscape=strdup(c);
}



const char *GWEN_MsgEngine_GetCharsToEscape(GWEN_MSGENGINE *e){
assert(e);
return e->charsToEscape;
}



void GWEN_MsgEngine_SetDelimiters(GWEN_MSGENGINE *e, const char *s){
assert(e);
free(e->delimiters);
if (s)
e->delimiters=strdup(s);
else
e->delimiters=strdup(GWEN_MSGENGINE_DEFAULT_DELIMITERS);
}



const char *GWEN_MsgEngine_GetDelimiters(GWEN_MSGENGINE *e){
assert(e);
return e->delimiters;
}



void GWEN_MsgEngine_SetMode(GWEN_MSGENGINE *e, const char *mode){
GWEN_DB_NODE *db;

assert(e);
db=GWEN_MsgEngine__GetGlobalValues(e);

if (mode)
GWEN_DB_SetCharValue(db,
GWEN_DB_FLAGS_OVERWRITE_VARS,
"engine/secmode",
mode);
else
GWEN_DB_DeleteVar(db, "engine/secmode");
}


const char *GWEN_MsgEngine_GetMode(GWEN_MSGENGINE *e){
GWEN_DB_NODE *db;

assert(e);
db=GWEN_MsgEngine__GetGlobalValues(e);
return GWEN_DB_GetCharValue(db, "engine/secmode", 0, 0);
}



GWEN_DB_NODE *GWEN_MsgEngine__GetGlobalValues(GWEN_MSGENGINE *e){
GWEN_DB_NODE *globalValues;

assert(e);
if (e->getGlobalValuesPtr) {
globalValues=e->getGlobalValuesPtr(e);
if (!globalValues)
globalValues=e->globalValues;
}
else {
globalValues=e->globalValues;
}
assert(globalValues);
return globalValues;
}



unsigned int GWEN_MsgEngine_GetProtocolVersion(GWEN_MSGENGINE *e){
GWEN_DB_NODE *db;

assert(e);
db=GWEN_MsgEngine__GetGlobalValues(e);
return GWEN_DB_GetIntValue(db, "engine/pversion", 0, 0);
}



void GWEN_MsgEngine_SetProtocolVersion(GWEN_MSGENGINE *e,
unsigned int p){
GWEN_DB_NODE *db;

assert(e);
db=GWEN_MsgEngine__GetGlobalValues(e);

GWEN_DB_SetIntValue(db,
GWEN_DB_FLAGS_OVERWRITE_VARS,
"engine/pversion",
p);
}



GWEN_XMLNODE *GWEN_MsgEngine_GetDefinitions(GWEN_MSGENGINE *e){
assert(e);
return e->defs;
}


void GWEN_MsgEngine_SetDefinitions(GWEN_MSGENGINE *e,
GWEN_XMLNODE *n,
int take){
assert(e);
if (e->ownDefs)
GWEN_XMLNode_free(e->defs);
e->defs=n;
e->ownDefs=take;
}



void
GWEN_MsgEngine_SetGetGlobalValuesFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_GETGLOBALVALUES_PTR p){
assert(e);
e->getGlobalValuesPtr=p;
}



GWEN_MSGENGINE_GETGLOBALVALUES_PTR
GWEN_MsgEngine_GetGetGlobalValuesFunction(GWEN_MSGENGINE *e){
assert(e);
return e->getGlobalValuesPtr;
}



void GWEN_MsgEngine_SetTypeReadFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_TYPEREAD_PTR p){
assert(e);
e->typeReadPtr=p;
}



GWEN_MSGENGINE_TYPEREAD_PTR
GWEN_MsgEngine_GetTypeReadFunction(GWEN_MSGENGINE *e){
assert(e);
return e->typeReadPtr;
}



void GWEN_MsgEngine_SetTypeWriteFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_TYPEWRITE_PTR p){
assert(e);
e->typeWritePtr=p;
}



GWEN_MSGENGINE_TYPEWRITE_PTR
GWEN_MsgEngine_GetTypeWriteFunction(GWEN_MSGENGINE *e){
assert(e);
return e->typeWritePtr;
}



void GWEN_MsgEngine_SetTypeCheckFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_TYPECHECK_PTR p){
assert(e);
e->typeCheckPtr=p;
}



GWEN_MSGENGINE_TYPECHECK_PTR
GWEN_MsgEngine_GetTypeCheckFunction(GWEN_MSGENGINE *e){
assert(e);
return e->typeCheckPtr;
}






void GWEN_MsgEngine_SetBinTypeReadFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_BINTYPEREAD_PTR p){
assert(e);
e->binTypeReadPtr=p;
}



GWEN_MSGENGINE_BINTYPEREAD_PTR
GWEN_MsgEngine_GetBinTypeReadFunction(GWEN_MSGENGINE *e){
assert(e);
return e->binTypeReadPtr;
}



void
GWEN_MsgEngine_SetBinTypeWriteFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_BINTYPEWRITE_PTR p){
assert(e);
e->binTypeWritePtr=p;
}



GWEN_MSGENGINE_BINTYPEWRITE_PTR
GWEN_MsgEngine_GetBinTypeWriteFunction(GWEN_MSGENGINE *e){
assert(e);
return e->binTypeWritePtr;
}



void
GWEN_MsgEngine_SetGetCharValueFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_GETCHARVALUE_PTR p){
assert(e);
e->getCharValuePtr=p;
}



void
GWEN_MsgEngine_SetGetIntValueFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_GETINTVALUE_PTR p){
assert(e);
e->getIntValuePtr=p;
}



void
GWEN_MsgEngine_SetFreeDataFunction(GWEN_MSGENGINE *e,
GWEN_MSGENGINE_FREEDATA_PTR p){
assert(e);
DBG_WARN(GWEN_LOGDOMAIN, "GWEN_MsgEngine_SetFreeDataFunction: Deprecated");
e->freeDataPtr=p;
}



void *GWEN_MsgEngine_GetInheritorData(const GWEN_MSGENGINE *e){
assert(e);
return e->inheritorData;
}



void GWEN_MsgEngine_SetInheritorData(GWEN_MSGENGINE *e, void *d){
assert(e);
DBG_WARN(GWEN_LOGDOMAIN, "GWEN_MsgEngine_SetInheritorData: Deprecated");
if (e->inheritorData && e->freeDataPtr)
e->freeDataPtr(e);
e->inheritorData=d;
}



int GWEN_MsgEngine__WriteValue(GWEN_MSGENGINE *e,
GWEN_BUFFER *gbuf,
GWEN_BUFFER *data,
GWEN_XMLNODE *node) {
unsigned int minsize;
unsigned int maxsize;
unsigned int fixSize;
unsigned int startPos;
int filler;
const char *type;
const char *name;
int rv;

/* get some sizes */
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
fixSize=atoi(GWEN_XMLNode_GetProperty(node, "size","0"));
filler=atoi(GWEN_XMLNode_GetProperty(node, "filler","0"));
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
name=GWEN_XMLNode_GetProperty(node, "name","<unnamed>");
startPos=GWEN_Buffer_GetPos(gbuf);

/* check sizes */
if (minsize && GWEN_Buffer_GetUsedBytes(data)<minsize) {
DBG_ERROR(GWEN_LOGDOMAIN, "Data too short (minsize is %d)", minsize);
return -1;
}
if (maxsize && GWEN_Buffer_GetUsedBytes(data)>maxsize) {
DBG_ERROR(GWEN_LOGDOMAIN, "Data too long (maxsize is %d)", maxsize);
return -1;
}

rv=1;
if (e->typeWritePtr) {
rv=e->typeWritePtr(e,
gbuf,
data,
node);
}
if (rv==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "External type writing failed");
return -1;
}
else if (rv==1) {
int i;

/* type not handled externally, so handle it myself */
if (strcasecmp(type, "bin")==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Writing binary data (%d bytes added to %d bytes)",
GWEN_Buffer_GetUsedBytes(data),
GWEN_Buffer_GetUsedBytes(gbuf));
if (GWEN_Buffer_AllocRoom(gbuf, 10+GWEN_Buffer_GetUsedBytes(data))) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
sprintf(GWEN_Buffer_GetPosPointer(gbuf),
"@%d@",
GWEN_Buffer_GetUsedBytes(data));


i=strlen(GWEN_Buffer_GetPosPointer(gbuf));
GWEN_Buffer_IncrementPos(gbuf, i);
GWEN_Buffer_AdjustUsedBytes(gbuf);
GWEN_Buffer_AppendBuffer(gbuf, data);
} /* if type is "bin" */
else if (strcasecmp(type, "num")==0) {
int num;
unsigned int len;
unsigned int lj;

num=atoi(GWEN_Buffer_GetPosPointer(data));
len=strlen(GWEN_Buffer_GetPosPointer(data));

if (atoi(GWEN_XMLNode_GetProperty(node, "leftfill","0"))) {
if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}

/* fill left */
for (lj=0; lj<(maxsize-len); lj++)
GWEN_Buffer_AppendByte(gbuf, '0');

/* write value */
for (lj=0; lj<len; lj++)
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));
}
else if (atoi(GWEN_XMLNode_GetProperty(node, "rightfill","0"))) {
if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}

/* write value */
for (lj=0; lj<len; lj++)
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));

/* fill right */
for (lj=0; lj<(maxsize-len); lj++)
GWEN_Buffer_AppendByte(gbuf, '0');
}
else {
if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Maxsize in XML file is higher than the buffer size");
return -1;
}
for (lj=0; lj<len; lj++)
GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data));
}
} /* if type is num */
else {
/* TODO: Check for valids */
const char *p;
int lastWasEscape;
unsigned int pcount;

p=GWEN_Buffer_GetPosPointer(data);
pcount=0;
lastWasEscape=0;
while(*p && pcount<GWEN_Buffer_GetUsedBytes(data)) {
int c;

c=(unsigned char)*p;
if (lastWasEscape) {
lastWasEscape=0;
switch(c) {
case 'r': c='\r'; break;
case 'n': c='\n'; break;
case 'f': c='\f'; break;
case 't': c='\t'; break;
default: c=(unsigned char)*p;
} /* switch */
}
else {
if (*p=='\\') {
lastWasEscape=1;
c=-1;
}
else
c=(unsigned char)*p;
}
if (c!=-1) {
int needsEscape;

needsEscape=0;
if (c==e->escapeChar)
needsEscape=1;
else {
if (e->charsToEscape)
if (strchr(e->charsToEscape, c))
needsEscape=1;
}
if (needsEscape) {
/* write escape char */
if (GWEN_Buffer_AppendByte(gbuf,
e->escapeChar)) {
return -1;
}
}
if (GWEN_Buffer_AppendByte(gbuf, c)) {
return -1;
}
}
p++;
pcount++;
} /* while */
if (pcount<GWEN_Buffer_GetUsedBytes(data)) {
DBG_WARN(GWEN_LOGDOMAIN, "Premature end of string (%d<%d)",
pcount, GWEN_Buffer_GetUsedBytes(data));
}
if (*p) {
DBG_WARN(GWEN_LOGDOMAIN,
"String for \"%s\" (type %s) is longer than expected "
"(no #0 at pos=%d)",
name, type,
GWEN_Buffer_GetUsedBytes(data)-1);
}
} /* if type is not BIN */
} /* if type not external */
else {
DBG_INFO(GWEN_LOGDOMAIN, "Type \"%s\" (for %s) is external (write)",
type, name);

} /* if external type */

/* fill data */
if (fixSize) {
GWEN_TYPE_UINT32 bs;
unsigned int j;

bs=GWEN_Buffer_GetPos(gbuf)-startPos;
if (bs>fixSize) {
DBG_ERROR(GWEN_LOGDOMAIN,
"Data too long (size is %d, fixed size is %d)",
bs, fixSize);
return -1;
}

for (j=bs; j<fixSize; j++)
GWEN_Buffer_AppendByte(gbuf, (unsigned char)filler);
}

return 0;
}



int GWEN_MsgEngine__IsCharTyp(GWEN_MSGENGINE *e,
const char *type) {
if (e->typeCheckPtr) {
GWEN_DB_VALUETYPE vt;

vt=e->typeCheckPtr(e, type);
if (vt!=GWEN_DB_VALUETYPE_UNKNOWN) {
if (vt==GWEN_DB_VALUETYPE_CHAR)
return 1;
}
}
return
(strcasecmp(type, "alpha")==0) ||
(strcasecmp(type, "ascii")==0) ||
(strcasecmp(type, "an")==0) ||
(strcasecmp(type, "float")==0);
}



int GWEN_MsgEngine__IsIntTyp(GWEN_MSGENGINE *e,
const char *type) {
if (e->typeCheckPtr) {
GWEN_DB_VALUETYPE vt;

vt=e->typeCheckPtr(e, type);
if (vt!=GWEN_DB_VALUETYPE_UNKNOWN) {
if (vt==GWEN_DB_VALUETYPE_INT)
return 1;
}
}
return
(strcasecmp(type, "num")==0);
}



int GWEN_MsgEngine__IsBinTyp(GWEN_MSGENGINE *e,
const char *type) {
if (e->typeCheckPtr) {
GWEN_DB_VALUETYPE vt;

vt=e->typeCheckPtr(e, type);
if (vt!=GWEN_DB_VALUETYPE_UNKNOWN) {
if (vt==GWEN_DB_VALUETYPE_BIN)
return 1;
}
}
return
(strcasecmp(type, "bin")==0);
}



int GWEN_MsgEngine__GetInline(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
GWEN_BUFFER *mbuf) {
/* get data from within the XML node */
GWEN_XMLNODE *n;
const char *type;


type=GWEN_XMLNode_GetProperty(node, "type", "ascii");
DBG_DEBUG(GWEN_LOGDOMAIN,
"Getting data of type \"%s\" from within XML file", type);
n=GWEN_XMLNode_GetFirstData(node);
if (!n) {
DBG_DEBUG(GWEN_LOGDOMAIN, "No child");
return 1;
}

if (GWEN_MsgEngine__IsBinTyp(e, type)) {
const char *dp;
unsigned int dplen;
const char *stype;

stype=GWEN_XMLNode_GetProperty(node, "storedAs", type);
if (GWEN_MsgEngine__IsBinTyp(e, stype)) {
dp=GWEN_XMLNode_GetData(n);
dplen=strlen(dp);
if (GWEN_Text_FromHexBuffer(dp, mbuf)) {
DBG_INFO(GWEN_LOGDOMAIN, "here");
return -1;
}
} /* if stored as bin */
else {
/* stored as char */
GWEN_Buffer_AppendString(mbuf, GWEN_XMLNode_GetData(n));
}
} /* if binType */
else {
GWEN_Buffer_AppendString(mbuf, GWEN_XMLNode_GetData(n));
}

return 0;
}





int GWEN_MsgEngine__WriteElement(GWEN_MSGENGINE *e,
GWEN_BUFFER *gbuf,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_DB_NODE *gr,
int loopNr,
int isOptional,
GWEN_XMLNODE_PATH *nodePath) {
const char *name;
const char *type;
unsigned int minsize;
unsigned int maxsize;
char numbuffer[256];
const char *pdata;
unsigned int datasize;
GWEN_BUFFER *data;
GWEN_BUFFER *tdata;
int handled;

pdata=0;
handled=0;
data=0;
tdata=0;

/* get type */
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");
DBG_DEBUG(GWEN_LOGDOMAIN, "Type is \"%s\"", type);
/* get some sizes */
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));

if (e->binTypeWritePtr &&
GWEN_MsgEngine__IsBinTyp(e, type) &&
atoi(GWEN_XMLNode_GetProperty(node, "writebin", "1"))) {
int rv;

data=GWEN_Buffer_new(0,
64,
0,
1);

rv=e->binTypeWritePtr(e, node, gr, data);
if (rv==-1) {
/* error */
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
return -1;
}
else if (rv==0) {
handled=1;
}
else if (rv==1) {
GWEN_Buffer_free(data);
data=0;
}
}

if (!handled) {
/* get name */
name=GWEN_XMLNode_GetProperty(node, "name", 0);
if (!name) {
int rv;

/* get data from within the XML node */
tdata=GWEN_Buffer_new(0, 32, 0, 1);
GWEN_Buffer_SetStep(tdata, 256);
rv=GWEN_MsgEngine__GetInline(e, node, tdata);
if (rv==0) {
pdata=GWEN_Buffer_GetStart(tdata);
datasize=GWEN_Buffer_GetUsedBytes(tdata);
}
else {
GWEN_Buffer_free(tdata);
tdata=0;
pdata="";
datasize=0;
}
} /* if (!name) */
else {
const char *nptr;
DBG_DEBUG(GWEN_LOGDOMAIN, "Name provided (%s), loop is %d", name, loopNr);
nptr=name;

if (gr) {
GWEN_DB_VALUETYPE vt;
int idata;

/* Variable type of DB takes precedence
*/
vt=GWEN_DB_GetValueTypeByPath(gr, nptr, loopNr);
if (vt==GWEN_DB_VALUETYPE_UNKNOWN) {
if (GWEN_MsgEngine__IsCharTyp(e, type))
vt=GWEN_DB_VALUETYPE_CHAR;
else if (GWEN_MsgEngine__IsIntTyp(e, type))
vt=GWEN_DB_VALUETYPE_INT;
else if (GWEN_MsgEngine__IsBinTyp(e, type))
vt=GWEN_DB_VALUETYPE_BIN;
else {
DBG_INFO(GWEN_LOGDOMAIN,
"Unable to determine parameter "
"type (%s), assuming \"char\" for this matter", type);
vt=GWEN_DB_VALUETYPE_CHAR;
}
}
/* get the value of the given var from the db */
switch(vt) {
case GWEN_DB_VALUETYPE_CHAR:
DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is char", name);
pdata=GWEN_DB_GetCharValue(gr, nptr, loopNr, 0);
if (pdata) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Value of \"%s\" is %s", nptr, pdata);
datasize=strlen(pdata);
}
else
datasize=0;
break;
case GWEN_DB_VALUETYPE_INT:
DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is int", name);
if (GWEN_DB_ValueExists(gr, nptr, loopNr)) {
idata=GWEN_DB_GetIntValue(gr, nptr, loopNr, 0);
if (-1==GWEN_Text_NumToString(idata, numbuffer,
sizeof(numbuffer),0)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
GWEN_Buffer_free(data);
return -1;
}
DBG_DEBUG(GWEN_LOGDOMAIN, "Value of \"%s\" is %d", nptr, idata);
pdata=numbuffer;
datasize=strlen(numbuffer);
}
break;
case GWEN_DB_VALUETYPE_BIN:
DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is bin", name);
pdata=GWEN_DB_GetBinValue(gr, nptr, loopNr, 0, 0, &datasize);
break;

default:
DBG_WARN(GWEN_LOGDOMAIN, "Unsupported parameter type (%d)", vt);
break;
} /* switch vt */
} /* if gr */
if (!pdata) {
GWEN_XMLNODE_PATH *copyOfNodePath;
copyOfNodePath=GWEN_XMLNode_Path_dup(nodePath);
/* still no data, try to get it from the XML file */
DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\"", name);
pdata=GWEN_MsgEngine__SearchForValue(e,
node, copyOfNodePath, nptr,
&datasize);
GWEN_XMLNode_Path_free(copyOfNodePath);
if (pdata) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Found value of \"%s\"", name);
}
}

if (!pdata) {
int rv;
/* get data from within the XML node */
tdata=GWEN_Buffer_new(0, 32, 0, 1);
GWEN_Buffer_SetStep(tdata, 256);
rv=GWEN_MsgEngine__GetInline(e, node, tdata);
if (rv==0) {
pdata=GWEN_Buffer_GetStart(tdata);
datasize=GWEN_Buffer_GetUsedBytes(tdata);
}
else {
GWEN_Buffer_free(tdata);
tdata=0;
}
}

if (pdata==0) {
if (isOptional) {
DBG_INFO(GWEN_LOGDOMAIN, "Value not found, omitting element \"%s[%d]\"",
name, loopNr);
GWEN_Buffer_free(data);
return 1;
}
else {
DBG_ERROR(GWEN_LOGDOMAIN,
"Value for element \"%s[%d]\" (mode \"%s\") not found",
name, loopNr,
GWEN_MsgEngine_GetMode(e));
GWEN_DB_Dump(gr, stderr, 4);
GWEN_Buffer_free(data);
return -1;
}
}
}

if (!data)
data=GWEN_Buffer_new((char*)pdata,
datasize,
datasize,
0 /* dont take ownership*/ );
}

/* write value */
if (GWEN_MsgEngine__WriteValue(e,
gbuf,
data,
node)!=0) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not write value");
GWEN_Buffer_free(data);
GWEN_Buffer_free(tdata);
return -1;
}
GWEN_Buffer_free(data);
GWEN_Buffer_free(tdata);

return 0;
}



GWEN_XMLNODE *GWEN_MsgEngine_FindGroupByProperty(GWEN_MSGENGINE *e,
const char *pname,
int version,
const char *pvalue) {
return GWEN_MsgEngine_FindNodeByProperty(e, "GROUP", pname, version, pvalue);
}



GWEN_XMLNODE *GWEN_MsgEngine_FindNodeByProperty(GWEN_MSGENGINE *e,
const char *t,
const char *pname,
int version,
const char *pvalue) {
GWEN_XMLNODE *n;
const char *p;
int i;
const char *mode;
unsigned int proto;
char buffer[256];

if ((strlen(t)+4)>sizeof(buffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Type name too long.");
return 0;
}

mode=GWEN_MsgEngine_GetMode(e);
proto=GWEN_MsgEngine_GetProtocolVersion(e);
if (!e->defs) {
DBG_INFO(GWEN_LOGDOMAIN, "No definitions available");
return 0;
}
n=e->defs;
n=GWEN_XMLNode_GetChild(n);

/* find type+"S" */
strcpy(buffer, t);
strcat(buffer,"S");
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, buffer)==0)
break;
}
n=GWEN_XMLNode_Next(n);
} /* while */

if (!n) {
DBG_INFO(GWEN_LOGDOMAIN, "No definitions available for type \"%s\"", t);
return 0;
}

/* find approppriate group definition */
if (!mode)
mode="";
n=GWEN_XMLNode_GetChild(n);
if (!n) {
DBG_INFO(GWEN_LOGDOMAIN, "No definitions inside \"%s\"", buffer);
return 0;
}

/* find type+"def" */
strcpy(buffer, t);
strcat(buffer,"def");
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, buffer)==0) {
p=GWEN_XMLNode_GetProperty(n, pname,"");
if (strcasecmp(p, pvalue)==0) {
i=atoi(GWEN_XMLNode_GetProperty(n, "pversion" ,"0"));
if (proto==0 || (int)proto==i || i==0) {
i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0"));
if (version==0 || version==i) {
p=GWEN_XMLNode_GetProperty(n, "mode","");
if (strcasecmp(p, mode)==0 || !*p) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\" found",
pname, pvalue);
return n;
}
}
}
}
}
}
n=GWEN_XMLNode_Next(n);
} /* while */

DBG_INFO(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\"(%d) not found",
pname,
pvalue,
version);
return 0;
}



const char *GWEN_MsgEngine__TransformValue(GWEN_MSGENGINE *e,
const char *pvalue,
GWEN_XMLNODE *node,
GWEN_XMLNODE *dnode,
unsigned int *datasize) {
const char *p;
char pbuffer[256];
GWEN_DB_NODE *globalValues;

globalValues=GWEN_MsgEngine__GetGlobalValues(e);
assert(globalValues);

if (pvalue) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Transforming value \"%s\"", pvalue);
/* check whether the value is a property */
p=pvalue;
while (*p && isspace((int)*p))
p++;
if (*p=='$' || *p=='+') {
/* global property */
int incr;

incr=(*p=='+');
p++;

DBG_DEBUG(GWEN_LOGDOMAIN, "Getting global property \"%s\"", p);
if (incr) {
int z;

z=GWEN_DB_GetIntValue(globalValues, p, 0, 0);
DBG_DEBUG(GWEN_LOGDOMAIN, "Incrementing global property \"%s\" (%d)",
p, z);
if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string");
return 0;
}

z++;
DBG_DEBUG(GWEN_LOGDOMAIN, "Setting global property \"%s\"=%d", p, z);
GWEN_DB_SetIntValue(globalValues,
GWEN_DB_FLAGS_DEFAULT |
GWEN_DB_FLAGS_OVERWRITE_VARS,
p, z);
pvalue=pbuffer;
*datasize=strlen(pvalue);
}
else {
int z;
GWEN_DB_VALUETYPE vt;
const char *type = "should_be_known";
/* default value; otherwise the compiler issues a warning */

DBG_DEBUG(GWEN_LOGDOMAIN, "Getting global property \"%s\"", p);
vt=GWEN_DB_GetVariableType(globalValues, p);
if (vt==GWEN_DB_VALUETYPE_UNKNOWN) {
if (!GWEN_DB_VariableExists(globalValues, p)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unable to determine type of \"%s\"", p);
return 0;
}
type=GWEN_XMLNode_GetProperty(dnode, "type", "ascii");
if (GWEN_MsgEngine__IsCharTyp(e, type))
vt=GWEN_DB_VALUETYPE_CHAR;
else if (GWEN_MsgEngine__IsIntTyp(e, type))
vt=GWEN_DB_VALUETYPE_INT;
else if (GWEN_MsgEngine__IsBinTyp(e, type))
vt=GWEN_DB_VALUETYPE_BIN;
else {
DBG_ERROR(GWEN_LOGDOMAIN,
"Unable to determine type of \"%s\" (xml)", p);
return 0;
}
}

switch(vt) {
case GWEN_DB_VALUETYPE_CHAR:
pvalue=GWEN_DB_GetCharValue(globalValues, p, 0, "");
*datasize=strlen(pvalue);
break;

case GWEN_DB_VALUETYPE_INT:
z=GWEN_DB_GetIntValue(globalValues, p, 0, 0);
if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string");
return 0;
}
pvalue=pbuffer;
*datasize=strlen(pvalue);
break;

case GWEN_DB_VALUETYPE_BIN:
pvalue=GWEN_DB_GetBinValue(globalValues, p, 0,
0,0,
datasize);
break;

default:
DBG_ERROR(GWEN_LOGDOMAIN,"Unknown type %s", type);
return 0;
} /* switch */
}
DBG_DEBUG(GWEN_LOGDOMAIN, "Value transformed");
}
else if (*p=='%') {
/* local property */
p++;

DBG_DEBUG(GWEN_LOGDOMAIN, "Getting property \"%s\"", p);
pvalue=GWEN_XMLNode_GetProperty(node, p, 0);
if (pvalue) {
*datasize=strlen(pvalue);
DBG_DEBUG(GWEN_LOGDOMAIN, "Transformed value \"%s\"", pvalue);
}
else
*datasize=0;
}
else if (*p=='?') {
GWEN_DB_VALUETYPE vt;
int z;
const char *dtype;

/* get type */
dtype=GWEN_XMLNode_GetProperty(dnode, "type","ASCII");

/* program variable accessable via callback */
p++;
DBG_DEBUG(GWEN_LOGDOMAIN, "Getting program variable \"%s\"", p);

pvalue=0;
if (GWEN_MsgEngine__IsCharTyp(e, dtype))
vt=GWEN_DB_VALUETYPE_CHAR;
else if (GWEN_MsgEngine__IsIntTyp(e, dtype))
vt=GWEN_DB_VALUETYPE_INT;
else {
vt=GWEN_DB_VALUETYPE_CHAR;
}

switch(vt) {
case GWEN_DB_VALUETYPE_CHAR:
if (e->getCharValuePtr) {
pvalue=e->getCharValuePtr(e, p, 0);
if (pvalue)
*datasize=strlen(pvalue);
}
break;

case GWEN_DB_VALUETYPE_INT:
if (e->getIntValuePtr) {
z=e->getIntValuePtr(e, p, 0);
if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string");
return 0;
}
pvalue=pbuffer;
*datasize=strlen(pvalue);
}
else {
DBG_NOTICE(GWEN_LOGDOMAIN, "Callback for getIntValue not set");
}
break;

default:
DBG_ERROR(GWEN_LOGDOMAIN,"Unhandled type %s", dtype);
return 0;
} /* switch */

DBG_DEBUG(GWEN_LOGDOMAIN, "Value transformed");
}
else {
*datasize=strlen(pvalue);
}
}
return pvalue;
}



const char *GWEN_MsgEngine_SearchForProperty(GWEN_XMLNODE *node,
GWEN_XMLNODE *refnode,
const char *name,
int topDown) {
const char *pvalue;
GWEN_XMLNODE *pn;
const char *lastValue;

DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\" in properties", name);
lastValue=0;

pvalue=GWEN_XMLNode_GetProperty(node, name,0);
if (pvalue) {
if (!topDown)
return pvalue;
DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value (%s), but will look further", pvalue);
lastValue=pvalue;
}

pn=refnode;
while(pn) {
pvalue=GWEN_XMLNode_GetProperty(pn, name,0);
if (pvalue) {
if (!topDown)
return pvalue;
DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value (%s), but will look further", pvalue);
lastValue=pvalue;
}
pn=GWEN_XMLNode_GetParent(pn);
} /* while */
return lastValue;
}



int GWEN_MsgEngine_GetHighestTrustLevel(GWEN_XMLNODE *node,
GWEN_XMLNODE *refnode) {
int value;
GWEN_XMLNODE *pn;
int highestTrust;

highestTrust=0;

value=atoi(GWEN_XMLNode_GetProperty(node, "trustlevel","0"));
if (value>highestTrust)
highestTrust=value;

pn=node;
while(pn) {
value=atoi(GWEN_XMLNode_GetProperty(pn, "trustlevel","0"));
if (value>highestTrust)
highestTrust=value;
pn=GWEN_XMLNode_GetParent(pn);
} /* while */

pn=refnode;
while(pn) {
value=atoi(GWEN_XMLNode_GetProperty(pn, "trustlevel","0"));
if (value>highestTrust)
highestTrust=value;
pn=GWEN_XMLNode_GetParent(pn);
} /* while */
return highestTrust;
}



const char *GWEN_MsgEngine__SearchForValue(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
GWEN_XMLNODE_PATH *nodePath,
const char *name,
unsigned int *datasize) {
const char *pvalue;
GWEN_XMLNODE *pn;
char *bufferPtr;
int topDown;
const char *lastValue;
unsigned int lastDataSize;
unsigned int ldatasize;

DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\" in <VALUES>",
name);
if (!node) {
DBG_WARN(GWEN_LOGDOMAIN, "No node !");
}
topDown=atoi(GWEN_XMLNode_GetProperty(node, "topdown", "0"));
lastValue=0;
lastDataSize=0;

bufferPtr=0;

/*pn=GWEN_XMLNode_GetParent(node);*/
pn=GWEN_XMLNode_Path_Surface(nodePath);
while(pn) {
const char *ppath;
/*
if (GWEN_XMLNode_GetType(pn)==GWEN_XMLNodeTypeTag) {
DBG_NOTICE(GWEN_LOGDOMAIN, "Checking node \"%s\"",
GWEN_XMLNode_GetData(pn));
}*/
pvalue=GWEN_MsgEngine__findInValues(e, pn, node, name, &ldatasize);
if (pvalue) {
if (!topDown) {
free(bufferPtr);
*datasize=ldatasize;
return pvalue;
}
DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value, but will look further");
lastValue=pvalue;
lastDataSize=ldatasize;
}

ppath=GWEN_XMLNode_GetProperty(pn, "name", "");

if (*ppath) {
int i;
char *tmpptr;

if (bufferPtr) {
i=strlen(bufferPtr)+strlen(ppath)+2;
tmpptr=(char*)malloc(i);
assert(tmpptr);
sprintf(tmpptr, "%s/%s", ppath, bufferPtr);
free(bufferPtr);
bufferPtr=tmpptr;
}
else {
i=strlen(ppath)+strlen(name)+2;
tmpptr=(char*)malloc(i);
assert(tmpptr);
sprintf(tmpptr, "%s/%s", ppath, name);
bufferPtr=tmpptr;
}
name=bufferPtr;
}
pn=GWEN_XMLNode_Path_Surface(nodePath);
} /* while */

free(bufferPtr);
if (!lastValue)
*datasize=0;
else
*datasize=lastDataSize;
return lastValue;
}



const char *GWEN_MsgEngine__findInValues(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
GWEN_XMLNODE *dnode,
const char *name,
unsigned int *datasize) {
GWEN_XMLNODE *pn;

DBG_VERBOUS(GWEN_LOGDOMAIN, "Looking for value of \"%s\" in <VALUES>", name);
pn=GWEN_XMLNode_GetChild(node);

while(pn) {
if (GWEN_XMLNode_GetType(pn)==GWEN_XMLNodeTypeTag) {
GWEN_XMLNODE *n;
const char *p;

p=GWEN_XMLNode_GetData(pn);
assert(p);
DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s", p);
if (strcasecmp(p, "VALUES")==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "<values> found");
/* <preset> found, check all values */
n=GWEN_XMLNode_GetChild(pn);
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *p;

p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, "VALUE")==0) {
const char *pname;
const char *pvalue;

pname=GWEN_XMLNode_GetProperty(n, "path", 0);
if (pname) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Comparing against \"%s\"", pname);
if (strcasecmp(name, pname)==0) {
GWEN_XMLNODE *dn;

dn=GWEN_XMLNode_GetChild(n);
while (dn) {
if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) {
pvalue=GWEN_XMLNode_GetData(dn);
if (pvalue) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Transforming \"%s\"", pvalue);
pvalue=GWEN_MsgEngine__TransformValue(e,
pvalue,
node,
dnode,
datasize);
}
if (pvalue)
return pvalue;
}
dn=GWEN_XMLNode_Next(dn);
} /* while dn */
} /* if path matches name */
} /* if path given */
} /* if VALUE tag */
} /* if TAG */
n=GWEN_XMLNode_Next(n);
} /* while */
break; /* REMOVE this to check multiple groups */
} /* if <preset> found */
} /* if tag */
pn=GWEN_XMLNode_Next(pn);
} /* while node */

DBG_DEBUG(GWEN_LOGDOMAIN, "No value found for \"%s\" in <VALUES>", name);
return 0;
}



GWEN_XMLNODE *GWEN_MsgEngine__GetGroup(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
const char *t,
int version,
const char *pvalue) {
GWEN_XMLNODE *n;
const char *p;
int i;
const char *mode;
unsigned int proto;
char buffer[256];

if ((strlen(t)+4)>sizeof(buffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Type name too long.");
return 0;
}

mode=GWEN_MsgEngine_GetMode(e);
proto=GWEN_MsgEngine_GetProtocolVersion(e);

/* find type+"S" */
strcpy(buffer, t);
strcat(buffer,"S");
n=GWEN_XMLNode_FindFirstTag(node, buffer, 0, 0);
if (!n) {
DBG_DEBUG(GWEN_LOGDOMAIN,
"No definitions here for type \"%s\"", t);
return 0;
}

/* find approppriate group definition */
if (!mode)
mode="";
n=GWEN_XMLNode_GetFirstTag(n);
if (!n) {
DBG_INFO(GWEN_LOGDOMAIN, "No definitions inside \"%s\"", buffer);
return 0;
}

/* find type+"def" */
strcpy(buffer, t);
strcat(buffer, "def");
while(n) {
p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, buffer)==0 ||
strcasecmp(p, t)==0) {
p=GWEN_XMLNode_GetProperty(n, "id", "");
if (strcasecmp(p, pvalue)!=0)
p=GWEN_XMLNode_GetProperty(n, "name", "");
if (strcasecmp(p, pvalue)==0) {
i=atoi(GWEN_XMLNode_GetProperty(n, "pversion" ,"0"));
if (proto==0 || (int)proto==i || i==0) {
i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0"));
if (version==0 || version==i) {
p=GWEN_XMLNode_GetProperty(n, "mode","");
if (strcasecmp(p, mode)==0 || !*p) {
DBG_DEBUG(GWEN_LOGDOMAIN,
"Group definition for \"%s=%s\" found",
t, pvalue);
return n;
}
}
}
}
}
n=GWEN_XMLNode_GetNextTag(n);
} /* while */

DBG_DEBUG(GWEN_LOGDOMAIN,
"Group definition for \"%s=%s\"(%d) not found here",
t,
pvalue,
version);
return 0;
}



GWEN_XMLNODE *GWEN_MsgEngine_GetGroup(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
const GWEN_XMLNODE_PATH *nodePath,
const char *t,
int version,
const char *pvalue) {
GWEN_XMLNODE *n;
GWEN_XMLNODE *nLast = 0;
GWEN_XMLNODE *nRes = 0;
GWEN_XMLNODE_PATH *pathCopy;

assert(node);
assert(nodePath);
assert(t);
assert(pvalue);

pathCopy=GWEN_XMLNode_Path_dup(nodePath);
n=GWEN_XMLNode_Path_Surface(pathCopy);
/* first try all nodes along the path */
while(n) {
nLast=n;
nRes=GWEN_MsgEngine__GetGroup(e, n, t, version, pvalue);
if (nRes)
break;
n=GWEN_XMLNode_Path_Surface(pathCopy);
}
GWEN_XMLNode_Path_free(pathCopy);
if (nRes) {
/* already found */
if (nRes==node) {
DBG_ERROR(GWEN_LOGDOMAIN, "Loop detected.");
return 0;
}
return nRes;
}

if (nLast)
n=nLast;
else
n=node;

if (n) {
n=GWEN_XMLNode_GetParent(n);
while(n) {
nRes=GWEN_MsgEngine__GetGroup(e, n, t, version, pvalue);
if (nRes)
break;
n=GWEN_XMLNode_GetParent(n);
}
}

/* try root as a last resort */
if (!nRes && e->defs)
nRes=GWEN_MsgEngine__GetGroup(e, e->defs, t, version, pvalue);

if (!nRes) {
DBG_DEBUG(GWEN_LOGDOMAIN,
"Group definition for \"%s=%s\"(%d) not found",
t,
pvalue,
version);
return 0;
}
if (nRes==node) {
DBG_ERROR(GWEN_LOGDOMAIN, "Loop detected.");
return 0;
}
return nRes;
}



int GWEN_MsgEngine__WriteGroup(GWEN_MSGENGINE *e,
GWEN_BUFFER *gbuf,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_DB_NODE *gr,
int groupIsOptional,
GWEN_XMLNODE_PATH *nodePath) {
GWEN_XMLNODE *n;
const char *p;
char delimiter;
char terminator;
int isFirstElement;
int omittedElements;
int hasEntries;


/* get some settings */
if (rnode) {
/* get delimiter */
p=GWEN_XMLNode_GetProperty(rnode,
"delimiter",
GWEN_XMLNode_GetProperty(node,
"delimiter",
""));
delimiter=*p;

/* get terminating char, if any */
p=GWEN_XMLNode_GetProperty(rnode,
"terminator",
GWEN_XMLNode_GetProperty(node,
"terminator",
""));
terminator=*p;
}
else {
/* get delimiter */
p=GWEN_XMLNode_GetProperty(node,
"delimiter",
"");
delimiter=*p;

/* get terminating char, if any */
p=GWEN_XMLNode_GetProperty(node, "terminator","");
terminator=*p;
}

/* handle all child entries */
n=GWEN_XMLNode_GetChild(node);
isFirstElement=1;
omittedElements=0;
hasEntries=0;
if (!n) {
DBG_INFO(GWEN_LOGDOMAIN, "No subnodes !");
}
while(n) {
int t;
unsigned int minnum;
unsigned int maxnum;
int gversion;
const char *addEmptyMode;
unsigned int loopNr;

minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one");

DBG_DEBUG(GWEN_LOGDOMAIN, "Omitted elements: %d", omittedElements);
t=GWEN_XMLNode_GetType(n);
if (t==GWEN_XMLNodeTypeTag) {
const char *typ;

typ=GWEN_XMLNode_GetData(n);
if (typ==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)");
return -1;
}
if (strcasecmp(typ, "ELEM")==0) {
/* element tag found */
int j;
int rv;

DBG_VERBOUS(GWEN_LOGDOMAIN, "Found an element");
/* write element as often as needed */
for (loopNr=0; loopNr<maxnum; loopNr++) {
unsigned int posBeforeElement;

posBeforeElement=GWEN_Buffer_GetPos(gbuf);

/* write delimiter, if needed */
if (!isFirstElement && delimiter) {
DBG_VERBOUS(GWEN_LOGDOMAIN, "Appending %d delimiters", omittedElements+1);
for (j=0; j<omittedElements+1; j++) {
if (GWEN_Buffer_AppendByte(gbuf, delimiter)) {
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
return -1;
}
}
}

rv=GWEN_MsgEngine__WriteElement(e,
gbuf,
n,
rnode,
gr,
loopNr,
loopNr>=minnum ||
(groupIsOptional && !hasEntries),
nodePath);
if (rv==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "Error writing element");
DBG_INFO(GWEN_LOGDOMAIN, "Node is:");
GWEN_XMLNode_Dump(n, stderr, 1);
if (gr) {
DBG_INFO(GWEN_LOGDOMAIN, "Data is:");
GWEN_DB_Dump(gr, stderr, 1);
}
return -1;
}
else if (rv==0) {
isFirstElement=0;
omittedElements=0;
hasEntries=1;
DBG_DEBUG(GWEN_LOGDOMAIN, "Element written");
}
else {
/* element is optional, not found */
/* restore position */
GWEN_Buffer_SetPos(gbuf, posBeforeElement);
GWEN_Buffer_Crop(gbuf, 0, posBeforeElement);

if (strcasecmp(addEmptyMode, "max")==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Adding max empty");
omittedElements+=(maxnum-loopNr);
}
else if (strcasecmp(addEmptyMode, "min")==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Adding min empty");
if (loopNr<minnum)
omittedElements+=(minnum-loopNr);
}
else if (strcasecmp(addEmptyMode, "one")==0) {
if (loopNr==0)
omittedElements++;
}
else if (strcasecmp(addEmptyMode, "none")==0) {
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "Unknown addemptymode \"%s\"",
addEmptyMode);
return -1;
}
break;
}
} /* for */
}
else if (strcasecmp(typ, "VALUES")==0) {
}
else if (strcasecmp(typ, "DESCR")==0) {
}
else {
/* group tag found */
GWEN_XMLNODE *gn;
GWEN_DB_NODE *gcfg;
const char *gname;
const char *gtype;
unsigned int posBeforeGroup;

DBG_VERBOUS(GWEN_LOGDOMAIN, "Found a group");

gcfg=0;
gtype=GWEN_XMLNode_GetProperty(n, "type",0);
if (!gtype) {
/* no "type" property, so use this group directly */
DBG_INFO(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ);
gtype="";
gn=n;
}
else {
DBG_VERBOUS(GWEN_LOGDOMAIN, "<%s> tag is of type \"%s\"", typ, gtype);
gn=GWEN_MsgEngine_GetGroup(e, n, nodePath, typ,
gversion, gtype);
if (!gn) {
DBG_INFO(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ);
return -1;
}
}

gname=0;
gcfg=0;
if (gr) {
gname=GWEN_XMLNode_GetProperty(n, "name",0);
if (gname) {
DBG_VERBOUS(GWEN_LOGDOMAIN, "Group \"%s\" using special data", gname);
gcfg=GWEN_DB_GetFirstGroup(gr);
}
else {
DBG_DEBUG(GWEN_LOGDOMAIN, "Unnamed group, using basic data");
gcfg=gr;
}
}

/* write group as often as needed */
for (loopNr=0; loopNr<maxnum; loopNr++) {
int rv;
int groupIsEmpty;

groupIsEmpty=0;
posBeforeGroup=GWEN_Buffer_GetPos(gbuf);

/* find next matching group */
if (gname) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Finding next group named \"%s\"", gname);
while(gcfg) {
if (strcasecmp(GWEN_DB_GroupName(gcfg), gname)==0)
break;
gcfg=GWEN_DB_GetNextGroup(gcfg);
if (gcfg==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "No group found");
if (loopNr>=minnum)
groupIsEmpty=1;
}
} /* while */
}

if (!groupIsEmpty) {
int dive;

/* write delimiter, if needed */
if (!isFirstElement && delimiter) {
int j;

DBG_VERBOUS(GWEN_LOGDOMAIN, "Appending %d delimiters", omittedElements+1);
for (j=0; j<omittedElements+1; j++) {
if (GWEN_Buffer_AppendByte(gbuf, delimiter)) {
return -1;
}
}
omittedElements=0;
}
else
isFirstElement=0;

/* write group */

if (GWEN_XMLNode_Path_Dive(nodePath, n)) {
DBG_INFO(GWEN_LOGDOMAIN, "Called from here");
return -1;
}
if (n==gn)
dive=1;
else {
if (GWEN_XMLNode_Path_Dive(nodePath, gn)) {
DBG_INFO(GWEN_LOGDOMAIN, "Called from here");
return -1;
}
dive=2;
}
rv=GWEN_MsgEngine__WriteGroup(e,
gbuf,
gn,
n,
gcfg,
loopNr>=minnum || groupIsOptional,
nodePath);
GWEN_XMLNode_Path_Surface(nodePath);
if (dive==2)
GWEN_XMLNode_Path_Surface(nodePath);
if (rv==-1){
DBG_INFO(GWEN_LOGDOMAIN, "Could not write group \"%s\"", gtype);
if (gn) {
DBG_INFO(GWEN_LOGDOMAIN, "Node is:");
GWEN_XMLNode_Dump(gn, stderr, 1);
}
if (n) {
DBG_INFO(GWEN_LOGDOMAIN, "Referring node is:");
GWEN_XMLNode_Dump(n, stderr, 1);
}
if (gr) {
DBG_INFO(GWEN_LOGDOMAIN, "Data is:");
GWEN_DB_Dump(gr, stderr, 1);
}
return -1;
}
else if (rv==0) {
hasEntries=1;
}
else
groupIsEmpty=1;
}

if (groupIsEmpty) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Empty Group");
GWEN_Buffer_SetPos(gbuf, posBeforeGroup);
GWEN_Buffer_Crop(gbuf, 0, posBeforeGroup);

if (loopNr>=minnum) {
DBG_DEBUG(GWEN_LOGDOMAIN, "No data for group \"%s[%d]\", omitting",
gname, loopNr);
if (strcasecmp(addEmptyMode, "max")==0) {
DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding max empty");
omittedElements+=(maxnum-loopNr);
}
else if (strcasecmp(addEmptyMode, "min")==0) {
DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding min empty");
if (loopNr<minnum)
omittedElements+=(minnum-loopNr);
}
else if (strcasecmp(addEmptyMode, "one")==0) {
if (loopNr==0)
omittedElements++;
}
else if (strcasecmp(addEmptyMode, "none")==0) {
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "Unknown addemptymode \"%s\"",
addEmptyMode);
return -1;
}
break;
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "No data for group \"%s[%d]\"",
gname, loopNr);
return -1;
}
} /* if empty group */
/* use next group next time if any */
if (gcfg)
gcfg=GWEN_DB_GetNextGroup(gcfg);
} /* for */
}
}
else if (t==GWEN_XMLNodeTypeData) {
}
else {
DBG_DEBUG(GWEN_LOGDOMAIN, "Unhandled node type %d", t);
}
n=GWEN_XMLNode_Next(n);
} /* while */

/* write terminating character, if any */
if (terminator) {
if (GWEN_Buffer_AppendByte(gbuf, terminator)) {
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
return -1;
}
}

if (!hasEntries) {
DBG_INFO(GWEN_LOGDOMAIN, "No entries in node");
}
return hasEntries?0:1;
}



int GWEN_MsgEngine_CreateMessageFromNode(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node,
GWEN_BUFFER *gbuf,
GWEN_DB_NODE *msgData){
GWEN_XMLNODE_PATH *np;
int rv;

assert(e);
assert(node);
assert(msgData);

np=GWEN_XMLNode_Path_new();
GWEN_XMLNode_Path_Dive(np, node);
rv=GWEN_MsgEngine__WriteGroup(e,
gbuf,
node,
0,
msgData,
0,
np);
GWEN_XMLNode_Path_free(np);
if (rv){
const char *p;

p=GWEN_XMLNode_GetData(node);
if (p) {
DBG_INFO(GWEN_LOGDOMAIN, "Error writing group \"%s\"", p);
}
else {
DBG_INFO(GWEN_LOGDOMAIN, "Error writing group");
}
return -1;
}

return 0;
}



int GWEN_MsgEngine_CreateMessage(GWEN_MSGENGINE *e,
const char *msgName,
int msgVersion,
GWEN_BUFFER *gbuf,
GWEN_DB_NODE *msgData) {
GWEN_XMLNODE *group;

group=GWEN_MsgEngine_FindGroupByProperty(e, "id", msgVersion, msgName);
if (!group) {
DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" not found\n", msgName);
return -1;
}
return GWEN_MsgEngine_CreateMessageFromNode(e,
group,
gbuf,
msgData);
}



int GWEN_MsgEngine_AddDefinitions(GWEN_MSGENGINE *e,
GWEN_XMLNODE *node) {
GWEN_XMLNODE *nsrc, *ndst;

assert(e);
assert(node);

if (!e->defs) {
e->defs=GWEN_XMLNode_dup(node);
e->ownDefs=1;
return 0;
}

nsrc=GWEN_XMLNode_GetChild(node);
while(nsrc) {
if (GWEN_XMLNode_GetType(nsrc)==GWEN_XMLNodeTypeTag) {
ndst=GWEN_XMLNode_FindNode(e->defs, GWEN_XMLNodeTypeTag,
GWEN_XMLNode_GetData(nsrc));
if (ndst) {
GWEN_XMLNODE *n;

n=GWEN_XMLNode_GetChild(nsrc);
while (n) {
GWEN_XMLNODE *newNode;

DBG_DEBUG(GWEN_LOGDOMAIN, "Adding node \"%s\"", GWEN_XMLNode_GetData(n));
newNode=GWEN_XMLNode_dup(n);
GWEN_XMLNode_AddChild(ndst, newNode);
n=GWEN_XMLNode_Next(n);
} /* while n */
}
else {
GWEN_XMLNODE *newNode;

DBG_DEBUG(GWEN_LOGDOMAIN, "Adding branch \"%s\"", GWEN_XMLNode_GetData(nsrc));
newNode=GWEN_XMLNode_dup(nsrc);
GWEN_XMLNode_AddChild(e->defs, newNode);
}
} /* if TAG */
nsrc=GWEN_XMLNode_Next(nsrc);
} /* while */

return 0;
}



int GWEN_MsgEngine__ShowElement(GWEN_MSGENGINE *e,
const char *path,
GWEN_XMLNODE *node,
GWEN_STRINGLIST *sl,
GWEN_TYPE_UINT32 flags) {
const char *name;
const char *type;
const char *npath;
unsigned int minsize;
unsigned int maxsize;
unsigned int minnum;
unsigned int maxnum;
int j;
int isSet;
char nbuffer[256];
GWEN_STRINGLISTENTRY *en;

/* get type */
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");

/* get some sizes */
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1"));
maxnum=atoi(GWEN_XMLNode_GetProperty(node, "maxnum","1"));

npath="";
isSet=0;

/* get name */
name=GWEN_XMLNode_GetProperty(node, "name", 0);
if (path==0)
path="";

if (name) {
/* get value of a config variable */
if (strlen(path)+strlen(name)+10>=sizeof(nbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
if (*path)
sprintf(nbuffer, "%s/%s", path, name);
else
sprintf(nbuffer, "%s", name);
npath=nbuffer;
}

en=GWEN_StringList_FirstEntry(sl);
while(en) {
if (GWEN_StringListEntry_Data(en))
if (strcasecmp(GWEN_StringListEntry_Data(en), npath)==0) {
isSet=1;
break;
}
en=GWEN_StringListEntry_Next(en);
} /* while */

if (isSet && (flags & GWEN_MSGENGINE_SHOW_FLAGS_NOSET))
return 0;

fprintf(stdout, " %s",
npath);
j=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(npath);
if (j>0) {
int i;

for (i=0; i<j; i++)
fprintf(stdout, " ");
}
fprintf(stdout, "| %s", type);
j=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(type);
if (j>0) {
int i;

for (i=0; i<j; i++)
fprintf(stdout, " ");
}
fprintf(stdout, "| %4d-%4d", minsize, maxsize);
fprintf(stdout," | %3d ", maxnum);
fprintf(stdout," |");
if (minnum==0)
fprintf(stdout," optvar");
if (flags & GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL)
fprintf(stdout," optgrp");

if (isSet) {
fprintf(stdout," set");
}

fprintf(stdout,"\n");

return 0;
}



int GWEN_MsgEngine__ShowGroup(GWEN_MSGENGINE *e,
const char *path,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_STRINGLIST *sl,
GWEN_TYPE_UINT32 flags) {
GWEN_XMLNODE *n;
int isFirstElement;
int omittedElements;
int rv;

/* setup data */
n=GWEN_XMLNode_GetChild(node);

if (path==0)
path="";
if (*path=='/')
path++;

while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *p;

p=GWEN_XMLNode_GetData(n);
assert(p);
DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s",p);
if (strcasecmp(p, "VALUES")==0)
break;
} /* if tag */
n=GWEN_XMLNode_Next(n);
} /* while */

if (n) {
DBG_DEBUG(GWEN_LOGDOMAIN, "<preset> found");
/* <preset> found, handle all values */
n=GWEN_XMLNode_GetChild(n);
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *p;

p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, "VALUE")==0) {
const char *pname;
const char *pvalue;

pname=GWEN_XMLNode_GetProperty(n, "path", 0);
if (pname) {
GWEN_XMLNODE *dn;

/* path found, find data */
dn=GWEN_XMLNode_GetChild(n);
while (dn) {
if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) {
pvalue=GWEN_XMLNode_GetData(dn);
if (pvalue) {
char pbuffer[256];

/* check whether the value is a property */
p=pvalue;
while (*p && isspace((int)*p))
p++;
if (strlen(path)+strlen(pname)+2>sizeof(pbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
if (*path)
sprintf(pbuffer, "%s/%s", path, pname);
else
sprintf(pbuffer, "%s", pname);
GWEN_StringList_AppendString(sl,
pbuffer,
0,
1);
}
break;
}
dn=GWEN_XMLNode_Next(dn);
} /* while dn */
} /* if path given */
} /* if VALUE tag */
} /* if TAG */
n=GWEN_XMLNode_Next(n);
} /* while */
} /* if <preset> found */

/* now handle all child entries */
n=GWEN_XMLNode_GetChild(node);
isFirstElement=1;
omittedElements=0;
while(n) {
int t;
unsigned int minnum;
unsigned int maxnum;
int gversion;
const char *addEmptyMode;
unsigned int loopNr;
unsigned int lflags;

minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one");

lflags=flags;

DBG_DEBUG(GWEN_LOGDOMAIN, "Omitted elements: %d", omittedElements);
t=GWEN_XMLNode_GetType(n);
if (t==GWEN_XMLNodeTypeTag) {
const char *typ;

typ=GWEN_XMLNode_GetData(n);
if (typ==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)");
return -1;
}
if (strcasecmp(typ, "ELEM")==0) {
/* element tag found */

/* write element as often as needed */
rv=GWEN_MsgEngine__ShowElement(e,
path,
n,
sl,
lflags);
if (rv==-1)
return -1;
else {
isFirstElement=0;
omittedElements=0;
}
}
else if (strcasecmp(typ, "VALUES")==0) {
}
else if (strcasecmp(typ, "DESCR")==0) {
}
else {
/* group tag found */
GWEN_XMLNODE *gn;
const char *gname;
const char *gtype;

if (minnum==0)
lflags|=GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL;

gtype=GWEN_XMLNode_GetProperty(n, "type",0);
if (!gtype) {
/* no "type" property, so use this group directly */
DBG_DEBUG(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ);
gtype="";
gn=n;
}
else {
gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype);
if (!gn) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ);
return -1;
}
}

/* write group as often as needed */
for (loopNr=0; loopNr<maxnum; loopNr++) {
/* find group */
char pbuffer[256];
const char *npath;

/* get configuration */
gname=GWEN_XMLNode_GetProperty(n, "name",0);
if (gname) {
if (loopNr==0) {
if (strlen(path)+strlen(gname)+1>sizeof(pbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
sprintf(pbuffer, "%s/%s", path, gname);
npath=pbuffer;
}
else {
/* this is not the first one, so create new name */
if (strlen(path)+strlen(gname)+10>sizeof(pbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
if (*path)
sprintf(pbuffer, "%s/%s%d", path, gname, loopNr);
else
sprintf(pbuffer, "%s%d", gname, loopNr);
/* get the value of the given var */
npath=pbuffer;
}
} /* if name given */
else
npath=path;

/* write group */
if (GWEN_MsgEngine__ShowGroup(e,
npath,
gn,
n,
sl,
lflags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not show group \"%s\"", gtype);
return -1;
}
} /* for */
}
}
n=GWEN_XMLNode_Next(n);
} /* while */

return 0;
}



int GWEN_MsgEngine_ShowMessage(GWEN_MSGENGINE *e,
const char *typ,
const char *msgName,
int msgVersion,
GWEN_TYPE_UINT32 flags) {
GWEN_XMLNODE *group;
GWEN_STRINGLIST *sl;
int i, j;
const char *p;

sl=GWEN_StringList_new();

fprintf(stdout, "Message \"%s\" version %d\n",
msgName, msgVersion);
for (i=0; i<76; i++)
fprintf(stdout, "=");
fprintf(stdout, "\n");
p=" Variable";
fprintf(stdout, "%s", p);
i=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(p);
for (j=0; j<i; j++)
fprintf(stdout," ");

fprintf(stdout," |");
p=" Type";
fprintf(stdout, "%s", p);
i=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(p);
for (j=0; j<i; j++)
fprintf(stdout," ");

fprintf(stdout," | Size | Num | Flags\n");
for (i=0; i<76; i++)
fprintf(stdout, "-");
fprintf(stdout, "\n");

group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", msgVersion, msgName);
if (!group) {
DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" not found\n", msgName);
GWEN_StringList_free(sl);
return -1;
}

if (GWEN_MsgEngine__ShowGroup(e,
"",
group,
0,
sl,
flags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Error showing group \"%s\"", msgName);
GWEN_StringList_free(sl);
return -1;
}

GWEN_StringList_free(sl);

return 0;
}



int GWEN_MsgEngine__ListElement(GWEN_MSGENGINE *e,
const char *path,
GWEN_XMLNODE *node,
GWEN_STRINGLIST *sl,
GWEN_XMLNODE *listNode,
GWEN_TYPE_UINT32 flags) {
const char *name;
const char *type;
const char *npath;
int isSet;
char nbuffer[256];
GWEN_STRINGLISTENTRY *en;
GWEN_XMLNODE *nn;

/* get type */
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");

npath="";
isSet=0;

/* get name */
name=GWEN_XMLNode_GetProperty(node, "name", 0);
if (path==0)
path="";

if (name) {
/* get value of a config variable */
if (strlen(path)+strlen(name)+10>=sizeof(nbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
if (*path)
sprintf(nbuffer, "%s/%s", path, name);
else
sprintf(nbuffer, "%s", name);
npath=nbuffer;
}

en=GWEN_StringList_FirstEntry(sl);
while(en) {
if (GWEN_StringListEntry_Data(en))
if (strcasecmp(GWEN_StringListEntry_Data(en), npath)==0) {
isSet=1;
break;
}
en=GWEN_StringListEntry_Next(en);
} /* while */

if (isSet && (flags & GWEN_MSGENGINE_SHOW_FLAGS_NOSET))
return 0;

nn=GWEN_XMLNode_dup(node);
if (isSet)
GWEN_XMLNode_SetProperty(nn, "GWEN_set", "1");
GWEN_XMLNode_SetProperty(nn, "GWEN_path", npath);
GWEN_XMLNode_AddChild(listNode, nn);

return 0;
}



int GWEN_MsgEngine__ListGroup(GWEN_MSGENGINE *e,
const char *path,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_STRINGLIST *sl,
GWEN_XMLNODE *listNode,
GWEN_TYPE_UINT32 flags) {
GWEN_XMLNODE *n;
int rv;

/* setup data */
n=GWEN_XMLNode_GetChild(node);

if (path==0)
path="";
if (*path=='/')
path++;

while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *p;

p=GWEN_XMLNode_GetData(n);
assert(p);
DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s",p);
if (strcasecmp(p, "VALUES")==0)
break;
} /* if tag */
n=GWEN_XMLNode_Next(n);
} /* while */

if (n) {
DBG_DEBUG(GWEN_LOGDOMAIN, "<values> found");
/* <values> found, handle all values */
n=GWEN_XMLNode_GetChild(n);
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *p;

p=GWEN_XMLNode_GetData(n);
assert(p);
if (strcasecmp(p, "VALUE")==0) {
const char *pname;
const char *pvalue;

pname=GWEN_XMLNode_GetProperty(n, "path", 0);
if (pname) {
GWEN_XMLNODE *dn;

/* path found, find data */
dn=GWEN_XMLNode_GetChild(n);
while (dn) {
if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) {
pvalue=GWEN_XMLNode_GetData(dn);
if (pvalue) {
char pbuffer[256];

/* check whether the value is a property */
p=pvalue;
while (*p && isspace((int)*p))
p++;
if (strlen(path)+strlen(pname)+2>sizeof(pbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}
if (*path)
sprintf(pbuffer, "%s/%s", path, pname);
else
sprintf(pbuffer, "%s", pname);
DBG_INFO(GWEN_LOGDOMAIN, "Found preset value for %s", pbuffer);
GWEN_StringList_AppendString(sl,
pbuffer,
0,
1);
}
break;
}
dn=GWEN_XMLNode_Next(dn);
} /* while dn */
} /* if path given */
} /* if VALUE tag */
} /* if TAG */
n=GWEN_XMLNode_Next(n);
} /* while */
} /* if <values> found */

/* now handle all child entries */
n=GWEN_XMLNode_GetChild(node);
while(n) {
int t;
int gversion;
unsigned int lflags;

gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
lflags=flags;

t=GWEN_XMLNode_GetType(n);
if (t==GWEN_XMLNodeTypeTag) {
const char *typ;

typ=GWEN_XMLNode_GetData(n);
if (typ==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)");
return -1;
}
if (strcasecmp(typ, "ELEM")==0) {
/* element tag found */

/* list element */
rv=GWEN_MsgEngine__ListElement(e,
path,
n,
sl,
listNode,
lflags);
if (rv==-1)
return -1;
}
else if (strcasecmp(typ, "VALUES")==0) {
}
else if (strcasecmp(typ, "DESCR")==0) {
}
else {
/* group tag found */
GWEN_XMLNODE *gn;
GWEN_XMLNODE *nn;
const char *gname;
const char *gtype;
char pbuffer[256];
const char *npath;

gtype=GWEN_XMLNode_GetProperty(n, "type",0);
if (!gtype) {
/* no "type" property, so use this group directly */
DBG_DEBUG(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ);
gtype="";
gn=n;
}
else {
gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype);
if (!gn) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ);
return -1;
}
}

/* get configuration */
gname=GWEN_XMLNode_GetProperty(n, "name",0);
if (gname) {
if (strlen(path)+strlen(gname)+1>sizeof(pbuffer)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small");
return -1;
}

if (*path)
sprintf(pbuffer, "%s/%s", path, gname);
else
sprintf(pbuffer, "%s", gname);
npath=pbuffer;
} /* if name given */
else
npath=path;

nn=GWEN_XMLNode_dup(n);
if (gn!=n)
GWEN_XMLNode_CopyProperties(nn, gn, 0);
GWEN_XMLNode_SetProperty(nn, "GWEN_path", npath);
GWEN_XMLNode_AddChild(listNode, nn);

/* write group */
if (GWEN_MsgEngine__ListGroup(e,
npath,
gn,
n,
sl,
nn,
lflags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not list group \"%s\"", gtype);
return -1;
}
}
}
n=GWEN_XMLNode_Next(n);
} /* while */

return 0;
}



GWEN_XMLNODE *GWEN_MsgEngine_ListMessage(GWEN_MSGENGINE *e,
const char *typ,
const char *msgName,
int msgVersion,
GWEN_TYPE_UINT32 flags) {
GWEN_XMLNODE *group;
GWEN_STRINGLIST *sl;
GWEN_XMLNODE *listNode;

group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", msgVersion, msgName);
if (!group)
group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "code",
msgVersion, msgName);
if (!group) {
DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" (version %d) not found\n",
msgName, msgVersion);
return 0;
}

sl=GWEN_StringList_new();
/* copy group, but remove all children (we only want the properties) */
listNode=GWEN_XMLNode_dup(group);
GWEN_XMLNode_RemoveChildren(listNode);

if (GWEN_MsgEngine__ListGroup(e,
"",
group,
0,
sl,
listNode,
flags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Error showing group \"%s\"", msgName);
GWEN_StringList_free(sl);
GWEN_XMLNode_free(listNode);
return 0;
}

GWEN_StringList_free(sl);

return listNode;
}







int GWEN_MsgEngine__ReadValue(GWEN_MSGENGINE *e,
GWEN_BUFFER *msgbuf,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_BUFFER *vbuf,
const char *delimiters,
GWEN_TYPE_UINT32 flags) {
unsigned int minsize;
unsigned int maxsize;
unsigned int minnum;
GWEN_MSGENGINE_TRUSTLEVEL trustLevel;
unsigned int posInMsg;
const char *type;
int rv;
unsigned int realSize;

/* get some sizes */
posInMsg=GWEN_Buffer_GetPos(msgbuf);
realSize=0;
minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0"));
maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0"));
minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1"));
type=GWEN_XMLNode_GetProperty(node, "type","ASCII");

rv=1;
if (e->typeReadPtr) {
rv=e->typeReadPtr(e,
msgbuf,
node,
vbuf,
'\\',
delimiters);
}
if (rv==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "External type reading failed on type \"%s\"", type);
return -1;
}
else if (rv==1) {
if (strcasecmp(type, "bin")==0) {
if (GWEN_Buffer_GetBytesLeft(msgbuf)==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (@num@ expected)");
return -1;
}
else {
char lbuffer[16];
int c;
char *p;
int l;

p=lbuffer;
c=GWEN_Buffer_ReadByte(msgbuf);
if (c!='@') {
DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected");
return -1;
}

c=0;
while(GWEN_Buffer_GetBytesLeft(msgbuf)>0) {
c=GWEN_Buffer_ReadByte(msgbuf);
if (c==-1) {
DBG_ERROR(GWEN_LOGDOMAIN, "\"@\" expected");
return -1;
}
if (c=='@')
break;
*p=(char)c;
p++;
} /* while */
*p=0;
if (c!='@') {
DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected");
return -1;
}
if (sscanf(lbuffer, "%d", &l)!=1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad number format");
return -1;
}
DBG_DEBUG(GWEN_LOGDOMAIN, "Reading binary: %d bytes from pos %d (msgsize=%d)",
l,
GWEN_Buffer_GetPos(msgbuf),
GWEN_Buffer_GetUsedBytes(msgbuf));
if (GWEN_Buffer_GetBytesLeft(msgbuf) < (unsigned) l) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (binary beyond end)");
return -1;
}
if (GWEN_Buffer_AppendBytes(vbuf,
GWEN_Buffer_GetPosPointer(msgbuf),
l)) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Called from here");
return -1;
}
GWEN_Buffer_IncrementPos(msgbuf,l);
}
} /* if bin */
else {
/* type is not bin */
int lastWasEscape;
int isEscaped;

isEscaped=0;
lastWasEscape=0;

while(GWEN_Buffer_GetBytesLeft(msgbuf)) {
int c;

c=GWEN_Buffer_ReadByte(msgbuf);
if (lastWasEscape) {
lastWasEscape=0;
isEscaped=1;
}
else {
isEscaped=0;
if (c==e->escapeChar) {
lastWasEscape=1;
c=-1;
}
}
if (c!=-1) {
if (!isEscaped && (c && strchr(delimiters, c)!=0)) {
/* delimiter found, step back */
GWEN_Buffer_DecrementPos(msgbuf,1);
break;
}
else {
if (c=='\\' || iscntrl(c)) {
DBG_WARN(GWEN_LOGDOMAIN,
"Found a bad character (%02x) in type \"%s\", "
"converting to SPACE",
(unsigned int)c,
type);
c=' ';
}
if (GWEN_Buffer_AppendByte(vbuf, c)) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Called from here");
return -1;
}
}
}
} /* while */
} /* if !bin */
} /* if type not external */
else {
DBG_DEBUG(GWEN_LOGDOMAIN, "Type \"%s\" is external (read)", type);
}

realSize=GWEN_Buffer_GetUsedBytes(vbuf);

/* check the value */
if (realSize==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Datasize is 0");
if (minnum==0) {
DBG_DEBUG(GWEN_LOGDOMAIN, "... but thats ok");
/* value is empty, and that is allowed */
return 1;
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "Value missing");
GWEN_XMLNode_Dump(node, stderr, 1);
return -1;
}
}

/* check minimum size */
if (minsize!=0 && realSize<minsize) {
DBG_INFO(GWEN_LOGDOMAIN, "Value too short (%d<%d).",
realSize,
minsize);
return -1;
}

/* check maximum size */
if (maxsize!=0 && realSize>maxsize) {
DBG_INFO(GWEN_LOGDOMAIN, "Value too long (%d>%d).",
realSize, maxsize);
return -1;
}

if (flags & GWEN_MSGENGINE_READ_FLAGS_TRUSTINFO) {
/* add trust data to msgEngine */
const char *descr;

trustLevel=GWEN_MsgEngine_GetHighestTrustLevel(node, rnode);
if (trustLevel) {
unsigned int ustart;

ustart=GWEN_Buffer_GetPos(msgbuf)-realSize;
descr=GWEN_XMLNode_GetProperty(node, "name",0);
if (GWEN_MsgEngine_AddTrustInfo(e,
GWEN_Buffer_GetStart(vbuf),
realSize,
descr,
trustLevel,
ustart)) {
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
return -1;
}
}
}

return 0;
}



int GWEN_MsgEngine__ReadGroup(GWEN_MSGENGINE *e,
GWEN_BUFFER *msgbuf,
GWEN_XMLNODE *node,
GWEN_XMLNODE *rnode,
GWEN_DB_NODE *gr,
const char *delimiters,
GWEN_TYPE_UINT32 flags) {
unsigned int minsize;
unsigned int maxsize;
unsigned int minnum;
unsigned int maxnum;
const char *name;
const char *p;
char delimiter;
char terminator;
GWEN_XMLNODE *n;
int abortLoop;

/* get some settings */
if (rnode) {
/* get delimiter */
p=GWEN_XMLNode_GetProperty(rnode,
"delimiter",
GWEN_XMLNode_GetProperty(node,
"delimiter",
""));
delimiter=*p;

/* get terminating char, if any */
p=GWEN_XMLNode_GetProperty(rnode,
"terminator",
GWEN_XMLNode_GetProperty(node,
"terminator",
""));
terminator=*p;
}
else {
/* get delimiter */
p=GWEN_XMLNode_GetProperty(node,
"delimiter",
"");
delimiter=*p;

/* get terminating char, if any */
p=GWEN_XMLNode_GetProperty(node, "terminator","");
terminator=*p;
}

DBG_DEBUG(GWEN_LOGDOMAIN, "Delimiters are \"%s\" and \"%c\"",
delimiters, delimiter);

n=GWEN_XMLNode_GetChild(node);
while (n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
const char *type;

if (GWEN_Buffer_GetBytesLeft(msgbuf)==0)
break;

type=GWEN_XMLNode_GetData(n);

/*
DBG_NOTICE(GWEN_LOGDOMAIN, "Reading group from here :");
GWEN_Text_DumpString(GWEN_Buffer_GetStart(msgbuf)+
GWEN_Buffer_GetPos(msgbuf),
GWEN_Buffer_GetUsedBytes(msgbuf)-
GWEN_Buffer_GetPos(msgbuf),
stderr, 3);
*/
if (strcasecmp(type, "ELEM")==0) {
unsigned int loopNr;

/* get some sizes */
minsize=atoi(GWEN_XMLNode_GetProperty(n, "minsize","0"));
maxsize=atoi(GWEN_XMLNode_GetProperty(n, "maxsize","0"));
minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
name=GWEN_XMLNode_GetProperty(n, "name", 0);

loopNr=0;
abortLoop=0;
while((maxnum==0 || loopNr<maxnum) && !abortLoop) {
int c;

DBG_DEBUG(GWEN_LOGDOMAIN, "Reading %s", name);
if (GWEN_Buffer_GetBytesLeft(msgbuf)==0)
break;
c=GWEN_Buffer_PeekByte(msgbuf);
if (c==-1) {
DBG_DEBUG(GWEN_LOGDOMAIN, "called from here");
return -1;
}

DBG_VERBOUS(GWEN_LOGDOMAIN,
"Checking delimiter "
"(whether \"%c\" is in \"%s\")",
c, delimiters);
if (c && strchr(delimiters, c)) {
abortLoop=1;
DBG_VERBOUS(GWEN_LOGDOMAIN, "Found delimiter (\"%02x\" is in \"%s\")",
c, delimiters);
} /* if delimiter found */
else {
/* current char is not a delimiter */
if (name==0) {
}
else {
/* name is given */
int rv;
const char *dtype;
GWEN_BUFFER *vbuf;

vbuf=GWEN_Buffer_new(0,
GWEN_MSGENGINE_MAX_VALUE_LEN,
0,0);
/*DBG_DEBUG(GWEN_LOGDOMAIN, "Reading value from here:\n");
GWEN_Text_DumpString(GWEN_Buffer_GetPosPointer(msgbuf),
GWEN_Buffer_GetBytesLeft(msgbuf),
stderr, 1);*/

rv=GWEN_MsgEngine__ReadValue(e,
msgbuf,
n,
rnode,
vbuf,
":+'",
flags);
if (rv==1) {
DBG_INFO(GWEN_LOGDOMAIN, "Empty value");
}
else if (rv==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "Error parsing node \"%s\" (%s)",
name,
type);
GWEN_Buffer_free(vbuf);
return -1;
}

GWEN_Buffer_Rewind(vbuf);

/* special handling for binary data */
dtype=GWEN_XMLNode_GetProperty(n, "type", "");
if (GWEN_MsgEngine__IsBinTyp(e, dtype)) {
if (atoi(GWEN_XMLNode_GetProperty(n, "readbin", "1")) &&
e->binTypeReadPtr) {
rv=e->binTypeReadPtr(e, n, gr, vbuf);
}
else
rv=1;
if (rv==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "Called from here");
GWEN_Buffer_free(vbuf);
return -1;
}
else if (rv==1) {
/* bin type not handled, so handle it myself */
if (GWEN_DB_SetBinValue(gr,
GWEN_DB_FLAGS_DEFAULT,
name,
GWEN_Buffer_GetStart(vbuf),
GWEN_Buffer_GetUsedBytes(vbuf))) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not set value for \"%s\"", name);
GWEN_Buffer_free(vbuf);
return -1;
}
}
} /* if type is bin */
else if (GWEN_MsgEngine__IsIntTyp(e, dtype)) {
int z;

if (1!=sscanf(GWEN_Buffer_GetStart(vbuf), "%d", &z)) {
DBG_INFO(GWEN_LOGDOMAIN, "Value for \"%s\" is not an integer",
name);
return -1;
}
if (GWEN_DB_SetIntValue(gr,
GWEN_DB_FLAGS_DEFAULT,
name, z)) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not set int value for \"%s\"", name);
return -1;
}
} /* if type is int */
else {
DBG_DEBUG(GWEN_LOGDOMAIN, "Value is \"%s\"",
GWEN_Buffer_GetStart(vbuf));
if (GWEN_DB_SetCharValue(gr,
GWEN_DB_FLAGS_DEFAULT,
name,
GWEN_Buffer_GetStart(vbuf))){
DBG_INFO(GWEN_LOGDOMAIN, "Could not set value for \"%s\"", name);
return -1;
}
} /* if !bin */

GWEN_Buffer_free(vbuf);
} /* if name is given */
} /* if current char is not a delimiter */

if (GWEN_Buffer_GetBytesLeft(msgbuf)) {
if (delimiter) {
if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) {
GWEN_Buffer_IncrementPos(msgbuf,1);
}
}
}
loopNr++;
} /* while */
if (loopNr<minnum) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (too few ELEM repeats)");
GWEN_XMLNode_Dump(n, stderr, 2);
return -1;
}
n=GWEN_XMLNode_Next(n);
} /* if ELEM */
else if (strcasecmp(type, "VALUES")==0) {
n=GWEN_XMLNode_Next(n);
}
else if (strcasecmp(type, "DESCR")==0) {
n=GWEN_XMLNode_Next(n);
}
else {
/* group tag found */
GWEN_XMLNODE *gn;
GWEN_DB_NODE *gcfg;
const char *gname;
const char *gtype;
unsigned int gversion;
unsigned int loopNr;

minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1"));
maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1"));
gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0"));
gtype=GWEN_XMLNode_GetProperty(n, "type",0);
if (!gtype) {
/* no "type" property, so use this group directly */
DBG_INFO(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", type);
gtype="";
gn=n;
}
else {
gn=GWEN_MsgEngine_FindNodeByProperty(e, type, "id",
gversion, gtype);
if (!gn) {
DBG_INFO(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", type);
return -1;
}
}

/* get configuration */
loopNr=0;
abortLoop=0;
while((maxnum==0 || loopNr<maxnum) && !abortLoop) {
int c;

DBG_DEBUG(GWEN_LOGDOMAIN, "Reading group type %s", gtype);
if (GWEN_Buffer_GetBytesLeft(msgbuf)==0)
break;
c=GWEN_Buffer_PeekByte(msgbuf);
if (c && strchr(delimiters, c)) {
abortLoop=1;
}
else {
gname=GWEN_XMLNode_GetProperty(n, "name",0);
if (gname) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Creating group \"%s\"", gname);
gcfg=GWEN_DB_GetGroup(gr,
GWEN_PATH_FLAGS_CREATE_GROUP,
gname);
if (!gcfg) {
DBG_ERROR(GWEN_LOGDOMAIN, "Could not select group \"%s\"",
gname);
return -1;
}
DBG_DEBUG(GWEN_LOGDOMAIN, "Created group \"%s\"", gname);
} /* if name given */
else
gcfg=gr;

/* read group */
DBG_DEBUG(GWEN_LOGDOMAIN, "Reading group \"%s\"", gname);
if (GWEN_MsgEngine__ReadGroup(e,
msgbuf,
gn,
n,
gcfg,
delimiters,
flags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Could not read group \"%s\"", gtype);
return -1;
}
}
if (GWEN_Buffer_GetBytesLeft(msgbuf)) {
if (delimiter) {
if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) {
GWEN_Buffer_IncrementPos(msgbuf, 1);
}
}
}
loopNr++;
} /* while */
if (loopNr<minnum) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (too few group repeats)");
return -1;
}
n=GWEN_XMLNode_Next(n);
} /* if GROUP */
} /* if TAG */
else {
n=GWEN_XMLNode_Next(n);
}
} /* while */

/* check whether there still are nodes which have not been read */
while(n) {
if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) {
if (strcasecmp(GWEN_XMLNode_GetData(n), "ELEM")==0 ||
strcasecmp(GWEN_XMLNode_GetData(n), "GROUP")==0) {
unsigned int i;

i=atoi(GWEN_XMLNode_GetProperty(n, "minnum", "1"));
if (i) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (still tags to parse)");
GWEN_XMLNode_Dump(n, stderr, 2);
return -1;
}
}
}
n=GWEN_XMLNode_Next(n);
}


if (terminator) {
/* skip terminator */
if (GWEN_Buffer_GetBytesLeft(msgbuf)) {
if (GWEN_Buffer_PeekByte(msgbuf)==terminator) {
GWEN_Buffer_IncrementPos(msgbuf, 1);
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "Terminating character missing (pos=%d)",
GWEN_Buffer_GetPos(msgbuf));
GWEN_XMLNode_Dump(node, stderr, 1);
return -1;
}
}
else {
DBG_ERROR(GWEN_LOGDOMAIN, "Terminating character missing");
return -1;
}
}

return 0;
}



int GWEN_MsgEngine_ParseMessage(GWEN_MSGENGINE *e,
GWEN_XMLNODE *group,
GWEN_BUFFER *msgbuf,
GWEN_DB_NODE *msgData,
GWEN_TYPE_UINT32 flags){

if (GWEN_MsgEngine__ReadGroup(e,
msgbuf,
group,
0,
msgData,
e->delimiters,
flags)) {
DBG_INFO(GWEN_LOGDOMAIN, "Error reading group");
return -1;
}

return 0;
}



int GWEN_MsgEngine_SetValue(GWEN_MSGENGINE *e,
const char *path,
const char *value){
GWEN_DB_NODE *globalValues;

assert(e);
globalValues=GWEN_MsgEngine__GetGlobalValues(e);
assert(globalValues);
return GWEN_DB_SetCharValue(globalValues,
GWEN_DB_FLAGS_DEFAULT |
GWEN_DB_FLAGS_OVERWRITE_VARS,
path, value);
}



int GWEN_MsgEngine_SetIntValue(GWEN_MSGENGINE *e,
const char *path,
int value){
GWEN_DB_NODE *globalValues;

assert(e);
globalValues=GWEN_MsgEngine__GetGlobalValues(e);
assert(globalValues);
return GWEN_DB_SetIntValue(globalValues,
GWEN_DB_FLAGS_DEFAULT |
GWEN_DB_FLAGS_OVERWRITE_VARS,
path, value);
}



const char *GWEN_MsgEngine_GetValue(GWEN_MSGENGINE *e,
const char *path,
const char *defValue){
GWEN_DB_NODE *globalValues;

assert(e);
globalValues=GWEN_MsgEngine__GetGlobalValues(e);
assert(globalValues);
return GWEN_DB_GetCharValue(globalValues,
path, 0, defValue);
}



int GWEN_MsgEngine_GetIntValue(GWEN_MSGENGINE *e,
const char *path,
int defValue){
GWEN_DB_NODE *globalValues;

assert(e);
globalValues=GWEN_MsgEngine__GetGlobalValues(e);
assert(globalValues);
return GWEN_DB_GetIntValue(globalValues,
path, 0, defValue);
}



/* --------------------------------------------------------------- FUNCTION */
int GWEN_MsgEngine_SkipSegment(GWEN_MSGENGINE *e,
GWEN_BUFFER *msgbuf,
unsigned char escapeChar,
unsigned char delimiter) {
int esc;

esc=0;
while(GWEN_Buffer_GetBytesLeft(msgbuf)) {
if (esc) {
esc=0;
}
else {
int i;
unsigned char c;

i=GWEN_Buffer_ReadByte(msgbuf);
if (i==-1) {
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
return 0;
}
c=(unsigned int)i;
if (c==escapeChar) { /* escape */
esc=1;
}
else if (c=='@') {
/* skip binary data */
char lbuffer[16];
char *p;
int l;
int nc;

p=lbuffer;
while(1) {
nc=GWEN_Buffer_ReadByte(msgbuf);
if (nc==-1) {
DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected");
return -1;
}
if (nc=='@')
break;
*p=nc;
p++;
} /* while */
*p=0;
if (sscanf(lbuffer, "%d", &l)!=1) {
DBG_ERROR(GWEN_LOGDOMAIN, "Bad number format");
return -1;
}
if (GWEN_Buffer_GetUsedBytes(msgbuf)-GWEN_Buffer_GetPos(msgbuf)
< (unsigned) l) {
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (binary beyond end)");
return -1;
}
GWEN_Buffer_IncrementPos(msgbuf, l);
}
else if (c==delimiter) {/* segment-end */
return 0;
break;
}
}
} /* while */

DBG_ERROR(GWEN_LOGDOMAIN, "End of segment not found");
return -1;
}



/* --------------------------------------------------------------- FUNCTION */
int GWEN_MsgEngine_ReadMessage(GWEN_MSGENGINE *e,
const char *gtype,
GWEN_BUFFER *mbuf,
GWEN_DB_NODE *gr,
GWEN_TYPE_UINT32 flags) {
unsigned int segments;

segments=0;

while(GWEN_Buffer_GetBytesLeft(mbuf)) {
GWEN_XMLNODE *node;
unsigned int posBak;
const char *p;
GWEN_DB_NODE *tmpdb;
int segVer;

/* find head segment description */
tmpdb=GWEN_DB_Group_new("tmpdb");
node=GWEN_MsgEngine_FindGroupByProperty(e,
"id",
0,
"SegHead");
if (node==0) {
DBG_ERROR(GWEN_LOGDOMAIN, "Segment description not found");
GWEN_DB_Group_free(tmpdb);
return -1;
}

/* parse head segment */
posBak=GWEN_Buffer_GetPos(mbuf);
if (GWEN_MsgEngine_ParseMessage(e,
node,
mbuf,
tmpdb,
flags)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing segment head");
GWEN_DB_Group_free(tmpdb);
return -1;
}

/* get segment code */
segVer=GWEN_DB_GetIntValue(tmpdb,
"version",
0,
0);
p=GWEN_DB_GetCharValue(tmpdb,
"code",
0,
0);
if (!p) {
DBG_ERROR(GWEN_LOGDOMAIN, "No segment code for %s ? This seems to be a bad msg...",
gtype);
GWEN_Buffer_SetPos(mbuf, posBak);
DBG_ERROR(GWEN_LOGDOMAIN, "Full message (pos=%04x)", posBak);
GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf),
GWEN_Buffer_GetUsedBytes(mbuf),
stderr, 1);
GWEN_DB_Dump(tmpdb, stderr, 1);
GWEN_DB_Group_free(tmpdb);
return -1;
}

/* try to find corresponding XML node */
node=GWEN_MsgEngine_FindNodeByProperty(e,
gtype,
"code",
segVer,
p);
if (node==0) {
unsigned int ustart;

ustart=GWEN_Buffer_GetPos(mbuf);
ustart++; /* skip delimiter */

/* node not found, skip it */
DBG_NOTICE(GWEN_LOGDOMAIN,
"Unknown segment \"%s\" (Segnum=%d, version=%d, ref=%d)",
p,
GWEN_DB_GetIntValue(tmpdb, "seq", 0, -1),
GWEN_DB_GetIntValue(tmpdb, "version", 0, -1),
GWEN_DB_GetIntValue(tmpdb, "ref", 0, -1));
if (GWEN_MsgEngine_SkipSegment(e, mbuf, '?', '\'')) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error skipping segment \"%s\"", p);
GWEN_DB_Group_free(tmpdb);
return -1;
}
if (flags & GWEN_MSGENGINE_READ_FLAGS_TRUSTINFO) {
unsigned int usize;

usize=GWEN_Buffer_GetPos(mbuf)-ustart-1;
GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf)+ustart,
usize,
stderr, 1);
if (GWEN_MsgEngine_AddTrustInfo(e,
GWEN_Buffer_GetStart(mbuf)+ustart,
usize,
p,
GWEN_MsgEngineTrustLevelHigh,
ustart)) {
DBG_INFO(GWEN_LOGDOMAIN, "called from here");
GWEN_DB_Group_free(tmpdb);
return -1;
}
} /* if trustInfo handling wanted */
}
else {
/* ok, node available, get the corresponding description and parse
* the segment */
const char *id;
GWEN_DB_NODE *storegrp;
unsigned int startPos;

/* restore start position, since the segment head is part of a full
* description, so we need to restart reading from the very begin */
GWEN_Buffer_SetPos(mbuf, posBak);

/* create group in DB for this segment */
id=GWEN_XMLNode_GetProperty(node, "id", p);
storegrp=GWEN_DB_GetGroup(gr,
GWEN_PATH_FLAGS_CREATE_GROUP,
id);
assert(storegrp);

/* store the start position of this segment within the DB */
startPos=GWEN_Buffer_GetPos(mbuf);
GWEN_DB_SetIntValue(storegrp,
GWEN_DB_FLAGS_OVERWRITE_VARS,
"segment/pos",
startPos);

/* parse the segment */
if (GWEN_MsgEngine_ParseMessage(e,
node,
mbuf,
storegrp,
flags)) {
DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing segment \"%s\"",p);
GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf)+startPos,
GWEN_Buffer_GetUsedBytes(mbuf)-startPos,
stderr, 1);
GWEN_DB_Group_free(tmpdb);
return -1;
}

/* store segment size within DB */
GWEN_DB_SetIntValue(storegrp,
GWEN_DB_FLAGS_OVERWRITE_VARS,
"segment/length",
GWEN_Buffer_GetPos(mbuf)-startPos);
segments++;
}
GWEN_DB_Group_free(tmpdb);
} /* while */

/* done */
if (segments) {
DBG_DEBUG(GWEN_LOGDOMAIN, "Parsed %d segments", segments);
return 0;
}
else {
DBG_INFO(GWEN_LOGDOMAIN, "No segments parsed.");
return 1;
}
}








GWEN_MSGENGINE_TRUSTEDDATA*
GWEN_MsgEngine_TrustedData_new(const char *data,
unsigned int size,
const char *description,
GWEN_MSGENGINE_TRUSTLEVEL trustLevel){
GWEN_MSGENGINE_TRUSTEDDATA *td;

assert(data);
assert(size);
GWEN_NEW_OBJECT(GWEN_MSGENGINE_TRUSTEDDATA, td);
td->data=(char*)malloc(size);
assert(td->data);
memmove(td->data, data, size);
if (description)
td->description=strdup(description);
td->trustLevel=trustLevel;
td->size=size;
return td;
}



void GWEN_MsgEngine_TrustedData_free(GWEN_MSGENGINE_TRUSTEDDATA *td){
if (td) {
free(td->data);
free(td->description);
free(td->replacement);
free(td);
}
}



GWEN_MSGENGINE_TRUSTEDDATA*
GWEN_MsgEngine_TrustedData_GetNext(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->next;
}



const char*
GWEN_MsgEngine_TrustedData_GetData(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->data;
}



unsigned int
GWEN_MsgEngine_TrustedData_GetSize(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->size;
}



const char*
GWEN_MsgEngine_TrustedData_GetDescription(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->description;
}



GWEN_MSGENGINE_TRUSTLEVEL
GWEN_MsgEngine_TrustedData_GetTrustLevel(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->trustLevel;
}



const char*
GWEN_MsgEngine_TrustedData_GetReplacement(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
return td->replacement;
}



int GWEN_MsgEngine_TrustedData_AddPos(GWEN_MSGENGINE_TRUSTEDDATA *td,
unsigned int pos){
assert(td);
if (td->posCount>=GWEN_MSGENGINE_TRUSTEDDATA_MAXPOS)
return -1;
td->positions[td->posCount++]=pos;
return 0;
}



int GWEN_MsgEngine_TrustedData_GetFirstPos(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
td->posPointer=0;
return GWEN_MsgEngine_TrustedData_GetNextPos(td);
}



int GWEN_MsgEngine_TrustedData_GetNextPos(GWEN_MSGENGINE_TRUSTEDDATA *td){
assert(td);
if (td->posPointer>=td->posCount)
return -1;
return td->positions[td->posPointer++];
}



int
GWEN_MsgEngine_TrustedData_CreateReplacements(GWEN_MSGENGINE_TRUSTEDDATA
*td){
unsigned int nextNr;
GWEN_MSGENGINE_TRUSTEDDATA *ntd;
unsigned int count;

assert(td);
count=0;
ntd=td;
while(ntd) {
count++;
ntd=ntd->next;
}

if (count<0x10)
nextNr=0x01;
else
nextNr=0x11;

ntd=td;
while(ntd) {
unsigned int i;
char numbuffer[32];
char *rp;
GWEN_MSGENGINE_TRUSTEDDATA *std;
int match;

/* check whether the same data already exists */
std=td;
match=0;
while(std && std!=ntd) {

match=1;
if (std->size==ntd->size) {
unsigned int i;

for (i=0; i<td->size; i++) {
if (std->data[i]!=ntd->data[i]) {
match=0;
break;
}
} /* for */
}
else
match=0;

if (match)
break;
std=std->next;
} /* while */

if (match) {
/* copy the found match */
rp=strdup(std->replacement);
}
else {
/* this is a new one */
rp=(char*)malloc(ntd->size+1);
assert(rp);

if (ntd->size==1) {
if (count>=0x10)
nextNr+=0x10;
}
sprintf(numbuffer, "%02X", nextNr++);
for (i=0; i<ntd->size; i++) {
if (count<0x10)
rp[i]=numbuffer[1];
else
rp[i]=numbuffer[1-(i&1)];
} /* for */
rp[i]=0;
}
/*
DBG_DEBUG(GWEN_LOGDOMAIN, "Replacement: \"%s\" for \"%s\" (%d)", rp,
ntd->description,
ntd->size);
*/
free(ntd->replacement);
ntd->replacement=rp;

ntd=ntd->next;
} /* while */
return 0;
}



GWEN_MSGENGINE_TRUSTEDDATA *GWEN_MsgEngine_TakeTrustInfo(GWEN_MSGENGINE *e){
GWEN_MSGENGINE_TRUSTEDDATA *td;

assert(e);
td=e->trustInfos;
e->trustInfos=0;
return td;
}




int GWEN_MsgEngine_AddTrustInfo(GWEN_MSGENGINE *e,
const char *data,
unsigned int size,
const char *description,
GWEN_MSGENGINE_TRUSTLEVEL trustLevel,
unsigned int pos) {
GWEN_MSGENGINE_TRUSTEDDATA *td;
int match;

assert(e);
assert(data);
assert(size);

if (!description)
description="";

td=e->trustInfos;
while(td) {
unsigned int i;

/* compare data */
if (td->size==size &&
*description &&
*(td->description) &&
trustLevel==td->trustLevel &&
strcasecmp(description, td->description)==0) {
match=1;
for (i=0; i<td->size; i++) {
if (td->data[i]!=data[i]) {
match=0;
break;
}
} /* for */
}
else
match=0;

if (match)
break;
td=td->next;
} /* while */

if (!td) {
DBG_INFO(GWEN_LOGDOMAIN, "Creating new trustInfo for \"%s\" (%d)",
description, size);
td=GWEN_MsgEngine_TrustedData_new(data,
size,
description,
trustLevel);
GWEN_LIST_ADD(GWEN_MSGENGINE_TRUSTEDDATA, td, &(e->trustInfos));
}
else {
DBG_INFO(GWEN_LOGDOMAIN, "Reusing trustInfo for \"%s\" (%d)",
description, size);
}
GWEN_MsgEngine_TrustedData_AddPos(td, pos);
return 0;
}



(15-15/35)