gwenhywfar 4.0.3
|
00001 /*************************************************************************** 00002 begin : Fri Jul 04 2003 00003 copyright : (C) 2003 by Martin Preuss 00004 email : martin@libchipcard.de 00005 00006 *************************************************************************** 00007 * * 00008 * This library is free software; you can redistribute it and/or * 00009 * modify it under the terms of the GNU Lesser General Public * 00010 * License as published by the Free Software Foundation; either * 00011 * version 2.1 of the License, or (at your option) any later version. * 00012 * * 00013 * This library is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00016 * Lesser General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU Lesser General Public * 00019 * License along with this library; if not, write to the Free Software * 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 00021 * MA 02111-1307 USA * 00022 * * 00023 ***************************************************************************/ 00024 00025 #ifdef HAVE_CONFIG_H 00026 # include <config.h> 00027 #endif 00028 00029 #define DISABLE_DEBUGLOG 00030 00031 #include <gwenhywfar/gwenhywfarapi.h> 00032 #include <msgengine_p.h> 00033 #include <gwenhywfar/xml.h> 00034 #include <gwenhywfar/text.h> 00035 #include <gwenhywfar/misc.h> 00036 #include <gwenhywfar/path.h> 00037 #include <gwenhywfar/debug.h> 00038 #include <gwenhywfar/buffer.h> 00039 #include <stdlib.h> 00040 #include <assert.h> 00041 #include <string.h> 00042 #include <ctype.h> 00043 00044 00045 GWEN_INHERIT_FUNCTIONS(GWEN_MSGENGINE) 00046 00047 00048 GWEN_MSGENGINE *GWEN_MsgEngine_new(){ 00049 GWEN_MSGENGINE *e; 00050 00051 GWEN_NEW_OBJECT(GWEN_MSGENGINE, e); 00052 GWEN_INHERIT_INIT(GWEN_MSGENGINE, e); 00053 e->charsToEscape=strdup(GWEN_MSGENGINE_CHARSTOESCAPE); 00054 e->delimiters=strdup(GWEN_MSGENGINE_DEFAULT_DELIMITERS); 00055 e->globalValues=GWEN_DB_Group_new("globalvalues"); 00056 e->escapeChar='\\'; 00057 00058 e->usage=1; 00059 return e; 00060 } 00061 00062 00063 void GWEN_MsgEngine_free(GWEN_MSGENGINE *e){ 00064 if (e) { 00065 assert(e->usage); 00066 if (--(e->usage)==0) { 00067 GWEN_INHERIT_FINI(GWEN_MSGENGINE, e); 00068 00069 if (e->inheritorData && e->freeDataPtr) 00070 e->freeDataPtr(e); 00071 if (e->ownDefs) 00072 GWEN_XMLNode_free(e->defs); 00073 free(e->charsToEscape); 00074 free(e->delimiters); 00075 GWEN_DB_Group_free(e->globalValues); 00076 if (e->trustInfos) { 00077 /* free trustInfos */ 00078 GWEN_MSGENGINE_TRUSTEDDATA *td, *tdn; 00079 00080 td=e->trustInfos; 00081 while(td) { 00082 tdn=td->next; 00083 GWEN_MsgEngine_TrustedData_free(td); 00084 td=tdn; 00085 } /* while */ 00086 } 00087 GWEN_FREE_OBJECT(e); 00088 } 00089 } 00090 } 00091 00092 00093 00094 void GWEN_MsgEngine_Attach(GWEN_MSGENGINE *e){ 00095 assert(e); 00096 e->usage++; 00097 } 00098 00099 00100 void GWEN_MsgEngine_SetEscapeChar(GWEN_MSGENGINE *e, char c){ 00101 assert(e); 00102 e->escapeChar=c; 00103 } 00104 00105 00106 00107 char GWEN_MsgEngine_GetEscapeChar(GWEN_MSGENGINE *e){ 00108 assert(e); 00109 return e->escapeChar; 00110 } 00111 00112 00113 00114 void GWEN_MsgEngine_SetCharsToEscape(GWEN_MSGENGINE *e, const char *c){ 00115 assert(e); 00116 free(e->charsToEscape); 00117 e->charsToEscape=strdup(c); 00118 } 00119 00120 00121 00122 const char *GWEN_MsgEngine_GetCharsToEscape(GWEN_MSGENGINE *e){ 00123 assert(e); 00124 return e->charsToEscape; 00125 } 00126 00127 00128 00129 void GWEN_MsgEngine_SetDelimiters(GWEN_MSGENGINE *e, const char *s){ 00130 assert(e); 00131 free(e->delimiters); 00132 if (s) 00133 e->delimiters=strdup(s); 00134 else 00135 e->delimiters=strdup(GWEN_MSGENGINE_DEFAULT_DELIMITERS); 00136 } 00137 00138 00139 00140 const char *GWEN_MsgEngine_GetDelimiters(GWEN_MSGENGINE *e){ 00141 assert(e); 00142 return e->delimiters; 00143 } 00144 00145 00146 00147 void GWEN_MsgEngine_SetMode(GWEN_MSGENGINE *e, const char *mode){ 00148 GWEN_DB_NODE *db; 00149 00150 assert(e); 00151 db=GWEN_MsgEngine__GetGlobalValues(e); 00152 00153 if (mode) 00154 GWEN_DB_SetCharValue(db, 00155 GWEN_DB_FLAGS_OVERWRITE_VARS, 00156 "engine/secmode", 00157 mode); 00158 else 00159 GWEN_DB_DeleteVar(db, "engine/secmode"); 00160 } 00161 00162 00163 const char *GWEN_MsgEngine_GetMode(GWEN_MSGENGINE *e){ 00164 GWEN_DB_NODE *db; 00165 00166 assert(e); 00167 db=GWEN_MsgEngine__GetGlobalValues(e); 00168 return GWEN_DB_GetCharValue(db, "engine/secmode", 0, 0); 00169 } 00170 00171 00172 00173 GWEN_DB_NODE *GWEN_MsgEngine__GetGlobalValues(GWEN_MSGENGINE *e){ 00174 GWEN_DB_NODE *globalValues; 00175 00176 assert(e); 00177 if (e->getGlobalValuesPtr) { 00178 globalValues=e->getGlobalValuesPtr(e); 00179 if (!globalValues) 00180 globalValues=e->globalValues; 00181 } 00182 else { 00183 globalValues=e->globalValues; 00184 } 00185 assert(globalValues); 00186 return globalValues; 00187 } 00188 00189 00190 00191 unsigned int GWEN_MsgEngine_GetProtocolVersion(GWEN_MSGENGINE *e){ 00192 GWEN_DB_NODE *db; 00193 00194 assert(e); 00195 db=GWEN_MsgEngine__GetGlobalValues(e); 00196 return GWEN_DB_GetIntValue(db, "engine/pversion", 0, 0); 00197 } 00198 00199 00200 00201 void GWEN_MsgEngine_SetProtocolVersion(GWEN_MSGENGINE *e, 00202 unsigned int p){ 00203 GWEN_DB_NODE *db; 00204 00205 assert(e); 00206 db=GWEN_MsgEngine__GetGlobalValues(e); 00207 00208 GWEN_DB_SetIntValue(db, 00209 GWEN_DB_FLAGS_OVERWRITE_VARS, 00210 "engine/pversion", 00211 p); 00212 } 00213 00214 00215 00216 GWEN_XMLNODE *GWEN_MsgEngine_GetDefinitions(GWEN_MSGENGINE *e){ 00217 assert(e); 00218 return e->defs; 00219 } 00220 00221 00222 void GWEN_MsgEngine_SetDefinitions(GWEN_MSGENGINE *e, 00223 GWEN_XMLNODE *n, 00224 int take){ 00225 assert(e); 00226 if (e->ownDefs) 00227 GWEN_XMLNode_free(e->defs); 00228 e->defs=n; 00229 e->ownDefs=take; 00230 } 00231 00232 00233 00234 void 00235 GWEN_MsgEngine_SetGetGlobalValuesFunction(GWEN_MSGENGINE *e, 00236 GWEN_MSGENGINE_GETGLOBALVALUES_PTR p){ 00237 assert(e); 00238 e->getGlobalValuesPtr=p; 00239 } 00240 00241 00242 00243 GWEN_MSGENGINE_GETGLOBALVALUES_PTR 00244 GWEN_MsgEngine_GetGetGlobalValuesFunction(GWEN_MSGENGINE *e){ 00245 assert(e); 00246 return e->getGlobalValuesPtr; 00247 } 00248 00249 00250 00251 void GWEN_MsgEngine_SetTypeReadFunction(GWEN_MSGENGINE *e, 00252 GWEN_MSGENGINE_TYPEREAD_PTR p){ 00253 assert(e); 00254 e->typeReadPtr=p; 00255 } 00256 00257 00258 00259 GWEN_MSGENGINE_TYPEREAD_PTR 00260 GWEN_MsgEngine_GetTypeReadFunction(GWEN_MSGENGINE *e){ 00261 assert(e); 00262 return e->typeReadPtr; 00263 } 00264 00265 00266 00267 void GWEN_MsgEngine_SetTypeWriteFunction(GWEN_MSGENGINE *e, 00268 GWEN_MSGENGINE_TYPEWRITE_PTR p){ 00269 assert(e); 00270 e->typeWritePtr=p; 00271 } 00272 00273 00274 00275 GWEN_MSGENGINE_TYPEWRITE_PTR 00276 GWEN_MsgEngine_GetTypeWriteFunction(GWEN_MSGENGINE *e){ 00277 assert(e); 00278 return e->typeWritePtr; 00279 } 00280 00281 00282 00283 void GWEN_MsgEngine_SetTypeCheckFunction(GWEN_MSGENGINE *e, 00284 GWEN_MSGENGINE_TYPECHECK_PTR p){ 00285 assert(e); 00286 e->typeCheckPtr=p; 00287 } 00288 00289 00290 00291 GWEN_MSGENGINE_TYPECHECK_PTR 00292 GWEN_MsgEngine_GetTypeCheckFunction(GWEN_MSGENGINE *e){ 00293 assert(e); 00294 return e->typeCheckPtr; 00295 } 00296 00297 00298 00299 00300 00301 00302 void GWEN_MsgEngine_SetBinTypeReadFunction(GWEN_MSGENGINE *e, 00303 GWEN_MSGENGINE_BINTYPEREAD_PTR p){ 00304 assert(e); 00305 e->binTypeReadPtr=p; 00306 } 00307 00308 00309 00310 GWEN_MSGENGINE_BINTYPEREAD_PTR 00311 GWEN_MsgEngine_GetBinTypeReadFunction(GWEN_MSGENGINE *e){ 00312 assert(e); 00313 return e->binTypeReadPtr; 00314 } 00315 00316 00317 00318 void 00319 GWEN_MsgEngine_SetBinTypeWriteFunction(GWEN_MSGENGINE *e, 00320 GWEN_MSGENGINE_BINTYPEWRITE_PTR p){ 00321 assert(e); 00322 e->binTypeWritePtr=p; 00323 } 00324 00325 00326 00327 GWEN_MSGENGINE_BINTYPEWRITE_PTR 00328 GWEN_MsgEngine_GetBinTypeWriteFunction(GWEN_MSGENGINE *e){ 00329 assert(e); 00330 return e->binTypeWritePtr; 00331 } 00332 00333 00334 00335 void 00336 GWEN_MsgEngine_SetGetCharValueFunction(GWEN_MSGENGINE *e, 00337 GWEN_MSGENGINE_GETCHARVALUE_PTR p){ 00338 assert(e); 00339 e->getCharValuePtr=p; 00340 } 00341 00342 00343 00344 void 00345 GWEN_MsgEngine_SetGetIntValueFunction(GWEN_MSGENGINE *e, 00346 GWEN_MSGENGINE_GETINTVALUE_PTR p){ 00347 assert(e); 00348 e->getIntValuePtr=p; 00349 } 00350 00351 00352 00353 void 00354 GWEN_MsgEngine_SetFreeDataFunction(GWEN_MSGENGINE *e, 00355 GWEN_MSGENGINE_FREEDATA_PTR p){ 00356 assert(e); 00357 DBG_WARN(GWEN_LOGDOMAIN, "GWEN_MsgEngine_SetFreeDataFunction: Deprecated"); 00358 e->freeDataPtr=p; 00359 } 00360 00361 00362 00363 void *GWEN_MsgEngine_GetInheritorData(const GWEN_MSGENGINE *e){ 00364 assert(e); 00365 return e->inheritorData; 00366 } 00367 00368 00369 00370 void GWEN_MsgEngine_SetInheritorData(GWEN_MSGENGINE *e, void *d){ 00371 assert(e); 00372 DBG_WARN(GWEN_LOGDOMAIN, "GWEN_MsgEngine_SetInheritorData: Deprecated"); 00373 if (e->inheritorData && e->freeDataPtr) 00374 e->freeDataPtr(e); 00375 e->inheritorData=d; 00376 } 00377 00378 00379 00380 int GWEN_MsgEngine__WriteValue(GWEN_MSGENGINE *e, 00381 GWEN_BUFFER *gbuf, 00382 GWEN_BUFFER *data, 00383 GWEN_XMLNODE *node) { 00384 unsigned int minsize; 00385 unsigned int maxsize; 00386 unsigned int fixSize; 00387 unsigned int startPos; 00388 int filler; 00389 const char *type; 00390 const char *name; 00391 int rv; 00392 00393 /* get some sizes */ 00394 minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0")); 00395 maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0")); 00396 fixSize=atoi(GWEN_XMLNode_GetProperty(node, "size","0")); 00397 filler=atoi(GWEN_XMLNode_GetProperty(node, "filler","0")); 00398 type=GWEN_XMLNode_GetProperty(node, "type","ASCII"); 00399 name=GWEN_XMLNode_GetProperty(node, "name","<unnamed>"); 00400 startPos=GWEN_Buffer_GetPos(gbuf); 00401 00402 /* check sizes */ 00403 if (minsize && GWEN_Buffer_GetUsedBytes(data)<minsize) { 00404 DBG_ERROR(GWEN_LOGDOMAIN, "Data too short (minsize is %d)", minsize); 00405 return -1; 00406 } 00407 if (maxsize && GWEN_Buffer_GetUsedBytes(data)>maxsize) { 00408 DBG_ERROR(GWEN_LOGDOMAIN, "Data too long (maxsize is %d)", maxsize); 00409 return -1; 00410 } 00411 00412 rv=1; 00413 if (e->typeWritePtr) { 00414 rv=e->typeWritePtr(e, 00415 gbuf, 00416 data, 00417 node); 00418 } 00419 if (rv==-1) { 00420 DBG_INFO(GWEN_LOGDOMAIN, "External type writing failed"); 00421 return -1; 00422 } 00423 else if (rv==1) { 00424 int i; 00425 00426 /* type not handled externally, so handle it myself */ 00427 if (strcasecmp(type, "bin")==0) { 00428 DBG_DEBUG(GWEN_LOGDOMAIN, "Writing binary data (%d bytes added to %d bytes)", 00429 GWEN_Buffer_GetUsedBytes(data), 00430 GWEN_Buffer_GetUsedBytes(gbuf)); 00431 if (GWEN_Buffer_AllocRoom(gbuf, 10+GWEN_Buffer_GetUsedBytes(data))) { 00432 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 00433 return -1; 00434 } 00435 sprintf(GWEN_Buffer_GetPosPointer(gbuf), 00436 "@%d@", 00437 GWEN_Buffer_GetUsedBytes(data)); 00438 00439 00440 i=strlen(GWEN_Buffer_GetPosPointer(gbuf)); 00441 GWEN_Buffer_IncrementPos(gbuf, i); 00442 GWEN_Buffer_AdjustUsedBytes(gbuf); 00443 GWEN_Buffer_AppendBuffer(gbuf, data); 00444 } /* if type is "bin" */ 00445 else if (strcasecmp(type, "num")==0) { 00446 int num; 00447 unsigned int len; 00448 unsigned int lj; 00449 00450 num=atoi(GWEN_Buffer_GetPosPointer(data)); 00451 len=strlen(GWEN_Buffer_GetPosPointer(data)); 00452 00453 if (atoi(GWEN_XMLNode_GetProperty(node, "leftfill","0"))) { 00454 if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) { 00455 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 00456 return -1; 00457 } 00458 00459 /* fill left */ 00460 for (lj=0; lj<(maxsize-len); lj++) 00461 GWEN_Buffer_AppendByte(gbuf, '0'); 00462 00463 /* write value */ 00464 for (lj=0; lj<len; lj++) 00465 GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data)); 00466 } 00467 else if (atoi(GWEN_XMLNode_GetProperty(node, "rightfill","0"))) { 00468 if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) { 00469 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 00470 return -1; 00471 } 00472 00473 /* write value */ 00474 for (lj=0; lj<len; lj++) 00475 GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data)); 00476 00477 /* fill right */ 00478 for (lj=0; lj<(maxsize-len); lj++) 00479 GWEN_Buffer_AppendByte(gbuf, '0'); 00480 } 00481 else { 00482 if (GWEN_Buffer_AllocRoom(gbuf, maxsize+1)) { 00483 DBG_ERROR(GWEN_LOGDOMAIN, "Maxsize in XML file is higher than the buffer size"); 00484 return -1; 00485 } 00486 for (lj=0; lj<len; lj++) 00487 GWEN_Buffer_AppendByte(gbuf, GWEN_Buffer_ReadByte(data)); 00488 } 00489 } /* if type is num */ 00490 else { 00491 /* TODO: Check for valids */ 00492 const char *p; 00493 int lastWasEscape; 00494 unsigned int pcount; 00495 00496 p=GWEN_Buffer_GetPosPointer(data); 00497 pcount=0; 00498 lastWasEscape=0; 00499 while(*p && pcount<GWEN_Buffer_GetUsedBytes(data)) { 00500 int c; 00501 00502 c=(unsigned char)*p; 00503 if (lastWasEscape) { 00504 lastWasEscape=0; 00505 switch(c) { 00506 case 'r': c='\r'; break; 00507 case 'n': c='\n'; break; 00508 case 'f': c='\f'; break; 00509 case 't': c='\t'; break; 00510 default: c=(unsigned char)*p; 00511 } /* switch */ 00512 } 00513 else { 00514 if (*p=='\\') { 00515 lastWasEscape=1; 00516 c=-1; 00517 } 00518 else 00519 c=(unsigned char)*p; 00520 } 00521 if (c!=-1) { 00522 int needsEscape; 00523 00524 needsEscape=0; 00525 if (c==e->escapeChar) 00526 needsEscape=1; 00527 else { 00528 if (e->charsToEscape) 00529 if (strchr(e->charsToEscape, c)) 00530 needsEscape=1; 00531 } 00532 if (needsEscape) { 00533 /* write escape char */ 00534 if (GWEN_Buffer_AppendByte(gbuf, 00535 e->escapeChar)) { 00536 return -1; 00537 } 00538 } 00539 if (GWEN_Buffer_AppendByte(gbuf, c)) { 00540 return -1; 00541 } 00542 } 00543 p++; 00544 pcount++; 00545 } /* while */ 00546 if (pcount<GWEN_Buffer_GetUsedBytes(data)) { 00547 DBG_WARN(GWEN_LOGDOMAIN, "Premature end of string (%d<%d)", 00548 pcount, GWEN_Buffer_GetUsedBytes(data)); 00549 } 00550 if (*p) { 00551 DBG_WARN(GWEN_LOGDOMAIN, 00552 "String for \"%s\" (type %s) is longer than expected " 00553 "(no #0 at pos=%d)", 00554 name, type, 00555 GWEN_Buffer_GetUsedBytes(data)-1); 00556 } 00557 } /* if type is not BIN */ 00558 } /* if type not external */ 00559 else { 00560 DBG_INFO(GWEN_LOGDOMAIN, "Type \"%s\" (for %s) is external (write)", 00561 type, name); 00562 00563 } /* if external type */ 00564 00565 /* fill data */ 00566 if (fixSize) { 00567 uint32_t bs; 00568 unsigned int j; 00569 00570 bs=GWEN_Buffer_GetPos(gbuf)-startPos; 00571 if (bs>fixSize) { 00572 DBG_ERROR(GWEN_LOGDOMAIN, 00573 "Data too long (size is %d, fixed size is %d)", 00574 bs, fixSize); 00575 return -1; 00576 } 00577 00578 for (j=bs; j<fixSize; j++) 00579 GWEN_Buffer_AppendByte(gbuf, (unsigned char)filler); 00580 } 00581 00582 return 0; 00583 } 00584 00585 00586 00587 int GWEN_MsgEngine__IsCharTyp(GWEN_MSGENGINE *e, 00588 const char *type) { 00589 if (e->typeCheckPtr) { 00590 GWEN_DB_NODE_TYPE vt; 00591 00592 vt=e->typeCheckPtr(e, type); 00593 if (vt!=GWEN_DB_NodeType_Unknown) { 00594 if (vt==GWEN_DB_NodeType_ValueChar) 00595 return 1; 00596 } 00597 } 00598 return 00599 (strcasecmp(type, "alpha")==0) || 00600 (strcasecmp(type, "ascii")==0) || 00601 (strcasecmp(type, "an")==0) || 00602 (strcasecmp(type, "float")==0); 00603 } 00604 00605 00606 00607 int GWEN_MsgEngine__IsIntTyp(GWEN_MSGENGINE *e, 00608 const char *type) { 00609 if (e->typeCheckPtr) { 00610 GWEN_DB_NODE_TYPE vt; 00611 00612 vt=e->typeCheckPtr(e, type); 00613 if (vt!=GWEN_DB_NodeType_Unknown) { 00614 if (vt==GWEN_DB_NodeType_ValueInt) 00615 return 1; 00616 } 00617 } 00618 return 00619 (strcasecmp(type, "num")==0); 00620 } 00621 00622 00623 00624 int GWEN_MsgEngine__IsBinTyp(GWEN_MSGENGINE *e, 00625 const char *type) { 00626 if (e->typeCheckPtr) { 00627 GWEN_DB_NODE_TYPE vt; 00628 00629 vt=e->typeCheckPtr(e, type); 00630 if (vt!=GWEN_DB_NodeType_Unknown) { 00631 if (vt==GWEN_DB_NodeType_ValueBin) 00632 return 1; 00633 } 00634 } 00635 return 00636 (strcasecmp(type, "bin")==0); 00637 } 00638 00639 00640 00641 int GWEN_MsgEngine__GetInline(GWEN_MSGENGINE *e, 00642 GWEN_XMLNODE *node, 00643 GWEN_BUFFER *mbuf) { 00644 /* get data from within the XML node */ 00645 GWEN_XMLNODE *n; 00646 const char *type; 00647 00648 00649 type=GWEN_XMLNode_GetProperty(node, "type", "ascii"); 00650 DBG_DEBUG(GWEN_LOGDOMAIN, 00651 "Getting data of type \"%s\" from within XML file", type); 00652 n=GWEN_XMLNode_GetFirstData(node); 00653 if (!n) { 00654 DBG_DEBUG(GWEN_LOGDOMAIN, "No child"); 00655 return 1; 00656 } 00657 00658 if (GWEN_MsgEngine__IsBinTyp(e, type)) { 00659 const char *dp; 00660 unsigned int dplen; 00661 const char *stype; 00662 00663 stype=GWEN_XMLNode_GetProperty(node, "storedAs", type); 00664 if (GWEN_MsgEngine__IsBinTyp(e, stype)) { 00665 dp=GWEN_XMLNode_GetData(n); 00666 dplen=strlen(dp); 00667 if (GWEN_Text_FromHexBuffer(dp, mbuf)) { 00668 DBG_INFO(GWEN_LOGDOMAIN, "here"); 00669 return -1; 00670 } 00671 } /* if stored as bin */ 00672 else { 00673 /* stored as char */ 00674 GWEN_Buffer_AppendString(mbuf, GWEN_XMLNode_GetData(n)); 00675 } 00676 } /* if binType */ 00677 else { 00678 GWEN_Buffer_AppendString(mbuf, GWEN_XMLNode_GetData(n)); 00679 } 00680 00681 return 0; 00682 } 00683 00684 00685 00686 00687 00688 int GWEN_MsgEngine__WriteElement(GWEN_MSGENGINE *e, 00689 GWEN_BUFFER *gbuf, 00690 GWEN_XMLNODE *node, 00691 GWEN_XMLNODE *rnode, 00692 GWEN_DB_NODE *gr, 00693 int loopNr, 00694 int isOptional, 00695 GWEN_XMLNODE_PATH *nodePath) { 00696 const char *name; 00697 const char *type; 00698 unsigned int minsize; 00699 unsigned int maxsize; 00700 char numbuffer[256]; 00701 const char *pdata; 00702 unsigned int datasize; 00703 GWEN_BUFFER *data; 00704 GWEN_BUFFER *tdata; 00705 int handled; 00706 00707 pdata=0; 00708 handled=0; 00709 data=0; 00710 tdata=0; 00711 00712 /* get type */ 00713 type=GWEN_XMLNode_GetProperty(node, "type","ASCII"); 00714 DBG_DEBUG(GWEN_LOGDOMAIN, "Type is \"%s\"", type); 00715 /* get some sizes */ 00716 minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0")); 00717 maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0")); 00718 00719 if (e->binTypeWritePtr && 00720 GWEN_MsgEngine__IsBinTyp(e, type) && 00721 atoi(GWEN_XMLNode_GetProperty(node, "writebin", "1"))) { 00722 int rv; 00723 00724 data=GWEN_Buffer_new(0, 00725 64, 00726 0, 00727 1); 00728 00729 rv=e->binTypeWritePtr(e, node, gr, data); 00730 if (rv==-1) { 00731 /* error */ 00732 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 00733 return -1; 00734 } 00735 else if (rv==0) { 00736 handled=1; 00737 } 00738 else if (rv==1) { 00739 GWEN_Buffer_free(data); 00740 data=0; 00741 } 00742 } 00743 00744 if (!handled) { 00745 /* get name */ 00746 name=GWEN_XMLNode_GetProperty(node, "name", 0); 00747 if (!name) { 00748 int rv; 00749 00750 /* get data from within the XML node */ 00751 tdata=GWEN_Buffer_new(0, 32, 0, 1); 00752 GWEN_Buffer_SetStep(tdata, 256); 00753 rv=GWEN_MsgEngine__GetInline(e, node, tdata); 00754 if (rv==0) { 00755 pdata=GWEN_Buffer_GetStart(tdata); 00756 datasize=GWEN_Buffer_GetUsedBytes(tdata); 00757 } 00758 else { 00759 GWEN_Buffer_free(tdata); 00760 tdata=0; 00761 pdata=""; 00762 datasize=0; 00763 } 00764 } /* if (!name) */ 00765 else { 00766 const char *nptr; 00767 00768 DBG_DEBUG(GWEN_LOGDOMAIN, "Name provided (%s), loop is %d", name, loopNr); 00769 nptr=name; 00770 00771 if (gr) { 00772 GWEN_DB_NODE_TYPE vt; 00773 int idata; 00774 00775 /* Variable type of DB takes precedence 00776 */ 00777 vt=GWEN_DB_GetValueTypeByPath(gr, nptr, loopNr); 00778 if (vt==GWEN_DB_NodeType_Unknown) { 00779 if (GWEN_MsgEngine__IsCharTyp(e, type)) 00780 vt=GWEN_DB_NodeType_ValueChar; 00781 else if (GWEN_MsgEngine__IsIntTyp(e, type)) 00782 vt=GWEN_DB_NodeType_ValueInt; 00783 else if (GWEN_MsgEngine__IsBinTyp(e, type)) 00784 vt=GWEN_DB_NodeType_ValueBin; 00785 else { 00786 DBG_INFO(GWEN_LOGDOMAIN, 00787 "Unable to determine parameter " 00788 "type (%s), assuming \"char\" for this matter", type); 00789 vt=GWEN_DB_NodeType_ValueChar; 00790 } 00791 } 00792 00793 /* get the value of the given var from the db */ 00794 switch(vt) { 00795 case GWEN_DB_NodeType_ValueChar: 00796 DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is char", name); 00797 pdata=GWEN_DB_GetCharValue(gr, nptr, loopNr, 0); 00798 if (pdata) { 00799 DBG_DEBUG(GWEN_LOGDOMAIN, "Value of \"%s\" is %s", nptr, pdata); 00800 datasize=strlen(pdata); 00801 } 00802 else 00803 datasize=0; 00804 break; 00805 00806 case GWEN_DB_NodeType_ValueInt: 00807 DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is int", name); 00808 if (GWEN_DB_ValueExists(gr, nptr, loopNr)) { 00809 idata=GWEN_DB_GetIntValue(gr, nptr, loopNr, 0); 00810 if (-1==GWEN_Text_NumToString(idata, numbuffer, 00811 sizeof(numbuffer),0)) { 00812 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 00813 GWEN_Buffer_free(data); 00814 return -1; 00815 } 00816 DBG_DEBUG(GWEN_LOGDOMAIN, "Value of \"%s\" is %d", nptr, idata); 00817 pdata=numbuffer; 00818 datasize=strlen(numbuffer); 00819 } 00820 break; 00821 00822 case GWEN_DB_NodeType_ValueBin: 00823 DBG_DEBUG(GWEN_LOGDOMAIN, "Type of \"%s\" is bin", name); 00824 pdata=GWEN_DB_GetBinValue(gr, nptr, loopNr, 0, 0, &datasize); 00825 break; 00826 00827 default: 00828 DBG_WARN(GWEN_LOGDOMAIN, "Unsupported parameter type (%d)", vt); 00829 break; 00830 } /* switch vt */ 00831 } /* if gr */ 00832 00833 if (!pdata) { 00834 GWEN_XMLNODE_PATH *copyOfNodePath; 00835 00836 copyOfNodePath=GWEN_XMLNode_Path_dup(nodePath); 00837 00838 /* still no data, try to get it from the XML file */ 00839 DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\"", name); 00840 pdata=GWEN_MsgEngine__SearchForValue(e, 00841 node, copyOfNodePath, nptr, 00842 &datasize); 00843 GWEN_XMLNode_Path_free(copyOfNodePath); 00844 if (pdata) { 00845 DBG_DEBUG(GWEN_LOGDOMAIN, "Found value of \"%s\"", name); 00846 } 00847 } 00848 00849 if (!pdata) { 00850 int rv; 00851 00852 /* get data from within the XML node */ 00853 tdata=GWEN_Buffer_new(0, 32, 0, 1); 00854 GWEN_Buffer_SetStep(tdata, 256); 00855 rv=GWEN_MsgEngine__GetInline(e, node, tdata); 00856 if (rv==0) { 00857 pdata=GWEN_Buffer_GetStart(tdata); 00858 datasize=GWEN_Buffer_GetUsedBytes(tdata); 00859 } 00860 else { 00861 GWEN_Buffer_free(tdata); 00862 tdata=0; 00863 } 00864 } 00865 00866 if (pdata==0) { 00867 if (isOptional) { 00868 DBG_INFO(GWEN_LOGDOMAIN, "Value not found, omitting element \"%s[%d]\"", 00869 name, loopNr); 00870 GWEN_Buffer_free(data); 00871 return 1; 00872 } 00873 else { 00874 DBG_ERROR(GWEN_LOGDOMAIN, 00875 "Value for element \"%s[%d]\" (mode \"%s\") not found", 00876 name, loopNr, 00877 GWEN_MsgEngine_GetMode(e)); 00878 GWEN_DB_Dump(gr, 4); 00879 GWEN_Buffer_free(data); 00880 return -1; 00881 } 00882 } 00883 } 00884 00885 if (!data) 00886 data=GWEN_Buffer_new((char*)pdata, 00887 datasize, 00888 datasize, 00889 0 /* dont take ownership*/ ); 00890 } 00891 00892 /* write value */ 00893 if (GWEN_MsgEngine__WriteValue(e, 00894 gbuf, 00895 data, 00896 node)!=0) { 00897 DBG_INFO(GWEN_LOGDOMAIN, "Could not write value"); 00898 GWEN_Buffer_free(data); 00899 GWEN_Buffer_free(tdata); 00900 return -1; 00901 } 00902 GWEN_Buffer_free(data); 00903 GWEN_Buffer_free(tdata); 00904 00905 return 0; 00906 } 00907 00908 00909 00910 GWEN_XMLNODE *GWEN_MsgEngine_FindGroupByProperty(GWEN_MSGENGINE *e, 00911 const char *pname, 00912 int version, 00913 const char *pvalue) { 00914 return GWEN_MsgEngine_FindNodeByProperty(e, "GROUP", pname, version, pvalue); 00915 } 00916 00917 00918 00919 GWEN_XMLNODE *GWEN_MsgEngine_FindNodeByProperty(GWEN_MSGENGINE *e, 00920 const char *t, 00921 const char *pname, 00922 int version, 00923 const char *pvalue) { 00924 GWEN_XMLNODE *n; 00925 const char *p; 00926 int i; 00927 const char *mode; 00928 unsigned int proto; 00929 char buffer[256]; 00930 00931 if ((strlen(t)+4)>sizeof(buffer)) { 00932 DBG_ERROR(GWEN_LOGDOMAIN, "Type name too long."); 00933 return 0; 00934 } 00935 00936 mode=GWEN_MsgEngine_GetMode(e); 00937 proto=GWEN_MsgEngine_GetProtocolVersion(e); 00938 if (!e->defs) { 00939 DBG_INFO(GWEN_LOGDOMAIN, "No definitions available"); 00940 return 0; 00941 } 00942 n=e->defs; 00943 n=GWEN_XMLNode_GetChild(n); 00944 00945 /* find type+"S" */ 00946 strcpy(buffer, t); 00947 strcat(buffer,"S"); 00948 while(n) { 00949 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 00950 p=GWEN_XMLNode_GetData(n); 00951 assert(p); 00952 if (strcasecmp(p, buffer)==0) 00953 break; 00954 } 00955 n=GWEN_XMLNode_Next(n); 00956 } /* while */ 00957 00958 if (!n) { 00959 DBG_INFO(GWEN_LOGDOMAIN, "No definitions available for type \"%s\"", t); 00960 return 0; 00961 } 00962 00963 /* find approppriate group definition */ 00964 if (!mode) 00965 mode=""; 00966 n=GWEN_XMLNode_GetChild(n); 00967 if (!n) { 00968 DBG_INFO(GWEN_LOGDOMAIN, "No definitions inside \"%s\"", buffer); 00969 return 0; 00970 } 00971 00972 /* find type+"def" */ 00973 strcpy(buffer, t); 00974 strcat(buffer,"def"); 00975 while(n) { 00976 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 00977 p=GWEN_XMLNode_GetData(n); 00978 assert(p); 00979 if (strcasecmp(p, buffer)==0) { 00980 p=GWEN_XMLNode_GetProperty(n, pname,""); 00981 if (strcasecmp(p, pvalue)==0) { 00982 i=atoi(GWEN_XMLNode_GetProperty(n, "pversion" ,"0")); 00983 if (proto==0 || (int)proto==i || i==0) { 00984 i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0")); 00985 if (version==0 || version==i) { 00986 p=GWEN_XMLNode_GetProperty(n, "mode",""); 00987 if (strcasecmp(p, mode)==0 || !*p) { 00988 DBG_DEBUG(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\" found", 00989 pname, pvalue); 00990 return n; 00991 } 00992 } 00993 } 00994 } 00995 } 00996 } 00997 n=GWEN_XMLNode_Next(n); 00998 } /* while */ 00999 01000 DBG_INFO(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\"(%d) not found", 01001 pname, 01002 pvalue, 01003 version); 01004 return 0; 01005 } 01006 01007 01008 01009 GWEN_XMLNODE *GWEN_MsgEngine_FindNodeByPropertyStrictProto(GWEN_MSGENGINE *e, 01010 const char *t, 01011 const char *pname, 01012 int version, 01013 const char *pvalue) { 01014 GWEN_XMLNODE *n; 01015 const char *p; 01016 int i; 01017 const char *mode; 01018 unsigned int proto; 01019 char buffer[256]; 01020 01021 if ((strlen(t)+4)>sizeof(buffer)) { 01022 DBG_ERROR(GWEN_LOGDOMAIN, "Type name too long."); 01023 return 0; 01024 } 01025 01026 mode=GWEN_MsgEngine_GetMode(e); 01027 proto=GWEN_MsgEngine_GetProtocolVersion(e); 01028 if (!e->defs) { 01029 DBG_INFO(GWEN_LOGDOMAIN, "No definitions available"); 01030 return 0; 01031 } 01032 n=e->defs; 01033 n=GWEN_XMLNode_GetChild(n); 01034 01035 /* find type+"S" */ 01036 strcpy(buffer, t); 01037 strcat(buffer,"S"); 01038 while(n) { 01039 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 01040 p=GWEN_XMLNode_GetData(n); 01041 assert(p); 01042 if (strcasecmp(p, buffer)==0) 01043 break; 01044 } 01045 n=GWEN_XMLNode_Next(n); 01046 } /* while */ 01047 01048 if (!n) { 01049 DBG_INFO(GWEN_LOGDOMAIN, "No definitions available for type \"%s\"", t); 01050 return 0; 01051 } 01052 01053 /* find approppriate group definition */ 01054 if (!mode) 01055 mode=""; 01056 n=GWEN_XMLNode_GetChild(n); 01057 if (!n) { 01058 DBG_INFO(GWEN_LOGDOMAIN, "No definitions inside \"%s\"", buffer); 01059 return 0; 01060 } 01061 01062 /* find type+"def" */ 01063 strcpy(buffer, t); 01064 strcat(buffer,"def"); 01065 while(n) { 01066 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 01067 p=GWEN_XMLNode_GetData(n); 01068 assert(p); 01069 if (strcasecmp(p, buffer)==0) { 01070 p=GWEN_XMLNode_GetProperty(n, pname,""); 01071 if (strcasecmp(p, pvalue)==0) { 01072 i=atoi(GWEN_XMLNode_GetProperty(n, "pversion" ,"0")); 01073 if (proto==0 || (int)proto==i) { 01074 i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0")); 01075 if (version==0 || version==i) { 01076 p=GWEN_XMLNode_GetProperty(n, "mode",""); 01077 if (strcasecmp(p, mode)==0 || !*p) { 01078 DBG_DEBUG(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\" found", 01079 pname, pvalue); 01080 return n; 01081 } 01082 } 01083 } 01084 } 01085 } 01086 } 01087 n=GWEN_XMLNode_Next(n); 01088 } /* while */ 01089 01090 DBG_INFO(GWEN_LOGDOMAIN, "Group definition for \"%s=%s\"(%d) not found", 01091 pname, 01092 pvalue, 01093 version); 01094 return 0; 01095 } 01096 01097 01098 01099 const char *GWEN_MsgEngine__TransformValue(GWEN_MSGENGINE *e, 01100 const char *pvalue, 01101 GWEN_XMLNODE *node, 01102 GWEN_XMLNODE *dnode, 01103 unsigned int *datasize) { 01104 const char *p; 01105 static char pbuffer[256]; 01106 GWEN_DB_NODE *globalValues; 01107 01108 globalValues=GWEN_MsgEngine__GetGlobalValues(e); 01109 assert(globalValues); 01110 01111 if (pvalue) { 01112 DBG_DEBUG(GWEN_LOGDOMAIN, "Transforming value \"%s\"", pvalue); 01113 /* check whether the value is a property */ 01114 p=pvalue; 01115 while (*p && isspace((int)*p)) 01116 p++; 01117 if (*p=='$' || *p=='+') { 01118 /* global property */ 01119 int incr; 01120 01121 incr=(*p=='+'); 01122 p++; 01123 01124 DBG_DEBUG(GWEN_LOGDOMAIN, "Getting global property \"%s\"", p); 01125 if (incr) { 01126 int z; 01127 01128 z=GWEN_DB_GetIntValue(globalValues, p, 0, 0); 01129 DBG_DEBUG(GWEN_LOGDOMAIN, "Incrementing global property \"%s\" (%d)", 01130 p, z); 01131 if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) { 01132 DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string"); 01133 return 0; 01134 } 01135 01136 z++; 01137 DBG_DEBUG(GWEN_LOGDOMAIN, "Setting global property \"%s\"=%d", p, z); 01138 GWEN_DB_SetIntValue(globalValues, 01139 GWEN_DB_FLAGS_DEFAULT | 01140 GWEN_DB_FLAGS_OVERWRITE_VARS, 01141 p, z); 01142 pvalue=pbuffer; 01143 *datasize=strlen(pvalue); 01144 } 01145 else { 01146 int z; 01147 GWEN_DB_NODE_TYPE vt; 01148 const char *type = "should_be_known"; 01149 /* default value; otherwise the compiler issues a warning */ 01150 01151 DBG_DEBUG(GWEN_LOGDOMAIN, "Getting global property \"%s\"", p); 01152 vt=GWEN_DB_GetVariableType(globalValues, p); 01153 if (vt==GWEN_DB_NodeType_Unknown) { 01154 if (!GWEN_DB_VariableExists(globalValues, p)) { 01155 DBG_ERROR(GWEN_LOGDOMAIN, "Unable to determine type of \"%s\"", p); 01156 return 0; 01157 } 01158 type=GWEN_XMLNode_GetProperty(dnode, "type", "ascii"); 01159 if (GWEN_MsgEngine__IsCharTyp(e, type)) 01160 vt=GWEN_DB_NodeType_ValueChar; 01161 else if (GWEN_MsgEngine__IsIntTyp(e, type)) 01162 vt=GWEN_DB_NodeType_ValueInt; 01163 else if (GWEN_MsgEngine__IsBinTyp(e, type)) 01164 vt=GWEN_DB_NodeType_ValueBin; 01165 else { 01166 DBG_ERROR(GWEN_LOGDOMAIN, 01167 "Unable to determine type of \"%s\" (xml)", p); 01168 return 0; 01169 } 01170 } 01171 01172 switch(vt) { 01173 case GWEN_DB_NodeType_ValueChar: 01174 pvalue=GWEN_DB_GetCharValue(globalValues, p, 0, ""); 01175 *datasize=strlen(pvalue); 01176 break; 01177 01178 case GWEN_DB_NodeType_ValueInt: 01179 z=GWEN_DB_GetIntValue(globalValues, p, 0, 0); 01180 if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) { 01181 DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string"); 01182 return 0; 01183 } 01184 pvalue=pbuffer; 01185 *datasize=strlen(pvalue); 01186 break; 01187 01188 case GWEN_DB_NodeType_ValueBin: 01189 pvalue=GWEN_DB_GetBinValue(globalValues, p, 0, 01190 0,0, 01191 datasize); 01192 break; 01193 01194 default: 01195 DBG_ERROR(GWEN_LOGDOMAIN,"Unknown type %s", type); 01196 return 0; 01197 } /* switch */ 01198 } 01199 DBG_DEBUG(GWEN_LOGDOMAIN, "Value transformed"); 01200 } 01201 else if (*p=='%') { 01202 /* local property */ 01203 p++; 01204 01205 DBG_DEBUG(GWEN_LOGDOMAIN, "Getting property \"%s\"", p); 01206 pvalue=GWEN_XMLNode_GetProperty(node, p, 0); 01207 if (pvalue) { 01208 *datasize=strlen(pvalue); 01209 DBG_DEBUG(GWEN_LOGDOMAIN, "Transformed value \"%s\"", pvalue); 01210 } 01211 else 01212 *datasize=0; 01213 } 01214 else if (*p=='?') { 01215 GWEN_DB_NODE_TYPE vt; 01216 int z; 01217 const char *dtype; 01218 01219 /* get type */ 01220 dtype=GWEN_XMLNode_GetProperty(dnode, "type","ASCII"); 01221 01222 /* program variable accessable via callback */ 01223 p++; 01224 DBG_DEBUG(GWEN_LOGDOMAIN, "Getting program variable \"%s\"", p); 01225 01226 pvalue=0; 01227 if (GWEN_MsgEngine__IsCharTyp(e, dtype)) 01228 vt=GWEN_DB_NodeType_ValueChar; 01229 else if (GWEN_MsgEngine__IsIntTyp(e, dtype)) 01230 vt=GWEN_DB_NodeType_ValueInt; 01231 else { 01232 vt=GWEN_DB_NodeType_ValueChar; 01233 } 01234 01235 switch(vt) { 01236 case GWEN_DB_NodeType_ValueChar: 01237 if (e->getCharValuePtr) { 01238 pvalue=e->getCharValuePtr(e, p, 0); 01239 if (pvalue) 01240 *datasize=strlen(pvalue); 01241 } 01242 break; 01243 01244 case GWEN_DB_NodeType_ValueInt: 01245 if (e->getIntValuePtr) { 01246 z=e->getIntValuePtr(e, p, 0); 01247 if (GWEN_Text_NumToString(z, pbuffer, sizeof(pbuffer),0)<1) { 01248 DBG_ERROR(GWEN_LOGDOMAIN, "Error converting num to string"); 01249 return 0; 01250 } 01251 pvalue=pbuffer; 01252 *datasize=strlen(pvalue); 01253 } 01254 else { 01255 DBG_NOTICE(GWEN_LOGDOMAIN, "Callback for getIntValue not set"); 01256 } 01257 break; 01258 01259 default: 01260 DBG_ERROR(GWEN_LOGDOMAIN,"Unhandled type %s", dtype); 01261 return 0; 01262 } /* switch */ 01263 01264 DBG_DEBUG(GWEN_LOGDOMAIN, "Value transformed"); 01265 } 01266 else { 01267 *datasize=strlen(pvalue); 01268 } 01269 } 01270 return pvalue; 01271 } 01272 01273 01274 01275 const char *GWEN_MsgEngine_SearchForProperty(GWEN_XMLNODE *node, 01276 GWEN_XMLNODE *refnode, 01277 const char *name, 01278 int topDown) { 01279 const char *pvalue; 01280 GWEN_XMLNODE *pn; 01281 const char *lastValue; 01282 01283 DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\" in properties", name); 01284 lastValue=0; 01285 01286 pvalue=GWEN_XMLNode_GetProperty(node, name,0); 01287 if (pvalue) { 01288 if (!topDown) 01289 return pvalue; 01290 DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value (%s), but will look further", pvalue); 01291 lastValue=pvalue; 01292 } 01293 01294 pn=refnode; 01295 while(pn) { 01296 pvalue=GWEN_XMLNode_GetProperty(pn, name,0); 01297 if (pvalue) { 01298 if (!topDown) 01299 return pvalue; 01300 DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value (%s), but will look further", pvalue); 01301 lastValue=pvalue; 01302 } 01303 pn=GWEN_XMLNode_GetParent(pn); 01304 } /* while */ 01305 return lastValue; 01306 } 01307 01308 01309 01310 int GWEN_MsgEngine_GetHighestTrustLevel(GWEN_XMLNODE *node, 01311 GWEN_XMLNODE *refnode) { 01312 int value; 01313 GWEN_XMLNODE *pn; 01314 int highestTrust; 01315 01316 highestTrust=0; 01317 01318 value=atoi(GWEN_XMLNode_GetProperty(node, "trustlevel","0")); 01319 if (value>highestTrust) 01320 highestTrust=value; 01321 01322 pn=node; 01323 while(pn) { 01324 value=atoi(GWEN_XMLNode_GetProperty(pn, "trustlevel","0")); 01325 if (value>highestTrust) 01326 highestTrust=value; 01327 pn=GWEN_XMLNode_GetParent(pn); 01328 } /* while */ 01329 01330 pn=refnode; 01331 while(pn) { 01332 value=atoi(GWEN_XMLNode_GetProperty(pn, "trustlevel","0")); 01333 if (value>highestTrust) 01334 highestTrust=value; 01335 pn=GWEN_XMLNode_GetParent(pn); 01336 } /* while */ 01337 return highestTrust; 01338 } 01339 01340 01341 01342 const char *GWEN_MsgEngine__SearchForValue(GWEN_MSGENGINE *e, 01343 GWEN_XMLNODE *node, 01344 GWEN_XMLNODE_PATH *nodePath, 01345 const char *name, 01346 unsigned int *datasize) { 01347 const char *pvalue; 01348 GWEN_XMLNODE *pn; 01349 char *bufferPtr; 01350 int topDown; 01351 const char *lastValue; 01352 unsigned int lastDataSize; 01353 unsigned int ldatasize; 01354 01355 DBG_DEBUG(GWEN_LOGDOMAIN, "Searching for value of \"%s\" in <VALUES>", 01356 name); 01357 if (!node) { 01358 DBG_WARN(GWEN_LOGDOMAIN, "No node !"); 01359 } 01360 topDown=atoi(GWEN_XMLNode_GetProperty(node, "topdown", "0")); 01361 lastValue=0; 01362 lastDataSize=0; 01363 01364 bufferPtr=0; 01365 01366 /*pn=GWEN_XMLNode_GetParent(node);*/ 01367 pn=GWEN_XMLNode_Path_Surface(nodePath); 01368 while(pn) { 01369 const char *ppath; 01370 /* 01371 if (GWEN_XMLNode_GetType(pn)==GWEN_XMLNodeTypeTag) { 01372 DBG_NOTICE(GWEN_LOGDOMAIN, "Checking node \"%s\"", 01373 GWEN_XMLNode_GetData(pn)); 01374 }*/ 01375 pvalue=GWEN_MsgEngine__findInValues(e, pn, node, name, &ldatasize); 01376 if (pvalue) { 01377 if (!topDown) { 01378 free(bufferPtr); 01379 *datasize=ldatasize; 01380 return pvalue; 01381 } 01382 DBG_DEBUG(GWEN_LOGDOMAIN, "Found a value, but will look further"); 01383 lastValue=pvalue; 01384 lastDataSize=ldatasize; 01385 } 01386 01387 ppath=GWEN_XMLNode_GetProperty(pn, "name", ""); 01388 01389 if (*ppath) { 01390 int i; 01391 char *tmpptr; 01392 01393 if (bufferPtr) { 01394 i=strlen(bufferPtr)+strlen(ppath)+2; 01395 tmpptr=(char*)malloc(i); 01396 assert(tmpptr); 01397 sprintf(tmpptr, "%s/%s", ppath, bufferPtr); 01398 free(bufferPtr); 01399 bufferPtr=tmpptr; 01400 } 01401 else { 01402 i=strlen(ppath)+strlen(name)+2; 01403 tmpptr=(char*)malloc(i); 01404 assert(tmpptr); 01405 sprintf(tmpptr, "%s/%s", ppath, name); 01406 bufferPtr=tmpptr; 01407 } 01408 name=bufferPtr; 01409 } 01410 pn=GWEN_XMLNode_Path_Surface(nodePath); 01411 } /* while */ 01412 01413 free(bufferPtr); 01414 if (!lastValue) 01415 *datasize=0; 01416 else 01417 *datasize=lastDataSize; 01418 return lastValue; 01419 } 01420 01421 01422 01423 const char *GWEN_MsgEngine__findInValues(GWEN_MSGENGINE *e, 01424 GWEN_XMLNODE *node, 01425 GWEN_XMLNODE *dnode, 01426 const char *name, 01427 unsigned int *datasize) { 01428 GWEN_XMLNODE *pn; 01429 01430 DBG_VERBOUS(GWEN_LOGDOMAIN, "Looking for value of \"%s\" in <VALUES>", name); 01431 pn=GWEN_XMLNode_GetChild(node); 01432 01433 while(pn) { 01434 if (GWEN_XMLNode_GetType(pn)==GWEN_XMLNodeTypeTag) { 01435 GWEN_XMLNODE *n; 01436 const char *p; 01437 01438 p=GWEN_XMLNode_GetData(pn); 01439 assert(p); 01440 DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s", p); 01441 if (strcasecmp(p, "VALUES")==0) { 01442 DBG_DEBUG(GWEN_LOGDOMAIN, "<values> found"); 01443 /* <preset> found, check all values */ 01444 n=GWEN_XMLNode_GetChild(pn); 01445 while(n) { 01446 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 01447 p=GWEN_XMLNode_GetData(n); 01448 assert(p); 01449 if (strcasecmp(p, "VALUE")==0) { 01450 const char *pname; 01451 const char *pvalue; 01452 01453 pname=GWEN_XMLNode_GetProperty(n, "path", 0); 01454 if (pname) { 01455 DBG_DEBUG(GWEN_LOGDOMAIN, "Comparing against \"%s\"", pname); 01456 if (strcasecmp(name, pname)==0) { 01457 GWEN_XMLNODE *dn; 01458 01459 dn=GWEN_XMLNode_GetChild(n); 01460 while (dn) { 01461 if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) { 01462 pvalue=GWEN_XMLNode_GetData(dn); 01463 if (pvalue) { 01464 DBG_DEBUG(GWEN_LOGDOMAIN, "Transforming \"%s\"", pvalue); 01465 pvalue=GWEN_MsgEngine__TransformValue(e, 01466 pvalue, 01467 node, 01468 dnode, 01469 datasize); 01470 } 01471 if (pvalue) 01472 return pvalue; 01473 } 01474 dn=GWEN_XMLNode_Next(dn); 01475 } /* while dn */ 01476 } /* if path matches name */ 01477 } /* if path given */ 01478 } /* if VALUE tag */ 01479 } /* if TAG */ 01480 n=GWEN_XMLNode_Next(n); 01481 } /* while */ 01482 break; /* REMOVE this to check multiple groups */ 01483 } /* if <preset> found */ 01484 } /* if tag */ 01485 pn=GWEN_XMLNode_Next(pn); 01486 } /* while node */ 01487 01488 DBG_DEBUG(GWEN_LOGDOMAIN, "No value found for \"%s\" in <VALUES>", name); 01489 return 0; 01490 } 01491 01492 01493 01494 GWEN_XMLNODE *GWEN_MsgEngine__GetGroup(GWEN_MSGENGINE *e, 01495 GWEN_XMLNODE *node, 01496 const char *t, 01497 int version, 01498 const char *pvalue) { 01499 GWEN_XMLNODE *n; 01500 const char *p; 01501 int i; 01502 const char *mode; 01503 unsigned int proto; 01504 char buffer[256]; 01505 01506 if ((strlen(t)+4)>sizeof(buffer)) { 01507 DBG_ERROR(GWEN_LOGDOMAIN, "Type name too long."); 01508 return 0; 01509 } 01510 01511 mode=GWEN_MsgEngine_GetMode(e); 01512 proto=GWEN_MsgEngine_GetProtocolVersion(e); 01513 01514 /* find type+"S" */ 01515 strcpy(buffer, t); 01516 strcat(buffer,"S"); 01517 n=GWEN_XMLNode_FindFirstTag(node, buffer, 0, 0); 01518 if (!n) { 01519 DBG_DEBUG(GWEN_LOGDOMAIN, 01520 "No definitions here for type \"%s\"", t); 01521 return 0; 01522 } 01523 01524 /* find approppriate group definition */ 01525 if (!mode) 01526 mode=""; 01527 n=GWEN_XMLNode_GetFirstTag(n); 01528 if (!n) { 01529 DBG_INFO(GWEN_LOGDOMAIN, "No definitions inside \"%s\"", buffer); 01530 return 0; 01531 } 01532 01533 /* find type+"def" */ 01534 strcpy(buffer, t); 01535 strcat(buffer, "def"); 01536 while(n) { 01537 p=GWEN_XMLNode_GetData(n); 01538 assert(p); 01539 if (strcasecmp(p, buffer)==0 || 01540 strcasecmp(p, t)==0) { 01541 p=GWEN_XMLNode_GetProperty(n, "id", ""); 01542 if (strcasecmp(p, pvalue)!=0) 01543 p=GWEN_XMLNode_GetProperty(n, "name", ""); 01544 if (strcasecmp(p, pvalue)==0) { 01545 i=atoi(GWEN_XMLNode_GetProperty(n, "pversion" ,"0")); 01546 if (proto==0 || (int)proto==i || i==0) { 01547 i=atoi(GWEN_XMLNode_GetProperty(n, "version" ,"0")); 01548 if (version==0 || version==i) { 01549 p=GWEN_XMLNode_GetProperty(n, "mode",""); 01550 if (strcasecmp(p, mode)==0 || !*p) { 01551 DBG_DEBUG(GWEN_LOGDOMAIN, 01552 "Group definition for \"%s=%s\" found", 01553 t, pvalue); 01554 return n; 01555 } 01556 } 01557 } 01558 } 01559 } 01560 n=GWEN_XMLNode_GetNextTag(n); 01561 } /* while */ 01562 01563 DBG_DEBUG(GWEN_LOGDOMAIN, 01564 "Group definition for \"%s=%s\"(%d) not found here", 01565 t, 01566 pvalue, 01567 version); 01568 return 0; 01569 } 01570 01571 01572 01573 GWEN_XMLNODE *GWEN_MsgEngine_GetGroup(GWEN_MSGENGINE *e, 01574 GWEN_XMLNODE *node, 01575 const GWEN_XMLNODE_PATH *nodePath, 01576 const char *t, 01577 int version, 01578 const char *pvalue) { 01579 GWEN_XMLNODE *n; 01580 GWEN_XMLNODE *nLast = 0; 01581 GWEN_XMLNODE *nRes = 0; 01582 GWEN_XMLNODE_PATH *pathCopy; 01583 01584 assert(node); 01585 assert(nodePath); 01586 assert(t); 01587 assert(pvalue); 01588 01589 pathCopy=GWEN_XMLNode_Path_dup(nodePath); 01590 n=GWEN_XMLNode_Path_Surface(pathCopy); 01591 /* first try all nodes along the path */ 01592 while(n) { 01593 nLast=n; 01594 nRes=GWEN_MsgEngine__GetGroup(e, n, t, version, pvalue); 01595 if (nRes) 01596 break; 01597 n=GWEN_XMLNode_Path_Surface(pathCopy); 01598 } 01599 GWEN_XMLNode_Path_free(pathCopy); 01600 if (nRes) { 01601 /* already found */ 01602 if (nRes==node) { 01603 DBG_ERROR(GWEN_LOGDOMAIN, "Loop detected."); 01604 return 0; 01605 } 01606 return nRes; 01607 } 01608 01609 if (nLast) 01610 n=nLast; 01611 else 01612 n=node; 01613 01614 if (n) { 01615 n=GWEN_XMLNode_GetParent(n); 01616 while(n) { 01617 nRes=GWEN_MsgEngine__GetGroup(e, n, t, version, pvalue); 01618 if (nRes) 01619 break; 01620 n=GWEN_XMLNode_GetParent(n); 01621 } 01622 } 01623 01624 /* try root as a last resort */ 01625 if (!nRes && e->defs) 01626 nRes=GWEN_MsgEngine__GetGroup(e, e->defs, t, version, pvalue); 01627 01628 if (!nRes) { 01629 DBG_DEBUG(GWEN_LOGDOMAIN, 01630 "Group definition for \"%s=%s\"(%d) not found", 01631 t, 01632 pvalue, 01633 version); 01634 return 0; 01635 } 01636 if (nRes==node) { 01637 DBG_ERROR(GWEN_LOGDOMAIN, "Loop detected."); 01638 return 0; 01639 } 01640 return nRes; 01641 } 01642 01643 01644 01645 int GWEN_MsgEngine__WriteGroup(GWEN_MSGENGINE *e, 01646 GWEN_BUFFER *gbuf, 01647 GWEN_XMLNODE *node, 01648 GWEN_XMLNODE *rnode, 01649 GWEN_DB_NODE *gr, 01650 int groupIsOptional, 01651 GWEN_XMLNODE_PATH *nodePath) { 01652 GWEN_XMLNODE *n; 01653 const char *p; 01654 char delimiter; 01655 char terminator; 01656 int isFirstElement; 01657 int omittedElements; 01658 int hasEntries; 01659 01660 01661 /* get some settings */ 01662 if (rnode) { 01663 /* get delimiter */ 01664 p=GWEN_XMLNode_GetProperty(rnode, 01665 "delimiter", 01666 GWEN_XMLNode_GetProperty(node, 01667 "delimiter", 01668 "")); 01669 delimiter=*p; 01670 01671 /* get terminating char, if any */ 01672 p=GWEN_XMLNode_GetProperty(rnode, 01673 "terminator", 01674 GWEN_XMLNode_GetProperty(node, 01675 "terminator", 01676 "")); 01677 terminator=*p; 01678 } 01679 else { 01680 /* get delimiter */ 01681 p=GWEN_XMLNode_GetProperty(node, 01682 "delimiter", 01683 ""); 01684 delimiter=*p; 01685 01686 /* get terminating char, if any */ 01687 p=GWEN_XMLNode_GetProperty(node, "terminator",""); 01688 terminator=*p; 01689 } 01690 01691 /* handle all child entries */ 01692 n=GWEN_XMLNode_GetChild(node); 01693 isFirstElement=1; 01694 omittedElements=0; 01695 hasEntries=0; 01696 if (!n) { 01697 DBG_INFO(GWEN_LOGDOMAIN, "No subnodes !"); 01698 } 01699 while(n) { 01700 int t; 01701 unsigned int minnum; 01702 unsigned int maxnum; 01703 int gversion; 01704 const char *addEmptyMode; 01705 unsigned int loopNr; 01706 01707 minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1")); 01708 maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1")); 01709 gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0")); 01710 addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one"); 01711 01712 DBG_DEBUG(GWEN_LOGDOMAIN, "Omitted elements: %d", omittedElements); 01713 t=GWEN_XMLNode_GetType(n); 01714 if (t==GWEN_XMLNodeTypeTag) { 01715 const char *typ; 01716 01717 typ=GWEN_XMLNode_GetData(n); 01718 if (typ==0) { 01719 DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)"); 01720 return -1; 01721 } 01722 if (strcasecmp(typ, "ELEM")==0) { 01723 /* element tag found */ 01724 int j; 01725 int rv; 01726 01727 DBG_VERBOUS(GWEN_LOGDOMAIN, "Found an element"); 01728 /* write element as often as needed */ 01729 for (loopNr=0; loopNr<maxnum; loopNr++) { 01730 unsigned int posBeforeElement; 01731 01732 posBeforeElement=GWEN_Buffer_GetPos(gbuf); 01733 01734 /* write delimiter, if needed */ 01735 01736 /* 01737 Replaced the following code because it did not work correctly 01738 with segment HKDAN... (aquamaniac, 2005/07/09) 01739 01740 if (!isFirstElement && delimiter) { 01741 DBG_VERBOUS(GWEN_LOGDOMAIN, "Appending %d delimiters", omittedElements+1); 01742 for (j=0; j<omittedElements+1; j++) { 01743 if (GWEN_Buffer_AppendByte(gbuf, delimiter)) { 01744 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 01745 return -1; 01746 } 01747 } 01748 }*/ 01749 01750 if (delimiter) { 01751 DBG_VERBOUS(GWEN_LOGDOMAIN, "Appending %d delimiters", 01752 omittedElements); 01753 for (j=0; j<omittedElements; j++) { 01754 if (GWEN_Buffer_AppendByte(gbuf, delimiter)) { 01755 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 01756 return -1; 01757 } 01758 } 01759 if (!isFirstElement) 01760 if (GWEN_Buffer_AppendByte(gbuf, delimiter)) { 01761 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 01762 return -1; 01763 } 01764 } 01765 01766 rv=GWEN_MsgEngine__WriteElement(e, 01767 gbuf, 01768 n, 01769 rnode, 01770 gr, 01771 loopNr, 01772 loopNr>=minnum || 01773 (groupIsOptional && !hasEntries), 01774 nodePath); 01775 if (rv==-1) { 01776 DBG_INFO(GWEN_LOGDOMAIN, "Error writing element"); 01777 DBG_INFO(GWEN_LOGDOMAIN, "Node is:"); 01778 GWEN_XMLNode_Dump(n, 1); 01779 if (gr) { 01780 DBG_INFO(GWEN_LOGDOMAIN, "Data is:"); 01781 GWEN_DB_Dump(gr, 1); 01782 } 01783 return -1; 01784 } 01785 else if (rv==0) { 01786 isFirstElement=0; 01787 omittedElements=0; 01788 hasEntries=1; 01789 DBG_DEBUG(GWEN_LOGDOMAIN, "Element written"); 01790 } 01791 else { 01792 /* element is optional, not found */ 01793 /* restore position */ 01794 GWEN_Buffer_SetPos(gbuf, posBeforeElement); 01795 GWEN_Buffer_Crop(gbuf, 0, posBeforeElement); 01796 01797 if (strcasecmp(addEmptyMode, "max")==0) { 01798 DBG_DEBUG(GWEN_LOGDOMAIN, "Adding max empty"); 01799 omittedElements+=(maxnum-loopNr); 01800 } 01801 else if (strcasecmp(addEmptyMode, "min")==0) { 01802 DBG_DEBUG(GWEN_LOGDOMAIN, "Adding min empty"); 01803 if (loopNr<minnum) 01804 omittedElements+=(minnum-loopNr); 01805 } 01806 else if (strcasecmp(addEmptyMode, "one")==0) { 01807 if (loopNr==0) 01808 omittedElements++; 01809 } 01810 else if (strcasecmp(addEmptyMode, "none")==0) { 01811 } 01812 else { 01813 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown addemptymode \"%s\"", 01814 addEmptyMode); 01815 return -1; 01816 } 01817 break; 01818 } 01819 } /* for */ 01820 } 01821 else if (strcasecmp(typ, "VALUES")==0) { 01822 } 01823 else if (strcasecmp(typ, "DESCR")==0) { 01824 } 01825 else { 01826 /* group tag found */ 01827 GWEN_XMLNODE *gn; 01828 GWEN_DB_NODE *gcfg; 01829 const char *gname; 01830 const char *gtype; 01831 unsigned int posBeforeGroup; 01832 01833 DBG_VERBOUS(GWEN_LOGDOMAIN, "Found a group"); 01834 01835 gcfg=0; 01836 gtype=GWEN_XMLNode_GetProperty(n, "type",0); 01837 if (!gtype) { 01838 /* no "type" property, so use this group directly */ 01839 DBG_INFO(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ); 01840 gtype=""; 01841 gn=n; 01842 } 01843 else { 01844 DBG_VERBOUS(GWEN_LOGDOMAIN, "<%s> tag is of type \"%s\"", typ, gtype); 01845 gn=GWEN_MsgEngine_GetGroup(e, n, nodePath, typ, 01846 gversion, gtype); 01847 if (!gn) { 01848 DBG_INFO(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ); 01849 return -1; 01850 } 01851 } 01852 01853 gname=0; 01854 gcfg=0; 01855 if (gr) { 01856 gname=GWEN_XMLNode_GetProperty(n, "name",0); 01857 if (gname) { 01858 DBG_VERBOUS(GWEN_LOGDOMAIN, "Group \"%s\" using special data", gname); 01859 gcfg=GWEN_DB_GetFirstGroup(gr); 01860 } 01861 else { 01862 DBG_DEBUG(GWEN_LOGDOMAIN, "Unnamed group, using basic data"); 01863 gcfg=gr; 01864 } 01865 } 01866 01867 /* write group as often as needed */ 01868 for (loopNr=0; loopNr<maxnum; loopNr++) { 01869 int rv; 01870 int groupIsEmpty; 01871 01872 groupIsEmpty=0; 01873 posBeforeGroup=GWEN_Buffer_GetPos(gbuf); 01874 01875 /* find next matching group */ 01876 if (gname) { 01877 DBG_DEBUG(GWEN_LOGDOMAIN, "Finding next group named \"%s\"", gname); 01878 while(gcfg) { 01879 if (strcasecmp(GWEN_DB_GroupName(gcfg), gname)==0) 01880 break; 01881 gcfg=GWEN_DB_GetNextGroup(gcfg); 01882 if (gcfg==0) { 01883 DBG_DEBUG(GWEN_LOGDOMAIN, "No group found"); 01884 if (loopNr>=minnum) 01885 groupIsEmpty=1; 01886 } 01887 } /* while */ 01888 } 01889 01890 if (!groupIsEmpty) { 01891 int dive; 01892 01893 /* write delimiter, if needed */ 01894 if (!isFirstElement && delimiter) { 01895 int j; 01896 01897 DBG_VERBOUS(GWEN_LOGDOMAIN, "Appending %d delimiters", omittedElements+1); 01898 for (j=0; j<omittedElements+1; j++) { 01899 if (GWEN_Buffer_AppendByte(gbuf, delimiter)) { 01900 return -1; 01901 } 01902 } 01903 omittedElements=0; 01904 } 01905 else 01906 isFirstElement=0; 01907 01908 /* write group */ 01909 01910 if (GWEN_XMLNode_Path_Dive(nodePath, n)) { 01911 DBG_INFO(GWEN_LOGDOMAIN, "Called from here"); 01912 return -1; 01913 } 01914 if (n==gn) 01915 dive=1; 01916 else { 01917 if (GWEN_XMLNode_Path_Dive(nodePath, gn)) { 01918 DBG_INFO(GWEN_LOGDOMAIN, "Called from here"); 01919 return -1; 01920 } 01921 dive=2; 01922 } 01923 rv=GWEN_MsgEngine__WriteGroup(e, 01924 gbuf, 01925 gn, 01926 n, 01927 gcfg, 01928 loopNr>=minnum || groupIsOptional, 01929 nodePath); 01930 GWEN_XMLNode_Path_Surface(nodePath); 01931 if (dive==2) 01932 GWEN_XMLNode_Path_Surface(nodePath); 01933 if (rv==-1){ 01934 DBG_INFO(GWEN_LOGDOMAIN, "Could not write group \"%s\"", gtype); 01935 if (gn) { 01936 DBG_INFO(GWEN_LOGDOMAIN, "Node is:"); 01937 GWEN_XMLNode_Dump(gn, 1); 01938 } 01939 if (n) { 01940 DBG_INFO(GWEN_LOGDOMAIN, "Referring node is:"); 01941 GWEN_XMLNode_Dump(n, 1); 01942 } 01943 if (gr) { 01944 DBG_INFO(GWEN_LOGDOMAIN, "Data is:"); 01945 GWEN_DB_Dump(gr, 1); 01946 } 01947 return -1; 01948 } 01949 else if (rv==0) { 01950 hasEntries=1; 01951 } 01952 else 01953 groupIsEmpty=1; 01954 } 01955 01956 if (groupIsEmpty) { 01957 DBG_DEBUG(GWEN_LOGDOMAIN, "Empty Group"); 01958 GWEN_Buffer_SetPos(gbuf, posBeforeGroup); 01959 GWEN_Buffer_Crop(gbuf, 0, posBeforeGroup); 01960 01961 if (loopNr>=minnum) { 01962 DBG_DEBUG(GWEN_LOGDOMAIN, "No data for group \"%s[%d]\", omitting", 01963 gname, loopNr); 01964 if (strcasecmp(addEmptyMode, "max")==0) { 01965 DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding max empty"); 01966 omittedElements+=(maxnum-loopNr); 01967 } 01968 else if (strcasecmp(addEmptyMode, "min")==0) { 01969 DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding min empty"); 01970 if (loopNr<minnum) 01971 omittedElements+=(minnum-loopNr); 01972 } 01973 else if (strcasecmp(addEmptyMode, "one")==0) { 01974 if (loopNr==0) 01975 omittedElements++; 01976 } 01977 else if (strcasecmp(addEmptyMode, "none")==0) { 01978 } 01979 else { 01980 DBG_ERROR(GWEN_LOGDOMAIN, "Unknown addemptymode \"%s\"", 01981 addEmptyMode); 01982 return -1; 01983 } 01984 break; 01985 } 01986 else { 01987 DBG_ERROR(GWEN_LOGDOMAIN, "No data for group \"%s[%d]\"", 01988 gname, loopNr); 01989 return -1; 01990 } 01991 } /* if empty group */ 01992 /* use next group next time if any */ 01993 if (gcfg) 01994 gcfg=GWEN_DB_GetNextGroup(gcfg); 01995 } /* for */ 01996 } 01997 } 01998 else if (t==GWEN_XMLNodeTypeData) { 01999 } 02000 else { 02001 DBG_DEBUG(GWEN_LOGDOMAIN, "Unhandled node type %d", t); 02002 } 02003 n=GWEN_XMLNode_Next(n); 02004 } /* while */ 02005 02006 /* write terminating character, if any */ 02007 if (terminator) { 02008 if (GWEN_Buffer_AppendByte(gbuf, terminator)) { 02009 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 02010 return -1; 02011 } 02012 } 02013 02014 if (!hasEntries) { 02015 DBG_INFO(GWEN_LOGDOMAIN, "No entries in node"); 02016 } 02017 return hasEntries?0:1; 02018 } 02019 02020 02021 02022 int GWEN_MsgEngine_CreateMessageFromNode(GWEN_MSGENGINE *e, 02023 GWEN_XMLNODE *node, 02024 GWEN_BUFFER *gbuf, 02025 GWEN_DB_NODE *msgData){ 02026 GWEN_XMLNODE_PATH *np; 02027 int rv; 02028 02029 assert(e); 02030 assert(node); 02031 assert(msgData); 02032 02033 np=GWEN_XMLNode_Path_new(); 02034 GWEN_XMLNode_Path_Dive(np, node); 02035 rv=GWEN_MsgEngine__WriteGroup(e, 02036 gbuf, 02037 node, 02038 0, 02039 msgData, 02040 0, 02041 np); 02042 GWEN_XMLNode_Path_free(np); 02043 if (rv){ 02044 const char *p; 02045 02046 p=GWEN_XMLNode_GetData(node); 02047 if (p) { 02048 DBG_INFO(GWEN_LOGDOMAIN, "Error writing group \"%s\"", p); 02049 } 02050 else { 02051 DBG_INFO(GWEN_LOGDOMAIN, "Error writing group"); 02052 } 02053 return -1; 02054 } 02055 02056 return 0; 02057 } 02058 02059 02060 02061 int GWEN_MsgEngine_CreateMessage(GWEN_MSGENGINE *e, 02062 const char *msgName, 02063 int msgVersion, 02064 GWEN_BUFFER *gbuf, 02065 GWEN_DB_NODE *msgData) { 02066 GWEN_XMLNODE *group; 02067 02068 group=GWEN_MsgEngine_FindGroupByProperty(e, "id", msgVersion, msgName); 02069 if (!group) { 02070 DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" not found\n", msgName); 02071 return -1; 02072 } 02073 return GWEN_MsgEngine_CreateMessageFromNode(e, 02074 group, 02075 gbuf, 02076 msgData); 02077 } 02078 02079 02080 02081 int GWEN_MsgEngine_AddDefinitions(GWEN_MSGENGINE *e, 02082 GWEN_XMLNODE *node) { 02083 GWEN_XMLNODE *nsrc, *ndst; 02084 02085 assert(e); 02086 assert(node); 02087 02088 if (!e->defs) { 02089 e->defs=GWEN_XMLNode_dup(node); 02090 e->ownDefs=1; 02091 return 0; 02092 } 02093 02094 nsrc=GWEN_XMLNode_GetChild(node); 02095 while(nsrc) { 02096 if (GWEN_XMLNode_GetType(nsrc)==GWEN_XMLNodeTypeTag) { 02097 ndst=GWEN_XMLNode_FindNode(e->defs, GWEN_XMLNodeTypeTag, 02098 GWEN_XMLNode_GetData(nsrc)); 02099 if (ndst) { 02100 GWEN_XMLNODE *n; 02101 02102 n=GWEN_XMLNode_GetChild(nsrc); 02103 while (n) { 02104 GWEN_XMLNODE *newNode; 02105 02106 DBG_DEBUG(GWEN_LOGDOMAIN, "Adding node \"%s\"", GWEN_XMLNode_GetData(n)); 02107 newNode=GWEN_XMLNode_dup(n); 02108 GWEN_XMLNode_AddChild(ndst, newNode); 02109 n=GWEN_XMLNode_Next(n); 02110 } /* while n */ 02111 } 02112 else { 02113 GWEN_XMLNODE *newNode; 02114 02115 DBG_DEBUG(GWEN_LOGDOMAIN, "Adding branch \"%s\"", GWEN_XMLNode_GetData(nsrc)); 02116 newNode=GWEN_XMLNode_dup(nsrc); 02117 GWEN_XMLNode_AddChild(e->defs, newNode); 02118 } 02119 } /* if TAG */ 02120 nsrc=GWEN_XMLNode_Next(nsrc); 02121 } /* while */ 02122 02123 return 0; 02124 } 02125 02126 02127 02128 int GWEN_MsgEngine__ShowElement(GWEN_UNUSED GWEN_MSGENGINE *e, 02129 const char *path, 02130 GWEN_XMLNODE *node, 02131 GWEN_STRINGLIST *sl, 02132 uint32_t flags) { 02133 const char *name; 02134 const char *type; 02135 const char *npath; 02136 unsigned int minsize; 02137 unsigned int maxsize; 02138 unsigned int minnum; 02139 unsigned int maxnum; 02140 int j; 02141 int isSet; 02142 char nbuffer[256]; 02143 GWEN_STRINGLISTENTRY *en; 02144 02145 /* get type */ 02146 type=GWEN_XMLNode_GetProperty(node, "type","ASCII"); 02147 02148 /* get some sizes */ 02149 minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0")); 02150 maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0")); 02151 minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1")); 02152 maxnum=atoi(GWEN_XMLNode_GetProperty(node, "maxnum","1")); 02153 02154 npath=""; 02155 isSet=0; 02156 02157 /* get name */ 02158 name=GWEN_XMLNode_GetProperty(node, "name", 0); 02159 if (path==0) 02160 path=""; 02161 02162 if (name) { 02163 /* get value of a config variable */ 02164 if (strlen(path)+strlen(name)+10>=sizeof(nbuffer)) { 02165 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02166 return -1; 02167 } 02168 if (*path) 02169 sprintf(nbuffer, "%s/%s", path, name); 02170 else 02171 sprintf(nbuffer, "%s", name); 02172 npath=nbuffer; 02173 } 02174 02175 en=GWEN_StringList_FirstEntry(sl); 02176 while(en) { 02177 if (GWEN_StringListEntry_Data(en)) 02178 if (strcasecmp(GWEN_StringListEntry_Data(en), npath)==0) { 02179 isSet=1; 02180 break; 02181 } 02182 en=GWEN_StringListEntry_Next(en); 02183 } /* while */ 02184 02185 if (isSet && (flags & GWEN_MSGENGINE_SHOW_FLAGS_NOSET)) 02186 return 0; 02187 02188 fprintf(stdout, " %s", 02189 npath); 02190 j=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(npath); 02191 if (j>0) { 02192 int i; 02193 02194 for (i=0; i<j; i++) 02195 fprintf(stdout, " "); 02196 } 02197 fprintf(stdout, "| %s", type); 02198 j=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(type); 02199 if (j>0) { 02200 int i; 02201 02202 for (i=0; i<j; i++) 02203 fprintf(stdout, " "); 02204 } 02205 fprintf(stdout, "| %4d-%4d", minsize, maxsize); 02206 fprintf(stdout," | %3d ", maxnum); 02207 fprintf(stdout," |"); 02208 if (minnum==0) 02209 fprintf(stdout," optvar"); 02210 if (flags & GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL) 02211 fprintf(stdout," optgrp"); 02212 02213 if (isSet) { 02214 fprintf(stdout," set"); 02215 } 02216 02217 fprintf(stdout,"\n"); 02218 02219 return 0; 02220 } 02221 02222 02223 02224 int GWEN_MsgEngine__ShowGroup(GWEN_MSGENGINE *e, 02225 const char *path, 02226 GWEN_XMLNODE *node, 02227 GWEN_XMLNODE *rnode, 02228 GWEN_STRINGLIST *sl, 02229 uint32_t flags) { 02230 GWEN_XMLNODE *n; 02231 int isFirstElement; 02232 int omittedElements; 02233 int rv; 02234 02235 /* setup data */ 02236 n=GWEN_XMLNode_GetChild(node); 02237 02238 if (path==0) 02239 path=""; 02240 if (*path=='/') 02241 path++; 02242 02243 while(n) { 02244 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 02245 const char *p; 02246 02247 p=GWEN_XMLNode_GetData(n); 02248 assert(p); 02249 DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s",p); 02250 if (strcasecmp(p, "VALUES")==0) 02251 break; 02252 } /* if tag */ 02253 n=GWEN_XMLNode_Next(n); 02254 } /* while */ 02255 02256 if (n) { 02257 DBG_DEBUG(GWEN_LOGDOMAIN, "<preset> found"); 02258 /* <preset> found, handle all values */ 02259 n=GWEN_XMLNode_GetChild(n); 02260 while(n) { 02261 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 02262 const char *p; 02263 02264 p=GWEN_XMLNode_GetData(n); 02265 assert(p); 02266 if (strcasecmp(p, "VALUE")==0) { 02267 const char *pname; 02268 const char *pvalue; 02269 02270 pname=GWEN_XMLNode_GetProperty(n, "path", 0); 02271 if (pname) { 02272 GWEN_XMLNODE *dn; 02273 02274 /* path found, find data */ 02275 dn=GWEN_XMLNode_GetChild(n); 02276 while (dn) { 02277 if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) { 02278 pvalue=GWEN_XMLNode_GetData(dn); 02279 if (pvalue) { 02280 char pbuffer[256]; 02281 02282 /* check whether the value is a property */ 02283 p=pvalue; 02284 while (*p && isspace((int)*p)) 02285 p++; 02286 if (strlen(path)+strlen(pname)+2>sizeof(pbuffer)) { 02287 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02288 return -1; 02289 } 02290 if (*path) 02291 sprintf(pbuffer, "%s/%s", path, pname); 02292 else 02293 sprintf(pbuffer, "%s", pname); 02294 GWEN_StringList_AppendString(sl, 02295 pbuffer, 02296 0, 02297 1); 02298 } 02299 break; 02300 } 02301 dn=GWEN_XMLNode_Next(dn); 02302 } /* while dn */ 02303 } /* if path given */ 02304 } /* if VALUE tag */ 02305 } /* if TAG */ 02306 n=GWEN_XMLNode_Next(n); 02307 } /* while */ 02308 } /* if <preset> found */ 02309 02310 /* now handle all child entries */ 02311 n=GWEN_XMLNode_GetChild(node); 02312 isFirstElement=1; 02313 omittedElements=0; 02314 while(n) { 02315 int t; 02316 unsigned int minnum; 02317 unsigned int maxnum; 02318 int gversion; 02319 const char *addEmptyMode; 02320 unsigned int loopNr; 02321 unsigned int lflags; 02322 02323 minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1")); 02324 maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1")); 02325 gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0")); 02326 addEmptyMode=GWEN_XMLNode_GetProperty(n, "addemptymode","one"); 02327 02328 lflags=flags; 02329 02330 DBG_DEBUG(GWEN_LOGDOMAIN, "Omitted elements: %d", omittedElements); 02331 t=GWEN_XMLNode_GetType(n); 02332 if (t==GWEN_XMLNodeTypeTag) { 02333 const char *typ; 02334 02335 typ=GWEN_XMLNode_GetData(n); 02336 if (typ==0) { 02337 DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)"); 02338 return -1; 02339 } 02340 if (strcasecmp(typ, "ELEM")==0) { 02341 /* element tag found */ 02342 02343 /* write element as often as needed */ 02344 rv=GWEN_MsgEngine__ShowElement(e, 02345 path, 02346 n, 02347 sl, 02348 lflags); 02349 if (rv==-1) 02350 return -1; 02351 else { 02352 isFirstElement=0; 02353 omittedElements=0; 02354 } 02355 } 02356 else if (strcasecmp(typ, "VALUES")==0) { 02357 } 02358 else if (strcasecmp(typ, "DESCR")==0) { 02359 } 02360 else { 02361 /* group tag found */ 02362 GWEN_XMLNODE *gn; 02363 const char *gname; 02364 const char *gtype; 02365 02366 if (minnum==0) 02367 lflags|=GWEN_MSGENGINE_SHOW_FLAGS_OPTIONAL; 02368 02369 gtype=GWEN_XMLNode_GetProperty(n, "type",0); 02370 if (!gtype) { 02371 /* no "type" property, so use this group directly */ 02372 DBG_DEBUG(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ); 02373 gtype=""; 02374 gn=n; 02375 } 02376 else { 02377 gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype); 02378 if (!gn) { 02379 DBG_DEBUG(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ); 02380 return -1; 02381 } 02382 } 02383 02384 /* write group as often as needed */ 02385 for (loopNr=0; loopNr<maxnum; loopNr++) { 02386 /* find group */ 02387 char pbuffer[256]; 02388 const char *npath; 02389 02390 /* get configuration */ 02391 gname=GWEN_XMLNode_GetProperty(n, "name",0); 02392 if (gname) { 02393 if (loopNr==0) { 02394 if (strlen(path)+strlen(gname)+1>sizeof(pbuffer)) { 02395 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02396 return -1; 02397 } 02398 sprintf(pbuffer, "%s/%s", path, gname); 02399 npath=pbuffer; 02400 } 02401 else { 02402 /* this is not the first one, so create new name */ 02403 if (strlen(path)+strlen(gname)+10>sizeof(pbuffer)) { 02404 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02405 return -1; 02406 } 02407 if (*path) 02408 sprintf(pbuffer, "%s/%s%d", path, gname, loopNr); 02409 else 02410 sprintf(pbuffer, "%s%d", gname, loopNr); 02411 /* get the value of the given var */ 02412 npath=pbuffer; 02413 } 02414 } /* if name given */ 02415 else 02416 npath=path; 02417 02418 /* write group */ 02419 if (GWEN_MsgEngine__ShowGroup(e, 02420 npath, 02421 gn, 02422 n, 02423 sl, 02424 lflags)) { 02425 DBG_INFO(GWEN_LOGDOMAIN, "Could not show group \"%s\"", gtype); 02426 return -1; 02427 } 02428 } /* for */ 02429 } 02430 } 02431 n=GWEN_XMLNode_Next(n); 02432 } /* while */ 02433 02434 return 0; 02435 } 02436 02437 02438 02439 int GWEN_MsgEngine_ShowMessage(GWEN_MSGENGINE *e, 02440 const char *typ, 02441 const char *msgName, 02442 int msgVersion, 02443 uint32_t flags) { 02444 GWEN_XMLNODE *group; 02445 GWEN_STRINGLIST *sl; 02446 int i, j; 02447 const char *p; 02448 02449 sl=GWEN_StringList_new(); 02450 02451 fprintf(stdout, "Message \"%s\" version %d\n", 02452 msgName, msgVersion); 02453 for (i=0; i<76; i++) 02454 fprintf(stdout, "="); 02455 fprintf(stdout, "\n"); 02456 p=" Variable"; 02457 fprintf(stdout, "%s", p); 02458 i=GWEN_MSGENGINE_VARNAME_WIDTH-strlen(p); 02459 for (j=0; j<i; j++) 02460 fprintf(stdout," "); 02461 02462 fprintf(stdout," |"); 02463 p=" Type"; 02464 fprintf(stdout, "%s", p); 02465 i=GWEN_MSGENGINE_TYPENAME_WIDTH-strlen(p); 02466 for (j=0; j<i; j++) 02467 fprintf(stdout," "); 02468 02469 fprintf(stdout," | Size | Num | Flags\n"); 02470 for (i=0; i<76; i++) 02471 fprintf(stdout, "-"); 02472 fprintf(stdout, "\n"); 02473 02474 group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", msgVersion, msgName); 02475 if (!group) { 02476 DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" not found\n", msgName); 02477 GWEN_StringList_free(sl); 02478 return -1; 02479 } 02480 02481 if (GWEN_MsgEngine__ShowGroup(e, 02482 "", 02483 group, 02484 0, 02485 sl, 02486 flags)) { 02487 DBG_INFO(GWEN_LOGDOMAIN, "Error showing group \"%s\"", msgName); 02488 GWEN_StringList_free(sl); 02489 return -1; 02490 } 02491 02492 GWEN_StringList_free(sl); 02493 02494 return 0; 02495 } 02496 02497 02498 02499 int GWEN_MsgEngine__ListElement(GWEN_UNUSED GWEN_MSGENGINE *e, 02500 const char *path, 02501 GWEN_XMLNODE *node, 02502 GWEN_STRINGLIST *sl, 02503 GWEN_XMLNODE *listNode, 02504 uint32_t flags) { 02505 const char *name; 02506 const char *type; 02507 const char *npath; 02508 int isSet; 02509 char nbuffer[256]; 02510 GWEN_STRINGLISTENTRY *en; 02511 GWEN_XMLNODE *nn; 02512 02513 /* get type */ 02514 type=GWEN_XMLNode_GetProperty(node, "type","ASCII"); 02515 02516 npath=""; 02517 isSet=0; 02518 02519 /* get name */ 02520 name=GWEN_XMLNode_GetProperty(node, "name", 0); 02521 if (path==0) 02522 path=""; 02523 02524 if (name) { 02525 /* get value of a config variable */ 02526 if (strlen(path)+strlen(name)+10>=sizeof(nbuffer)) { 02527 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02528 return -1; 02529 } 02530 if (*path) 02531 sprintf(nbuffer, "%s/%s", path, name); 02532 else 02533 sprintf(nbuffer, "%s", name); 02534 npath=nbuffer; 02535 } 02536 02537 en=GWEN_StringList_FirstEntry(sl); 02538 while(en) { 02539 if (GWEN_StringListEntry_Data(en)) 02540 if (strcasecmp(GWEN_StringListEntry_Data(en), npath)==0) { 02541 isSet=1; 02542 break; 02543 } 02544 en=GWEN_StringListEntry_Next(en); 02545 } /* while */ 02546 02547 if (isSet && (flags & GWEN_MSGENGINE_SHOW_FLAGS_NOSET)) 02548 return 0; 02549 02550 nn=GWEN_XMLNode_dup(node); 02551 if (isSet) 02552 GWEN_XMLNode_SetProperty(nn, "GWEN_set", "1"); 02553 GWEN_XMLNode_SetProperty(nn, "GWEN_path", npath); 02554 GWEN_XMLNode_AddChild(listNode, nn); 02555 02556 return 0; 02557 } 02558 02559 02560 02561 int GWEN_MsgEngine__ListGroup(GWEN_MSGENGINE *e, 02562 const char *path, 02563 GWEN_XMLNODE *node, 02564 GWEN_XMLNODE *rnode, 02565 GWEN_STRINGLIST *sl, 02566 GWEN_XMLNODE *listNode, 02567 uint32_t flags) { 02568 GWEN_XMLNODE *n; 02569 int rv; 02570 02571 /* setup data */ 02572 n=GWEN_XMLNode_GetChild(node); 02573 02574 if (path==0) 02575 path=""; 02576 if (*path=='/') 02577 path++; 02578 02579 while(n) { 02580 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 02581 const char *p; 02582 02583 p=GWEN_XMLNode_GetData(n); 02584 assert(p); 02585 DBG_DEBUG(GWEN_LOGDOMAIN, "Checking %s",p); 02586 if (strcasecmp(p, "VALUES")==0) 02587 break; 02588 } /* if tag */ 02589 n=GWEN_XMLNode_Next(n); 02590 } /* while */ 02591 02592 if (n) { 02593 DBG_DEBUG(GWEN_LOGDOMAIN, "<values> found"); 02594 /* <values> found, handle all values */ 02595 n=GWEN_XMLNode_GetChild(n); 02596 while(n) { 02597 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 02598 const char *p; 02599 02600 p=GWEN_XMLNode_GetData(n); 02601 assert(p); 02602 if (strcasecmp(p, "VALUE")==0) { 02603 const char *pname; 02604 const char *pvalue; 02605 02606 pname=GWEN_XMLNode_GetProperty(n, "path", 0); 02607 if (pname) { 02608 GWEN_XMLNODE *dn; 02609 02610 /* path found, find data */ 02611 dn=GWEN_XMLNode_GetChild(n); 02612 while (dn) { 02613 if (GWEN_XMLNode_GetType(dn)==GWEN_XMLNodeTypeData) { 02614 pvalue=GWEN_XMLNode_GetData(dn); 02615 if (pvalue) { 02616 char pbuffer[256]; 02617 02618 /* check whether the value is a property */ 02619 p=pvalue; 02620 while (*p && isspace((int)*p)) 02621 p++; 02622 if (strlen(path)+strlen(pname)+2>sizeof(pbuffer)) { 02623 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02624 return -1; 02625 } 02626 if (*path) 02627 sprintf(pbuffer, "%s/%s", path, pname); 02628 else 02629 sprintf(pbuffer, "%s", pname); 02630 DBG_INFO(GWEN_LOGDOMAIN, "Found preset value for %s", pbuffer); 02631 GWEN_StringList_AppendString(sl, 02632 pbuffer, 02633 0, 02634 1); 02635 } 02636 break; 02637 } 02638 dn=GWEN_XMLNode_Next(dn); 02639 } /* while dn */ 02640 } /* if path given */ 02641 } /* if VALUE tag */ 02642 } /* if TAG */ 02643 n=GWEN_XMLNode_Next(n); 02644 } /* while */ 02645 } /* if <values> found */ 02646 02647 /* now handle all child entries */ 02648 n=GWEN_XMLNode_GetChild(node); 02649 while(n) { 02650 int t; 02651 int gversion; 02652 unsigned int lflags; 02653 02654 gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0")); 02655 lflags=flags; 02656 02657 t=GWEN_XMLNode_GetType(n); 02658 if (t==GWEN_XMLNodeTypeTag) { 02659 const char *typ; 02660 02661 typ=GWEN_XMLNode_GetData(n); 02662 if (typ==0) { 02663 DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed tag found (internal error?)"); 02664 return -1; 02665 } 02666 if (strcasecmp(typ, "ELEM")==0) { 02667 /* element tag found */ 02668 02669 /* list element */ 02670 rv=GWEN_MsgEngine__ListElement(e, 02671 path, 02672 n, 02673 sl, 02674 listNode, 02675 lflags); 02676 if (rv==-1) 02677 return -1; 02678 } 02679 else if (strcasecmp(typ, "VALUES")==0) { 02680 } 02681 else if (strcasecmp(typ, "DESCR")==0) { 02682 } 02683 else { 02684 /* group tag found */ 02685 GWEN_XMLNODE *gn; 02686 GWEN_XMLNODE *nn; 02687 const char *gname; 02688 const char *gtype; 02689 char pbuffer[256]; 02690 const char *npath; 02691 02692 gtype=GWEN_XMLNode_GetProperty(n, "type",0); 02693 if (!gtype) { 02694 /* no "type" property, so use this group directly */ 02695 DBG_DEBUG(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", typ); 02696 gtype=""; 02697 gn=n; 02698 } 02699 else { 02700 gn=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", gversion, gtype); 02701 if (!gn) { 02702 DBG_DEBUG(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", typ); 02703 return -1; 02704 } 02705 } 02706 02707 /* get configuration */ 02708 gname=GWEN_XMLNode_GetProperty(n, "name",0); 02709 if (gname) { 02710 if (strlen(path)+strlen(gname)+1>sizeof(pbuffer)) { 02711 DBG_ERROR(GWEN_LOGDOMAIN, "Buffer too small"); 02712 return -1; 02713 } 02714 02715 if (*path) 02716 sprintf(pbuffer, "%s/%s", path, gname); 02717 else 02718 sprintf(pbuffer, "%s", gname); 02719 npath=pbuffer; 02720 } /* if name given */ 02721 else 02722 npath=path; 02723 02724 nn=GWEN_XMLNode_dup(n); 02725 if (gn!=n) 02726 GWEN_XMLNode_CopyProperties(nn, gn, 0); 02727 GWEN_XMLNode_SetProperty(nn, "GWEN_path", npath); 02728 GWEN_XMLNode_AddChild(listNode, nn); 02729 02730 /* write group */ 02731 if (GWEN_MsgEngine__ListGroup(e, 02732 npath, 02733 gn, 02734 n, 02735 sl, 02736 nn, 02737 lflags)) { 02738 DBG_INFO(GWEN_LOGDOMAIN, "Could not list group \"%s\"", gtype); 02739 return -1; 02740 } 02741 } 02742 } 02743 n=GWEN_XMLNode_Next(n); 02744 } /* while */ 02745 02746 return 0; 02747 } 02748 02749 02750 02751 GWEN_XMLNODE *GWEN_MsgEngine_ListMessage(GWEN_MSGENGINE *e, 02752 const char *typ, 02753 const char *msgName, 02754 int msgVersion, 02755 uint32_t flags) { 02756 GWEN_XMLNODE *group; 02757 GWEN_STRINGLIST *sl; 02758 GWEN_XMLNODE *listNode; 02759 02760 group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "id", msgVersion, msgName); 02761 if (!group) 02762 group=GWEN_MsgEngine_FindNodeByProperty(e, typ, "code", 02763 msgVersion, msgName); 02764 if (!group) { 02765 DBG_ERROR(GWEN_LOGDOMAIN, "Group \"%s\" (version %d) not found\n", 02766 msgName, msgVersion); 02767 return 0; 02768 } 02769 02770 sl=GWEN_StringList_new(); 02771 /* copy group, but remove all children (we only want the properties) */ 02772 listNode=GWEN_XMLNode_dup(group); 02773 GWEN_XMLNode_RemoveChildren(listNode); 02774 02775 if (GWEN_MsgEngine__ListGroup(e, 02776 "", 02777 group, 02778 0, 02779 sl, 02780 listNode, 02781 flags)) { 02782 DBG_INFO(GWEN_LOGDOMAIN, "Error showing group \"%s\"", msgName); 02783 GWEN_StringList_free(sl); 02784 GWEN_XMLNode_free(listNode); 02785 return 0; 02786 } 02787 02788 GWEN_StringList_free(sl); 02789 02790 return listNode; 02791 } 02792 02793 02794 02795 02796 02797 02798 02799 int GWEN_MsgEngine__ReadValue(GWEN_MSGENGINE *e, 02800 GWEN_BUFFER *msgbuf, 02801 GWEN_XMLNODE *node, 02802 GWEN_XMLNODE *rnode, 02803 GWEN_BUFFER *vbuf, 02804 const char *delimiters, 02805 uint32_t flags) { 02806 unsigned int minsize; 02807 unsigned int maxsize; 02808 unsigned int size; 02809 unsigned int minnum; 02810 GWEN_MSGENGINE_TRUSTLEVEL trustLevel; 02811 unsigned int posInMsg; 02812 const char *type; 02813 int rv; 02814 unsigned int realSize; 02815 02816 /* get some sizes */ 02817 posInMsg=GWEN_Buffer_GetPos(msgbuf); 02818 realSize=0; 02819 size=atoi(GWEN_XMLNode_GetProperty(node, "size","0")); 02820 minsize=atoi(GWEN_XMLNode_GetProperty(node, "minsize","0")); 02821 maxsize=atoi(GWEN_XMLNode_GetProperty(node, "maxsize","0")); 02822 minnum=atoi(GWEN_XMLNode_GetProperty(node, "minnum","1")); 02823 type=GWEN_XMLNode_GetProperty(node, "type","ASCII"); 02824 02825 rv=1; 02826 if (e->typeReadPtr) { 02827 rv=e->typeReadPtr(e, 02828 msgbuf, 02829 node, 02830 vbuf, 02831 e->escapeChar, 02832 delimiters); 02833 } 02834 if (rv==-1) { 02835 DBG_INFO(GWEN_LOGDOMAIN, "External type reading failed on type \"%s\"", type); 02836 return -1; 02837 } 02838 else if (rv==1) { 02839 if (strcasecmp(type, "bin")==0) { 02840 if (GWEN_Buffer_GetBytesLeft(msgbuf)==0) { 02841 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (@num@ expected)"); 02842 return -1; 02843 } 02844 else { 02845 char lbuffer[16]; 02846 int c; 02847 char *p; 02848 int l; 02849 02850 p=lbuffer; 02851 c=GWEN_Buffer_ReadByte(msgbuf); 02852 if (c!='@') { 02853 DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected"); 02854 return -1; 02855 } 02856 02857 c=0; 02858 while(GWEN_Buffer_GetBytesLeft(msgbuf)>0) { 02859 c=GWEN_Buffer_ReadByte(msgbuf); 02860 if (c==-1) { 02861 DBG_ERROR(GWEN_LOGDOMAIN, "\"@\" expected"); 02862 return -1; 02863 } 02864 if (c=='@') 02865 break; 02866 *p=(char)c; 02867 p++; 02868 } /* while */ 02869 *p=0; 02870 if (c!='@') { 02871 DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected"); 02872 return -1; 02873 } 02874 if (sscanf(lbuffer, "%d", &l)!=1) { 02875 DBG_ERROR(GWEN_LOGDOMAIN, "Bad number format"); 02876 return -1; 02877 } 02878 DBG_DEBUG(GWEN_LOGDOMAIN, "Reading binary: %d bytes from pos %d (msgsize=%d)", 02879 l, 02880 GWEN_Buffer_GetPos(msgbuf), 02881 GWEN_Buffer_GetUsedBytes(msgbuf)); 02882 if (GWEN_Buffer_GetBytesLeft(msgbuf) < (unsigned) l) { 02883 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (binary beyond end)"); 02884 return -1; 02885 } 02886 if (GWEN_Buffer_AppendBytes(vbuf, 02887 GWEN_Buffer_GetPosPointer(msgbuf), 02888 l)) { 02889 DBG_DEBUG(GWEN_LOGDOMAIN, "Called from here"); 02890 return -1; 02891 } 02892 GWEN_Buffer_IncrementPos(msgbuf,l); 02893 } 02894 } /* if bin */ 02895 else { 02896 /* type is not bin */ 02897 int lastWasEscape; 02898 int isEscaped; 02899 int br; 02900 02901 isEscaped=0; 02902 lastWasEscape=0; 02903 02904 br=0; 02905 while(GWEN_Buffer_GetBytesLeft(msgbuf) && 02906 (size==0 || br<size)) { 02907 int c; 02908 02909 c=GWEN_Buffer_ReadByte(msgbuf); 02910 if (lastWasEscape) { 02911 lastWasEscape=0; 02912 isEscaped=1; 02913 } 02914 else { 02915 isEscaped=0; 02916 if (c==e->escapeChar) { 02917 lastWasEscape=1; 02918 c=-1; 02919 } 02920 } 02921 if (c!=-1) { 02922 if (!isEscaped && (c && strchr(delimiters, c)!=0)) { 02923 /* delimiter found, step back */ 02924 GWEN_Buffer_DecrementPos(msgbuf,1); 02925 break; 02926 } 02927 else { 02928 if (c=='\\' || iscntrl(c)) { 02929 DBG_WARN(GWEN_LOGDOMAIN, 02930 "Found a bad character (%02x) in type \"%s\", " 02931 "converting to SPACE", 02932 (unsigned int)c, 02933 type); 02934 c=' '; 02935 } 02936 if (GWEN_Buffer_AppendByte(vbuf, c)) { 02937 DBG_DEBUG(GWEN_LOGDOMAIN, "Called from here"); 02938 return -1; 02939 } 02940 br++; 02941 } 02942 } 02943 } /* while */ 02944 } /* if !bin */ 02945 } /* if type not external */ 02946 else { 02947 DBG_DEBUG(GWEN_LOGDOMAIN, "Type \"%s\" is external (read)", type); 02948 } 02949 02950 realSize=GWEN_Buffer_GetUsedBytes(vbuf); 02951 02952 /* check the value */ 02953 if (realSize==0) { 02954 DBG_DEBUG(GWEN_LOGDOMAIN, "Datasize is 0"); 02955 if (minnum==0) { 02956 DBG_DEBUG(GWEN_LOGDOMAIN, "... but thats ok"); 02957 /* value is empty, and that is allowed */ 02958 return 1; 02959 } 02960 else { 02961 DBG_ERROR(GWEN_LOGDOMAIN, "Value missing"); 02962 GWEN_XMLNode_Dump(node, 1); 02963 return -1; 02964 } 02965 } 02966 02967 /* check minimum size */ 02968 if (minsize!=0 && realSize<minsize) { 02969 DBG_INFO(GWEN_LOGDOMAIN, "Value too short (%d<%d).", 02970 realSize, 02971 minsize); 02972 return -1; 02973 } 02974 02975 /* check maximum size */ 02976 if (maxsize!=0 && realSize>maxsize) { 02977 DBG_INFO(GWEN_LOGDOMAIN, "Value too long (%d>%d).", 02978 realSize, maxsize); 02979 return -1; 02980 } 02981 02982 if (flags & GWEN_MSGENGINE_READ_FLAGS_TRUSTINFO) { 02983 /* add trust data to msgEngine */ 02984 const char *descr; 02985 02986 trustLevel=GWEN_MsgEngine_GetHighestTrustLevel(node, rnode); 02987 if (trustLevel) { 02988 unsigned int ustart; 02989 02990 ustart=GWEN_Buffer_GetPos(msgbuf)-realSize; 02991 descr=GWEN_XMLNode_GetProperty(node, "name",0); 02992 if (GWEN_MsgEngine_AddTrustInfo(e, 02993 GWEN_Buffer_GetStart(vbuf), 02994 realSize, 02995 descr, 02996 trustLevel, 02997 ustart)) { 02998 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 02999 return -1; 03000 } 03001 } 03002 } 03003 03004 return 0; 03005 } 03006 03007 03008 03009 int GWEN_MsgEngine__ReadGroup(GWEN_MSGENGINE *e, 03010 GWEN_BUFFER *msgbuf, 03011 GWEN_XMLNODE *node, 03012 GWEN_XMLNODE *rnode, 03013 GWEN_DB_NODE *gr, 03014 const char *delimiters, 03015 uint32_t flags) { 03016 unsigned int minsize; 03017 unsigned int maxsize; 03018 unsigned int minnum; 03019 unsigned int maxnum; 03020 const char *name; 03021 const char *p; 03022 char delimiter; 03023 char terminator; 03024 GWEN_XMLNODE *n; 03025 int abortLoop; 03026 GWEN_BUFFER *delimBuffer=0; 03027 03028 /* get some settings */ 03029 if (rnode) { 03030 /* get delimiter */ 03031 p=GWEN_XMLNode_GetProperty(rnode, 03032 "delimiter", 03033 GWEN_XMLNode_GetProperty(node, 03034 "delimiter", 03035 "")); 03036 delimiter=*p; 03037 03038 /* get terminating char, if any */ 03039 p=GWEN_XMLNode_GetProperty(rnode, 03040 "terminator", 03041 GWEN_XMLNode_GetProperty(node, 03042 "terminator", 03043 "")); 03044 terminator=*p; 03045 } 03046 else { 03047 /* get delimiter */ 03048 p=GWEN_XMLNode_GetProperty(node, 03049 "delimiter", 03050 ""); 03051 delimiter=*p; 03052 03053 /* get terminating char, if any */ 03054 p=GWEN_XMLNode_GetProperty(node, "terminator",""); 03055 terminator=*p; 03056 } 03057 03058 delimBuffer=GWEN_Buffer_new(0, strlen(delimiters)+2, 0, 1); 03059 GWEN_Buffer_AppendString(delimBuffer, delimiters); 03060 if (delimiter) 03061 GWEN_Buffer_AppendByte(delimBuffer, delimiter); 03062 if (terminator) 03063 GWEN_Buffer_AppendByte(delimBuffer, terminator); 03064 03065 DBG_DEBUG(GWEN_LOGDOMAIN, "Delimiters are \"%s\" and \"%c\"", 03066 delimiters, delimiter); 03067 03068 n=GWEN_XMLNode_GetChild(node); 03069 while (n) { 03070 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 03071 const char *type; 03072 03073 if (GWEN_Buffer_GetBytesLeft(msgbuf)==0) 03074 break; 03075 03076 type=GWEN_XMLNode_GetData(n); 03077 03078 /* 03079 DBG_NOTICE(GWEN_LOGDOMAIN, "Reading group from here :"); 03080 GWEN_Text_DumpString(GWEN_Buffer_GetStart(msgbuf)+ 03081 GWEN_Buffer_GetPos(msgbuf), 03082 GWEN_Buffer_GetUsedBytes(msgbuf)- 03083 GWEN_Buffer_GetPos(msgbuf), 03084 stderr, 3); 03085 */ 03086 if (strcasecmp(type, "ELEM")==0) { 03087 unsigned int loopNr; 03088 03089 /* get some sizes */ 03090 minsize=atoi(GWEN_XMLNode_GetProperty(n, "minsize","0")); 03091 maxsize=atoi(GWEN_XMLNode_GetProperty(n, "maxsize","0")); 03092 minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1")); 03093 maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1")); 03094 name=GWEN_XMLNode_GetProperty(n, "name", 0); 03095 03096 loopNr=0; 03097 abortLoop=0; 03098 while((maxnum==0 || loopNr<maxnum) && !abortLoop) { 03099 int c; 03100 03101 DBG_VERBOUS(GWEN_LOGDOMAIN, "Reading %s", name); 03102 if (GWEN_Buffer_GetBytesLeft(msgbuf)==0) 03103 break; 03104 c=GWEN_Buffer_PeekByte(msgbuf); 03105 if (c==-1) { 03106 DBG_DEBUG(GWEN_LOGDOMAIN, "called from here"); 03107 GWEN_Buffer_free(delimBuffer); 03108 return -1; 03109 } 03110 03111 DBG_VERBOUS(GWEN_LOGDOMAIN, 03112 "Checking delimiter at pos %x " 03113 "(whether \"%c\" is in \"%s\")", 03114 GWEN_Buffer_GetPos(msgbuf), 03115 c, GWEN_Buffer_GetStart(delimBuffer)); 03116 if (c && strchr(GWEN_Buffer_GetStart(delimBuffer), c)) { 03117 abortLoop=1; 03118 DBG_VERBOUS(GWEN_LOGDOMAIN, 03119 "Found delimiter (\"%c\" is in \"%s\")", 03120 c, GWEN_Buffer_GetStart(delimBuffer)); 03121 } /* if delimiter found */ 03122 else { 03123 /* current char is not a delimiter */ 03124 if (name==0) { 03125 DBG_VERBOUS(GWEN_LOGDOMAIN, "no name"); 03126 } 03127 else { 03128 /* name is given */ 03129 int rv; 03130 const char *dtype; 03131 GWEN_BUFFER *vbuf; 03132 03133 DBG_VERBOUS(GWEN_LOGDOMAIN, "Reading value from pos %x", 03134 GWEN_Buffer_GetPos(msgbuf)); 03135 vbuf=GWEN_Buffer_new(0, 03136 GWEN_MSGENGINE_MAX_VALUE_LEN, 03137 0,0); 03138 /* 03139 DBG_ERROR(GWEN_LOGDOMAIN, "Reading value from here:\n"); 03140 GWEN_Text_DumpString(GWEN_Buffer_GetPosPointer(msgbuf), 03141 GWEN_Buffer_GetBytesLeft(msgbuf), 03142 stderr, 1);*/ 03143 03144 rv=GWEN_MsgEngine__ReadValue(e, 03145 msgbuf, 03146 n, 03147 rnode, 03148 vbuf, 03149 GWEN_Buffer_GetStart(delimBuffer), 03150 //":+'", 03151 flags); 03152 if (rv==1) { 03153 DBG_INFO(GWEN_LOGDOMAIN, "Empty value"); 03154 } 03155 else if (rv==-1) { 03156 DBG_INFO(GWEN_LOGDOMAIN, "Error parsing node \"%s\" (%s)", 03157 name, 03158 type); 03159 GWEN_Buffer_free(vbuf); 03160 GWEN_Buffer_free(delimBuffer); 03161 return -1; 03162 } 03163 03164 GWEN_Buffer_Rewind(vbuf); 03165 03166 /* special handling for binary data */ 03167 dtype=GWEN_XMLNode_GetProperty(n, "type", ""); 03168 if (GWEN_MsgEngine__IsBinTyp(e, dtype)) { 03169 if (atoi(GWEN_XMLNode_GetProperty(n, "readbin", "1")) && 03170 e->binTypeReadPtr) { 03171 rv=e->binTypeReadPtr(e, n, gr, vbuf); 03172 } 03173 else 03174 rv=1; 03175 if (rv==-1) { 03176 DBG_INFO(GWEN_LOGDOMAIN, "Called from here"); 03177 GWEN_Buffer_free(vbuf); 03178 GWEN_Buffer_free(delimBuffer); 03179 return -1; 03180 } 03181 else if (rv==1) { 03182 /* bin type not handled, so handle it myself */ 03183 if (GWEN_DB_SetBinValue(gr, 03184 GWEN_DB_FLAGS_DEFAULT, 03185 name, 03186 GWEN_Buffer_GetStart(vbuf), 03187 GWEN_Buffer_GetUsedBytes(vbuf))) { 03188 DBG_INFO(GWEN_LOGDOMAIN, "Could not set value for \"%s\"", name); 03189 GWEN_Buffer_free(vbuf); 03190 GWEN_Buffer_free(delimBuffer); 03191 return -1; 03192 } 03193 } 03194 } /* if type is bin */ 03195 else if (GWEN_MsgEngine__IsIntTyp(e, dtype)) { 03196 int z; 03197 03198 if (1!=sscanf(GWEN_Buffer_GetStart(vbuf), "%d", &z)) { 03199 DBG_INFO(GWEN_LOGDOMAIN, "Value for \"%s\" is not an integer", 03200 name); 03201 GWEN_Buffer_free(delimBuffer); 03202 return -1; 03203 } 03204 if (GWEN_DB_SetIntValue(gr, 03205 GWEN_DB_FLAGS_DEFAULT, 03206 name, z)) { 03207 DBG_INFO(GWEN_LOGDOMAIN, "Could not set int value for \"%s\"", name); 03208 GWEN_Buffer_free(delimBuffer); 03209 return -1; 03210 } 03211 } /* if type is int */ 03212 else { 03213 DBG_DEBUG(GWEN_LOGDOMAIN, "Value is \"%s\"", 03214 GWEN_Buffer_GetStart(vbuf)); 03215 if (GWEN_DB_SetCharValue(gr, 03216 GWEN_DB_FLAGS_DEFAULT, 03217 name, 03218 GWEN_Buffer_GetStart(vbuf))){ 03219 DBG_INFO(GWEN_LOGDOMAIN, "Could not set value for \"%s\"", name); 03220 GWEN_Buffer_free(delimBuffer); 03221 return -1; 03222 } 03223 } /* if !bin */ 03224 03225 GWEN_Buffer_free(vbuf); 03226 } /* if name is given */ 03227 } /* if current char is not a delimiter */ 03228 03229 if (GWEN_Buffer_GetBytesLeft(msgbuf)) { 03230 if (delimiter) { 03231 if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) { 03232 GWEN_Buffer_IncrementPos(msgbuf,1); 03233 } 03234 } 03235 } 03236 loopNr++; 03237 } /* while */ 03238 if (loopNr<minnum) { 03239 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (too few ELEM repeats)"); 03240 GWEN_XMLNode_Dump(n, 2); 03241 GWEN_Buffer_free(delimBuffer); 03242 return -1; 03243 } 03244 n=GWEN_XMLNode_Next(n); 03245 } /* if ELEM */ 03246 else if (strcasecmp(type, "VALUES")==0) { 03247 n=GWEN_XMLNode_Next(n); 03248 } 03249 else if (strcasecmp(type, "DESCR")==0) { 03250 n=GWEN_XMLNode_Next(n); 03251 } 03252 else { 03253 /* group tag found */ 03254 GWEN_XMLNODE *gn; 03255 GWEN_DB_NODE *gcfg; 03256 const char *gname; 03257 const char *gtype; 03258 unsigned int gversion; 03259 unsigned int loopNr; 03260 03261 minnum=atoi(GWEN_XMLNode_GetProperty(n, "minnum","1")); 03262 maxnum=atoi(GWEN_XMLNode_GetProperty(n, "maxnum","1")); 03263 gversion=atoi(GWEN_XMLNode_GetProperty(n, "version","0")); 03264 gtype=GWEN_XMLNode_GetProperty(n, "type",0); 03265 if (!gtype) { 03266 /* no "type" property, so use this group directly */ 03267 DBG_INFO(GWEN_LOGDOMAIN, "<%s> tag has no \"type\" property", type); 03268 gtype=""; 03269 gn=n; 03270 } 03271 else { 03272 gn=GWEN_MsgEngine_FindNodeByProperty(e, type, "id", 03273 gversion, gtype); 03274 if (!gn) { 03275 DBG_INFO(GWEN_LOGDOMAIN, "Definition for type \"%s\" not found", type); 03276 GWEN_Buffer_free(delimBuffer); 03277 return -1; 03278 } 03279 } 03280 03281 /* get configuration */ 03282 loopNr=0; 03283 abortLoop=0; 03284 while((maxnum==0 || loopNr<maxnum) && !abortLoop) { 03285 int c; 03286 03287 DBG_DEBUG(GWEN_LOGDOMAIN, "Reading group type %s", gtype); 03288 if (GWEN_Buffer_GetBytesLeft(msgbuf)==0) 03289 break; 03290 c=GWEN_Buffer_PeekByte(msgbuf); 03291 if (c && strchr(GWEN_Buffer_GetStart(delimBuffer), c)) { 03292 abortLoop=1; 03293 } 03294 else { 03295 gname=GWEN_XMLNode_GetProperty(n, "name",0); 03296 if (gname) { 03297 DBG_DEBUG(GWEN_LOGDOMAIN, "Creating group \"%s\"", gname); 03298 gcfg=GWEN_DB_GetGroup(gr, 03299 GWEN_PATH_FLAGS_CREATE_GROUP, 03300 gname); 03301 if (!gcfg) { 03302 DBG_ERROR(GWEN_LOGDOMAIN, "Could not select group \"%s\"", 03303 gname); 03304 GWEN_Buffer_free(delimBuffer); 03305 return -1; 03306 } 03307 DBG_DEBUG(GWEN_LOGDOMAIN, "Created group \"%s\"", gname); 03308 } /* if name given */ 03309 else 03310 gcfg=gr; 03311 03312 /* read group */ 03313 DBG_DEBUG(GWEN_LOGDOMAIN, "Reading group \"%s\"", gname); 03314 if (GWEN_MsgEngine__ReadGroup(e, 03315 msgbuf, 03316 gn, 03317 n, 03318 gcfg, 03319 GWEN_Buffer_GetStart(delimBuffer), 03320 flags)) { 03321 DBG_INFO(GWEN_LOGDOMAIN, "Could not read group \"%s\"", gtype); 03322 GWEN_Buffer_free(delimBuffer); 03323 return -1; 03324 } 03325 } 03326 if (GWEN_Buffer_GetBytesLeft(msgbuf)) { 03327 if (delimiter) { 03328 if (GWEN_Buffer_PeekByte(msgbuf)==delimiter) { 03329 GWEN_Buffer_IncrementPos(msgbuf, 1); 03330 } 03331 } 03332 } 03333 loopNr++; 03334 } /* while */ 03335 if (loopNr<minnum) { 03336 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (too few group repeats)"); 03337 GWEN_Buffer_free(delimBuffer); 03338 return -1; 03339 } 03340 n=GWEN_XMLNode_Next(n); 03341 } /* if GROUP */ 03342 } /* if TAG */ 03343 else { 03344 n=GWEN_XMLNode_Next(n); 03345 } 03346 } /* while */ 03347 03348 /* check whether there still are nodes which have not been read */ 03349 while(n) { 03350 if (GWEN_XMLNode_GetType(n)==GWEN_XMLNodeTypeTag) { 03351 if (strcasecmp(GWEN_XMLNode_GetData(n), "ELEM")==0 || 03352 strcasecmp(GWEN_XMLNode_GetData(n), "GROUP")==0) { 03353 unsigned int i; 03354 03355 i=atoi(GWEN_XMLNode_GetProperty(n, "minnum", "1")); 03356 if (i) { 03357 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (still tags to parse)"); 03358 GWEN_XMLNode_Dump(n, 2); 03359 GWEN_Buffer_free(delimBuffer); 03360 return -1; 03361 } 03362 } 03363 } 03364 n=GWEN_XMLNode_Next(n); 03365 } 03366 03367 03368 if (terminator) { 03369 /* skip terminator */ 03370 if (GWEN_Buffer_GetBytesLeft(msgbuf)) { 03371 if (GWEN_Buffer_PeekByte(msgbuf)==terminator) { 03372 GWEN_Buffer_IncrementPos(msgbuf, 1); 03373 } 03374 else { 03375 DBG_ERROR(GWEN_LOGDOMAIN, 03376 "Terminating character missing (pos=%d [%x]) " 03377 "expecting \"%c\", got \"%c\")", 03378 GWEN_Buffer_GetPos(msgbuf), 03379 GWEN_Buffer_GetPos(msgbuf), 03380 terminator, 03381 GWEN_Buffer_PeekByte(msgbuf)); 03382 GWEN_XMLNode_Dump(node, 1); 03383 GWEN_Buffer_free(delimBuffer); 03384 return -1; 03385 } 03386 } 03387 else { 03388 DBG_ERROR(GWEN_LOGDOMAIN, "Terminating character missing"); 03389 GWEN_Buffer_free(delimBuffer); 03390 return -1; 03391 } 03392 } 03393 03394 GWEN_Buffer_free(delimBuffer); 03395 return 0; 03396 } 03397 03398 03399 03400 int GWEN_MsgEngine_ParseMessage(GWEN_MSGENGINE *e, 03401 GWEN_XMLNODE *group, 03402 GWEN_BUFFER *msgbuf, 03403 GWEN_DB_NODE *msgData, 03404 uint32_t flags){ 03405 03406 if (GWEN_MsgEngine__ReadGroup(e, 03407 msgbuf, 03408 group, 03409 0, 03410 msgData, 03411 e->delimiters, 03412 flags)) { 03413 DBG_INFO(GWEN_LOGDOMAIN, "Error reading group"); 03414 return -1; 03415 } 03416 03417 return 0; 03418 } 03419 03420 03421 03422 int GWEN_MsgEngine_SetValue(GWEN_MSGENGINE *e, 03423 const char *path, 03424 const char *value){ 03425 GWEN_DB_NODE *globalValues; 03426 03427 assert(e); 03428 globalValues=GWEN_MsgEngine__GetGlobalValues(e); 03429 assert(globalValues); 03430 return GWEN_DB_SetCharValue(globalValues, 03431 GWEN_DB_FLAGS_DEFAULT | 03432 GWEN_DB_FLAGS_OVERWRITE_VARS, 03433 path, value); 03434 } 03435 03436 03437 03438 int GWEN_MsgEngine_SetIntValue(GWEN_MSGENGINE *e, 03439 const char *path, 03440 int value){ 03441 GWEN_DB_NODE *globalValues; 03442 03443 assert(e); 03444 globalValues=GWEN_MsgEngine__GetGlobalValues(e); 03445 assert(globalValues); 03446 return GWEN_DB_SetIntValue(globalValues, 03447 GWEN_DB_FLAGS_DEFAULT | 03448 GWEN_DB_FLAGS_OVERWRITE_VARS, 03449 path, value); 03450 } 03451 03452 03453 03454 const char *GWEN_MsgEngine_GetValue(GWEN_MSGENGINE *e, 03455 const char *path, 03456 const char *defValue){ 03457 GWEN_DB_NODE *globalValues; 03458 03459 assert(e); 03460 globalValues=GWEN_MsgEngine__GetGlobalValues(e); 03461 assert(globalValues); 03462 return GWEN_DB_GetCharValue(globalValues, 03463 path, 0, defValue); 03464 } 03465 03466 03467 03468 int GWEN_MsgEngine_GetIntValue(GWEN_MSGENGINE *e, 03469 const char *path, 03470 int defValue){ 03471 GWEN_DB_NODE *globalValues; 03472 03473 assert(e); 03474 globalValues=GWEN_MsgEngine__GetGlobalValues(e); 03475 assert(globalValues); 03476 return GWEN_DB_GetIntValue(globalValues, 03477 path, 0, defValue); 03478 } 03479 03480 03481 03482 /* --------------------------------------------------------------- FUNCTION */ 03483 int GWEN_MsgEngine_SkipSegment(GWEN_UNUSED GWEN_MSGENGINE *e, 03484 GWEN_BUFFER *msgbuf, 03485 unsigned char escapeChar, 03486 unsigned char delimiter) { 03487 int esc; 03488 03489 esc=0; 03490 while(GWEN_Buffer_GetBytesLeft(msgbuf)) { 03491 if (esc) { 03492 esc=0; 03493 } 03494 else { 03495 int i; 03496 unsigned char c; 03497 03498 i=GWEN_Buffer_ReadByte(msgbuf); 03499 if (i==-1) { 03500 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 03501 return 0; 03502 } 03503 c=(unsigned int)i; 03504 if (c==escapeChar) { /* escape */ 03505 esc=1; 03506 } 03507 else if (c=='@') { 03508 /* skip binary data */ 03509 char lbuffer[16]; 03510 char *p; 03511 int l; 03512 int nc; 03513 03514 p=lbuffer; 03515 while(1) { 03516 nc=GWEN_Buffer_ReadByte(msgbuf); 03517 if (nc==-1) { 03518 DBG_ERROR(GWEN_LOGDOMAIN, "\"@num@\" expected"); 03519 return -1; 03520 } 03521 if (nc=='@') 03522 break; 03523 *p=nc; 03524 p++; 03525 } /* while */ 03526 *p=0; 03527 if (sscanf(lbuffer, "%d", &l)!=1) { 03528 DBG_ERROR(GWEN_LOGDOMAIN, "Bad number format"); 03529 return -1; 03530 } 03531 if (GWEN_Buffer_GetUsedBytes(msgbuf)-GWEN_Buffer_GetPos(msgbuf) 03532 < (unsigned) l) { 03533 DBG_ERROR(GWEN_LOGDOMAIN, "Premature end of message (binary beyond end)"); 03534 return -1; 03535 } 03536 GWEN_Buffer_IncrementPos(msgbuf, l); 03537 } 03538 else if (c==delimiter) {/* segment-end */ 03539 return 0; 03540 break; 03541 } 03542 } 03543 } /* while */ 03544 03545 DBG_ERROR(GWEN_LOGDOMAIN, "End of segment not found"); 03546 return -1; 03547 } 03548 03549 03550 03551 /* --------------------------------------------------------------- FUNCTION */ 03552 int GWEN_MsgEngine_ReadMessage(GWEN_MSGENGINE *e, 03553 const char *gtype, 03554 GWEN_BUFFER *mbuf, 03555 GWEN_DB_NODE *gr, 03556 uint32_t flags) { 03557 unsigned int segments; 03558 03559 segments=0; 03560 03561 while(GWEN_Buffer_GetBytesLeft(mbuf)) { 03562 GWEN_XMLNODE *node; 03563 unsigned int posBak; 03564 const char *p; 03565 GWEN_DB_NODE *tmpdb; 03566 int segVer; 03567 03568 /* find head segment description */ 03569 tmpdb=GWEN_DB_Group_new("tmpdb"); 03570 node=GWEN_MsgEngine_FindGroupByProperty(e, 03571 "id", 03572 0, 03573 "SegHead"); 03574 if (node==0) { 03575 DBG_ERROR(GWEN_LOGDOMAIN, "Segment description not found"); 03576 GWEN_DB_Group_free(tmpdb); 03577 return -1; 03578 } 03579 03580 /* parse head segment */ 03581 posBak=GWEN_Buffer_GetPos(mbuf); 03582 if (GWEN_MsgEngine_ParseMessage(e, 03583 node, 03584 mbuf, 03585 tmpdb, 03586 flags)) { 03587 DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing segment head"); 03588 GWEN_DB_Group_free(tmpdb); 03589 return -1; 03590 } 03591 03592 /* get segment code */ 03593 segVer=GWEN_DB_GetIntValue(tmpdb, 03594 "version", 03595 0, 03596 0); 03597 p=GWEN_DB_GetCharValue(tmpdb, 03598 "code", 03599 0, 03600 0); 03601 if (!p) { 03602 DBG_ERROR(GWEN_LOGDOMAIN, "No segment code for %s ? This seems to be a bad msg...", 03603 gtype); 03604 GWEN_Buffer_SetPos(mbuf, posBak); 03605 DBG_ERROR(GWEN_LOGDOMAIN, "Full message (pos=%04x)", posBak); 03606 GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf), 03607 GWEN_Buffer_GetUsedBytes(mbuf), 03608 1); 03609 GWEN_DB_Dump(tmpdb, 1); 03610 GWEN_DB_Group_free(tmpdb); 03611 return -1; 03612 } 03613 03614 /* try to find corresponding XML node */ 03615 node=GWEN_MsgEngine_FindNodeByProperty(e, 03616 gtype, 03617 "code", 03618 segVer, 03619 p); 03620 if (node==0) { 03621 unsigned int ustart; 03622 03623 ustart=GWEN_Buffer_GetPos(mbuf); 03624 ustart++; /* skip delimiter */ 03625 03626 /* node not found, skip it */ 03627 DBG_NOTICE(GWEN_LOGDOMAIN, 03628 "Unknown segment \"%s\" (Segnum=%d, version=%d, ref=%d)", 03629 p, 03630 GWEN_DB_GetIntValue(tmpdb, "seq", 0, -1), 03631 GWEN_DB_GetIntValue(tmpdb, "version", 0, -1), 03632 GWEN_DB_GetIntValue(tmpdb, "ref", 0, -1)); 03633 if (GWEN_MsgEngine_SkipSegment(e, mbuf, '?', '\'')) { 03634 DBG_ERROR(GWEN_LOGDOMAIN, "Error skipping segment \"%s\"", p); 03635 GWEN_DB_Group_free(tmpdb); 03636 return -1; 03637 } 03638 if (flags & GWEN_MSGENGINE_READ_FLAGS_TRUSTINFO) { 03639 unsigned int usize; 03640 03641 usize=GWEN_Buffer_GetPos(mbuf)-ustart-1; 03642 #if 0 03643 GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf)+ustart, 03644 usize, 03645 stderr, 1); 03646 #endif 03647 if (GWEN_MsgEngine_AddTrustInfo(e, 03648 GWEN_Buffer_GetStart(mbuf)+ustart, 03649 usize, 03650 p, 03651 GWEN_MsgEngineTrustLevelHigh, 03652 ustart)) { 03653 DBG_INFO(GWEN_LOGDOMAIN, "called from here"); 03654 GWEN_DB_Group_free(tmpdb); 03655 return -1; 03656 } 03657 } /* if trustInfo handling wanted */ 03658 } 03659 else { 03660 /* ok, node available, get the corresponding description and parse 03661 * the segment */ 03662 const char *id; 03663 GWEN_DB_NODE *storegrp; 03664 unsigned int startPos; 03665 03666 /* restore start position, since the segment head is part of a full 03667 * description, so we need to restart reading from the very begin */ 03668 GWEN_Buffer_SetPos(mbuf, posBak); 03669 03670 /* create group in DB for this segment */ 03671 id=GWEN_XMLNode_GetProperty(node, "id", p); 03672 storegrp=GWEN_DB_GetGroup(gr, 03673 GWEN_PATH_FLAGS_CREATE_GROUP, 03674 id); 03675 assert(storegrp); 03676 03677 /* store the start position of this segment within the DB */ 03678 startPos=GWEN_Buffer_GetPos(mbuf); 03679 GWEN_DB_SetIntValue(storegrp, 03680 GWEN_DB_FLAGS_OVERWRITE_VARS, 03681 "segment/pos", 03682 startPos); 03683 03684 /* parse the segment */ 03685 if (GWEN_MsgEngine_ParseMessage(e, 03686 node, 03687 mbuf, 03688 storegrp, 03689 flags)) { 03690 DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing segment \"%s\" at %d (%x)", 03691 p, 03692 GWEN_Buffer_GetPos(mbuf)-startPos, 03693 GWEN_Buffer_GetPos(mbuf)-startPos); 03694 GWEN_Text_DumpString(GWEN_Buffer_GetStart(mbuf)+startPos, 03695 GWEN_Buffer_GetUsedBytes(mbuf)-startPos, 03696 1); 03697 DBG_ERROR(GWEN_LOGDOMAIN, "Stored data so far:"); 03698 GWEN_DB_Dump(storegrp, 2); 03699 GWEN_DB_Group_free(tmpdb); 03700 return -1; 03701 } 03702 03703 /* store segment size within DB */ 03704 GWEN_DB_SetIntValue(storegrp, 03705 GWEN_DB_FLAGS_OVERWRITE_VARS, 03706 "segment/length", 03707 GWEN_Buffer_GetPos(mbuf)-startPos); 03708 segments++; 03709 } 03710 GWEN_DB_Group_free(tmpdb); 03711 } /* while */ 03712 03713 /* done */ 03714 if (segments) { 03715 DBG_DEBUG(GWEN_LOGDOMAIN, "Parsed %d segments", segments); 03716 return 0; 03717 } 03718 else { 03719 DBG_INFO(GWEN_LOGDOMAIN, "No segments parsed."); 03720 return 1; 03721 } 03722 } 03723 03724 03725 03726 03727 03728 03729 03730 03731 GWEN_MSGENGINE_TRUSTEDDATA* 03732 GWEN_MsgEngine_TrustedData_new(const char *data, 03733 unsigned int size, 03734 const char *description, 03735 GWEN_MSGENGINE_TRUSTLEVEL trustLevel){ 03736 GWEN_MSGENGINE_TRUSTEDDATA *td; 03737 03738 assert(data); 03739 assert(size); 03740 GWEN_NEW_OBJECT(GWEN_MSGENGINE_TRUSTEDDATA, td); 03741 td->data=(char*)malloc(size); 03742 assert(td->data); 03743 memmove(td->data, data, size); 03744 if (description) 03745 td->description=strdup(description); 03746 td->trustLevel=trustLevel; 03747 td->size=size; 03748 return td; 03749 } 03750 03751 03752 03753 void GWEN_MsgEngine_TrustedData_free(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03754 if (td) { 03755 free(td->data); 03756 free(td->description); 03757 free(td->replacement); 03758 GWEN_FREE_OBJECT(td); 03759 } 03760 } 03761 03762 03763 03764 GWEN_MSGENGINE_TRUSTEDDATA* 03765 GWEN_MsgEngine_TrustedData_GetNext(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03766 assert(td); 03767 return td->next; 03768 } 03769 03770 03771 03772 const char* 03773 GWEN_MsgEngine_TrustedData_GetData(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03774 assert(td); 03775 return td->data; 03776 } 03777 03778 03779 03780 unsigned int 03781 GWEN_MsgEngine_TrustedData_GetSize(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03782 assert(td); 03783 return td->size; 03784 } 03785 03786 03787 03788 const char* 03789 GWEN_MsgEngine_TrustedData_GetDescription(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03790 assert(td); 03791 return td->description; 03792 } 03793 03794 03795 03796 GWEN_MSGENGINE_TRUSTLEVEL 03797 GWEN_MsgEngine_TrustedData_GetTrustLevel(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03798 assert(td); 03799 return td->trustLevel; 03800 } 03801 03802 03803 03804 const char* 03805 GWEN_MsgEngine_TrustedData_GetReplacement(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03806 assert(td); 03807 return td->replacement; 03808 } 03809 03810 03811 03812 int GWEN_MsgEngine_TrustedData_AddPos(GWEN_MSGENGINE_TRUSTEDDATA *td, 03813 unsigned int pos){ 03814 assert(td); 03815 if (td->posCount>=GWEN_MSGENGINE_TRUSTEDDATA_MAXPOS) 03816 return -1; 03817 td->positions[td->posCount++]=pos; 03818 return 0; 03819 } 03820 03821 03822 03823 int GWEN_MsgEngine_TrustedData_GetFirstPos(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03824 assert(td); 03825 td->posPointer=0; 03826 return GWEN_MsgEngine_TrustedData_GetNextPos(td); 03827 } 03828 03829 03830 03831 int GWEN_MsgEngine_TrustedData_GetNextPos(GWEN_MSGENGINE_TRUSTEDDATA *td){ 03832 assert(td); 03833 if (td->posPointer>=td->posCount) 03834 return -1; 03835 return td->positions[td->posPointer++]; 03836 } 03837 03838 03839 03840 int 03841 GWEN_MsgEngine_TrustedData_CreateReplacements(GWEN_MSGENGINE_TRUSTEDDATA 03842 *td){ 03843 unsigned int nextNr; 03844 GWEN_MSGENGINE_TRUSTEDDATA *ntd; 03845 unsigned int count; 03846 03847 assert(td); 03848 count=0; 03849 ntd=td; 03850 while(ntd) { 03851 count++; 03852 ntd=ntd->next; 03853 } 03854 03855 if (count<0x10) 03856 nextNr=0x01; 03857 else 03858 nextNr=0x11; 03859 03860 ntd=td; 03861 while(ntd) { 03862 unsigned int i; 03863 char numbuffer[32]; 03864 char *rp; 03865 GWEN_MSGENGINE_TRUSTEDDATA *std; 03866 int match; 03867 03868 /* check whether the same data already exists */ 03869 std=td; 03870 match=0; 03871 while(std && std!=ntd) { 03872 03873 match=1; 03874 if (std->size==ntd->size) { 03875 for (i=0; i<td->size; i++) { 03876 if (std->data[i]!=ntd->data[i]) { 03877 match=0; 03878 break; 03879 } 03880 } /* for */ 03881 } 03882 else 03883 match=0; 03884 03885 if (match) 03886 break; 03887 std=std->next; 03888 } /* while */ 03889 03890 if (match) { 03891 /* copy the found match */ 03892 rp=strdup(std->replacement); 03893 } 03894 else { 03895 /* this is a new one */ 03896 rp=(char*)malloc(ntd->size+1); 03897 assert(rp); 03898 03899 if (ntd->size==1) { 03900 if (count>=0x10) 03901 nextNr+=0x10; 03902 } 03903 sprintf(numbuffer, "%02X", nextNr++); 03904 for (i=0; i<ntd->size; i++) { 03905 if (count<0x10) 03906 rp[i]=numbuffer[1]; 03907 else 03908 rp[i]=numbuffer[1-(i&1)]; 03909 } /* for */ 03910 rp[i]=0; 03911 } 03912 /* 03913 DBG_DEBUG(GWEN_LOGDOMAIN, "Replacement: \"%s\" for \"%s\" (%d)", rp, 03914 ntd->description, 03915 ntd->size); 03916 */ 03917 free(ntd->replacement); 03918 ntd->replacement=rp; 03919 03920 ntd=ntd->next; 03921 } /* while */ 03922 return 0; 03923 } 03924 03925 03926 03927 GWEN_MSGENGINE_TRUSTEDDATA *GWEN_MsgEngine_TakeTrustInfo(GWEN_MSGENGINE *e){ 03928 GWEN_MSGENGINE_TRUSTEDDATA *td; 03929 03930 assert(e); 03931 td=e->trustInfos; 03932 e->trustInfos=0; 03933 return td; 03934 } 03935 03936 03937 03938 03939 int GWEN_MsgEngine_AddTrustInfo(GWEN_MSGENGINE *e, 03940 const char *data, 03941 unsigned int size, 03942 const char *description, 03943 GWEN_MSGENGINE_TRUSTLEVEL trustLevel, 03944 unsigned int pos) { 03945 GWEN_MSGENGINE_TRUSTEDDATA *td; 03946 int match; 03947 03948 assert(e); 03949 assert(data); 03950 assert(size); 03951 03952 if (!description) 03953 description=""; 03954 03955 td=e->trustInfos; 03956 while(td) { 03957 unsigned int i; 03958 03959 /* compare data */ 03960 if (td->size==size && 03961 *description && 03962 *(td->description) && 03963 trustLevel==td->trustLevel && 03964 strcasecmp(description, td->description)==0) { 03965 match=1; 03966 for (i=0; i<td->size; i++) { 03967 if (td->data[i]!=data[i]) { 03968 match=0; 03969 break; 03970 } 03971 } /* for */ 03972 } 03973 else 03974 match=0; 03975 03976 if (match) 03977 break; 03978 td=td->next; 03979 } /* while */ 03980 03981 if (!td) { 03982 DBG_INFO(GWEN_LOGDOMAIN, "Creating new trustInfo for \"%s\" (%d)", 03983 description, size); 03984 td=GWEN_MsgEngine_TrustedData_new(data, 03985 size, 03986 description, 03987 trustLevel); 03988 GWEN_LIST_ADD(GWEN_MSGENGINE_TRUSTEDDATA, td, &(e->trustInfos)); 03989 } 03990 else { 03991 DBG_INFO(GWEN_LOGDOMAIN, "Reusing trustInfo for \"%s\" (%d)", 03992 description, size); 03993 } 03994 GWEN_MsgEngine_TrustedData_AddPos(td, pos); 03995 return 0; 03996 } 03997 03998 03999