21497ec7a8e7547ed63202c554b49640391a2a58
[yazproxy-moved-to-github.git] / src / yaz-proxy-config.cpp
1 /* $Id: yaz-proxy-config.cpp,v 1.7 2004-10-18 22:10:57 adam Exp $
2    Copyright (c) 1998-2004, Index Data.
3
4 This file is part of the yaz-proxy.
5
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 #include <ctype.h>
23 #include <yaz/log.h>
24 #include <yazproxy/proxy.h>
25
26 #if HAVE_XSLT
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29 #include <libxslt/xsltutils.h>
30 #include <libxslt/transform.h>
31 #endif
32
33 class Yaz_ProxyConfigP {
34     friend class Yaz_ProxyConfig;
35
36     int m_copy;
37
38     int mycmp(const char *hay, const char *item, size_t len);
39     int match_list(int v, const char *m);
40     int atoi_l(const char **cp);
41 #if HAVE_XSLT
42     int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
43                      const char *schema_identifier);
44     xmlDocPtr m_docPtr;
45     xmlNodePtr m_proxyPtr;
46     void return_target_info(xmlNodePtr ptr, const char **url,
47                             int *limit_bw, int *limit_pdu, int *limit_req,
48                             int *target_idletime, int *client_idletime,
49                             int *keepalive_limit_bw, int *keepalive_limit_pdu,
50                             int *pre_init, const char **cql2rpn);
51     void return_limit(xmlNodePtr ptr,
52                       int *limit_bw, int *limit_pdu, int *limit_req);
53     int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
54                      char **addinfo);
55     xmlNodePtr find_target_node(const char *name, const char *db);
56     xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
57     const char *get_text(xmlNodePtr ptr);
58     int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
59                                 Z_AttributeList *attrs,
60                                 char **addinfo);
61     int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
62                                char **addinfo);
63     int get_explain_ptr(const char *host, const char *db,
64                         xmlNodePtr *ptr_target, xmlNodePtr *ptr_explain);
65 #endif
66 };
67
68 Yaz_ProxyConfig::Yaz_ProxyConfig()
69 {
70     m_cp = new Yaz_ProxyConfigP;
71     m_cp->m_copy = 0;
72 #if HAVE_XSLT
73     m_cp->m_docPtr = 0;
74     m_cp->m_proxyPtr = 0;
75 #endif
76 }
77
78 Yaz_ProxyConfig::~Yaz_ProxyConfig()
79 {
80 #if HAVE_XSLT
81     if (!m_cp->m_copy && m_cp->m_docPtr)
82         xmlFreeDoc(m_cp->m_docPtr);
83 #endif
84     delete m_cp;
85 }
86
87 int Yaz_ProxyConfig::read_xml(const char *fname)
88 {
89 #if HAVE_XSLT
90     xmlDocPtr ndoc = xmlParseFile(fname);
91
92     if (!ndoc)
93     {
94         yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
95         return -1;  // no good
96     }
97     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
98     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
99         strcmp((const char *) proxyPtr->name, "proxy"))
100     {
101         yaz_log(LOG_WARN, "No proxy element in %s", fname);
102         xmlFreeDoc(ndoc);
103         return -1;
104     }
105     m_cp->m_proxyPtr = proxyPtr;
106
107     // OK: release previous and make it the current one.
108     if (m_cp->m_docPtr)
109         xmlFreeDoc(m_cp->m_docPtr);
110     m_cp->m_docPtr = ndoc;
111     return 0;
112 #else
113     return -2;
114 #endif
115 }
116
117 #if HAVE_XSLT
118 const char *Yaz_ProxyConfigP::get_text(xmlNodePtr ptr)
119 {
120     for(ptr = ptr->children; ptr; ptr = ptr->next)
121         if (ptr->type == XML_TEXT_NODE)
122         {
123             xmlChar *t = ptr->content;
124             if (t)
125             {
126                 while (*t == ' ')
127                     t++;
128                 return (const char *) t;
129             }
130         }
131     return 0;
132 }
133 #endif
134
135 #if HAVE_XSLT
136 void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr,
137                                    int *limit_bw,
138                                    int *limit_pdu,
139                                    int *limit_req)
140 {
141     for (ptr = ptr->children; ptr; ptr = ptr->next)
142     {
143         if (ptr->type == XML_ELEMENT_NODE 
144             && !strcmp((const char *) ptr->name, "bandwidth"))
145         {
146             const char *t = get_text(ptr);
147             if (t)
148                 *limit_bw = atoi(t);
149         }
150         if (ptr->type == XML_ELEMENT_NODE 
151             && !strcmp((const char *) ptr->name, "retrieve"))
152         {
153             const char *t = get_text(ptr);
154             if (t)
155                 *limit_req = atoi(t);
156         }
157         if (ptr->type == XML_ELEMENT_NODE 
158             && !strcmp((const char *) ptr->name, "pdu"))
159         {
160             const char *t = get_text(ptr);
161             if (t)
162                 *limit_pdu = atoi(t);
163         }
164     }
165 }
166 #endif
167
168 #if HAVE_XSLT
169 void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr,
170                                           const char **url,
171                                           int *limit_bw,
172                                           int *limit_pdu,
173                                           int *limit_req,
174                                           int *target_idletime,
175                                           int *client_idletime,
176                                           int *keepalive_limit_bw,
177                                           int *keepalive_limit_pdu,
178                                           int *pre_init,
179                                           const char **cql2rpn)
180 {
181     *pre_init = 0;
182     int no_url = 0;
183     ptr = ptr->children;
184     for (; ptr; ptr = ptr->next)
185     {
186         if (ptr->type == XML_ELEMENT_NODE 
187             && !strcmp((const char *) ptr->name, "preinit"))
188         {
189             const char *v = get_text(ptr);
190             *pre_init = v ? atoi(v) : 1;
191         }
192         if (ptr->type == XML_ELEMENT_NODE 
193             && !strcmp((const char *) ptr->name, "url"))
194         {
195             const char *t = get_text(ptr);
196             if (t && no_url < MAX_ZURL_PLEX)
197             {
198                 url[no_url++] = t;
199                 url[no_url] = 0;
200             }
201         }
202         if (ptr->type == XML_ELEMENT_NODE 
203             && !strcmp((const char *) ptr->name, "keepalive"))
204         {
205             int dummy;
206             *keepalive_limit_bw = 500000;
207             *keepalive_limit_pdu = 1000;
208             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
209                          &dummy);
210         }
211         if (ptr->type == XML_ELEMENT_NODE 
212             && !strcmp((const char *) ptr->name, "limit"))
213             return_limit(ptr, limit_bw, limit_pdu, limit_req);
214         if (ptr->type == XML_ELEMENT_NODE 
215             && !strcmp((const char *) ptr->name, "target-timeout"))
216         {
217             const char *t = get_text(ptr);
218             if (t)
219             {
220                 *target_idletime = atoi(t);
221                 if (*target_idletime < 0)
222                     *target_idletime = 0;
223             }
224         }
225         if (ptr->type == XML_ELEMENT_NODE 
226             && !strcmp((const char *) ptr->name, "client-timeout"))
227         {
228             const char *t = get_text(ptr);
229             if (t)
230             {
231                 *client_idletime = atoi(t);
232                 if (*client_idletime < 0)
233                     *client_idletime = 0;
234             }
235         }
236         if (ptr->type == XML_ELEMENT_NODE 
237             && !strcmp((const char *) ptr->name, "cql2rpn"))
238         {
239             const char *t = get_text(ptr);
240             if (t)
241                 *cql2rpn = t;
242         }
243     }
244 }
245 #endif
246
247 int Yaz_ProxyConfigP::atoi_l(const char **cp)
248 {
249     int v = 0;
250     while (**cp && isdigit(**cp))
251     {
252         v = v*10 + (**cp - '0');
253         (*cp)++;
254     }
255     return v;
256 }
257
258 int Yaz_ProxyConfigP::match_list(int v, const char *m)
259 {
260     while(m && *m)
261     {
262         while(*m && isspace(*m))
263             m++;
264         if (*m == '*')
265             return 1;
266         int l = atoi_l(&m);
267         int h = l;
268         if (*m == '-')
269         {
270             ++m;
271             h = atoi_l(&m);
272         }
273         if (v >= l && v <= h)
274           return 1;
275         if (*m == ',')
276             m++;
277     }
278     return 0;
279 }
280
281 #if HAVE_XSLT
282 int Yaz_ProxyConfigP::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
283                                               Z_AttributeList *attrs,
284                                               char **addinfo)
285 {
286     int i;
287     for (i = 0; i<attrs->num_attributes; i++)
288     {
289         Z_AttributeElement *el = attrs->attributes[i];
290         
291         if (!el->attributeType)
292             continue;
293         int type = *el->attributeType;
294         int *value = 0;
295         
296         if (el->which == Z_AttributeValue_numeric && el->value.numeric)
297             value = el->value.numeric;
298         
299         xmlNodePtr ptr;
300         for(ptr = ptrl->children; ptr; ptr = ptr->next)
301         {
302             if (ptr->type == XML_ELEMENT_NODE &&
303                 !strcmp((const char *) ptr->name, "attribute"))
304             {
305                 const char *match_type = 0;
306                 const char *match_value = 0;
307                 const char *match_error = 0;
308                 struct _xmlAttr *attr;
309                 for (attr = ptr->properties; attr; attr = attr->next)
310                 {
311                     if (!strcmp((const char *) attr->name, "type") &&
312                         attr->children && attr->children->type == XML_TEXT_NODE)
313                         match_type = (const char *) attr->children->content;
314                     if (!strcmp((const char *) attr->name, "value") &&
315                         attr->children && attr->children->type == XML_TEXT_NODE)
316                         match_value = (const char *) attr->children->content;
317                     if (!strcmp((const char *) attr->name, "error") &&
318                         attr->children && attr->children->type == XML_TEXT_NODE)
319                         match_error = (const char *) attr->children->content;
320                 }
321                 if (match_type && match_value)
322                 {
323                     char addinfo_str[20];
324                     if (!match_list(type, match_type))
325                         continue;
326                     
327                     *addinfo_str = '\0';
328                     if (!strcmp(match_type, "*"))
329                         sprintf (addinfo_str, "%d", type);
330                     else if (value)
331                     {
332                         if (!match_list(*value, match_value))
333                             continue;
334                         sprintf (addinfo_str, "%d", *value);
335                     }
336                     else
337                         continue;
338                     
339                     if (match_error)
340                     {
341                         if (*addinfo_str)
342                             *addinfo = odr_strdup(odr, addinfo_str);
343                         return atoi(match_error);
344                     }
345                     break;
346                 }
347             }
348         }
349     }
350     return 0;
351 }
352 #endif
353
354 #if HAVE_XSLT
355 int Yaz_ProxyConfigP::check_type_1_structure(ODR odr, xmlNodePtr ptr,
356                                             Z_RPNStructure *q,
357                                             char **addinfo)
358 {
359     if (q->which == Z_RPNStructure_complex)
360     {
361         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
362         if (e)
363             return e;
364         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
365         return e;
366     }
367     else if (q->which == Z_RPNStructure_simple)
368     {
369         if (q->u.simple->which == Z_Operand_APT)
370         {
371             return check_type_1_attributes(
372                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
373                 addinfo);
374         }
375     }
376     return 0;
377 }
378 #endif
379
380 #if HAVE_XSLT
381 int Yaz_ProxyConfigP::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
382                                    char **addinfo)
383 {
384     // possibly check for Bib-1
385     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
386 }
387 #endif
388
389 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
390                                  char **addinfo)
391 {
392 #if HAVE_XSLT
393     xmlNodePtr ptr;
394     
395     ptr = m_cp->find_target_node(name, 0);
396     if (ptr)
397     {
398         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
399             return m_cp->check_type_1(odr, ptr, query->u.type_1, addinfo);
400     }
401 #endif
402     return 0;
403 }
404
405 #if HAVE_XSLT
406 int Yaz_ProxyConfigP::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
407                                    const char *schema_identifier)
408 {
409     char *esn = 0;
410     int default_match = 1;
411     if (comp && comp->which == Z_RecordComp_simple &&
412         comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
413     {
414         esn = comp->u.simple->u.generic;
415     }
416     // if no ESN/schema was given accept..
417     if (!esn)
418         return 1;
419     // check if schema identifier match
420     if (schema_identifier && !strcmp(esn, schema_identifier))
421         return 1;
422     // Check each name element
423     for (; ptr; ptr = ptr->next)
424     {
425         if (ptr->type == XML_ELEMENT_NODE 
426             && !strcmp((const char *) ptr->name, "name"))
427         {
428             xmlNodePtr tptr = ptr->children;
429             default_match = 0;
430             for (; tptr; tptr = tptr->next)
431                 if (tptr->type == XML_TEXT_NODE && tptr->content)
432                 {
433                     xmlChar *t = tptr->content;
434                     while (*t && isspace(*t))
435                         t++;
436                     int i = 0;
437                     while (esn[i] && esn[i] == t[i])
438                         i++;
439                     if (!esn[i] && (!t[i] || isspace(t[i])))
440                         return 1;
441                 }
442         }
443     }
444     return default_match;
445 }
446 #endif
447
448 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
449                                   Odr_oid *syntax, Z_RecordComposition *comp,
450                                   char **addinfo,
451                                   char **stylesheet, char **schema,
452                                   char **backend_type,
453                                   char **backend_charset)
454 {
455     if (stylesheet)
456     {
457         xfree (*stylesheet);
458         *stylesheet = 0;
459     }
460     if (schema)
461     {
462         xfree (*schema);
463         *schema = 0;
464     }
465     if (backend_type)
466     {
467         xfree (*backend_type);
468         *backend_type = 0;
469     }
470     if (backend_charset)
471     {
472         xfree (*backend_charset);
473         *backend_charset = 0;
474     }
475 #if HAVE_XSLT
476     int syntax_has_matched = 0;
477     xmlNodePtr ptr;
478     
479     ptr = m_cp->find_target_node(name, 0);
480     if (!ptr)
481         return 0;
482     for(ptr = ptr->children; ptr; ptr = ptr->next)
483     {
484         if (ptr->type == XML_ELEMENT_NODE &&
485             !strcmp((const char *) ptr->name, "syntax"))
486         {
487             int match = 0;  // if we match record syntax
488             const char *match_type = 0;
489             const char *match_error = 0;
490             const char *match_marcxml = 0;
491             const char *match_stylesheet = 0;
492             const char *match_identifier = 0;
493             const char *match_backend_type = 0;
494             const char *match_backend_charset = 0;
495             struct _xmlAttr *attr;
496             for (attr = ptr->properties; attr; attr = attr->next)
497             {
498                 if (!strcmp((const char *) attr->name, "type") &&
499                     attr->children && attr->children->type == XML_TEXT_NODE)
500                     match_type = (const char *) attr->children->content;
501                 if (!strcmp((const char *) attr->name, "error") &&
502                     attr->children && attr->children->type == XML_TEXT_NODE)
503                     match_error = (const char *) attr->children->content;
504                 if (!strcmp((const char *) attr->name, "marcxml") &&
505                     attr->children && attr->children->type == XML_TEXT_NODE)
506                     match_marcxml = (const char *) attr->children->content;
507                 if (!strcmp((const char *) attr->name, "stylesheet") &&
508                     attr->children && attr->children->type == XML_TEXT_NODE)
509                     match_stylesheet = (const char *) attr->children->content;
510                 if (!strcmp((const char *) attr->name, "identifier") &&
511                     attr->children && attr->children->type == XML_TEXT_NODE)
512                     match_identifier = (const char *) attr->children->content;
513                 if (!strcmp((const char *) attr->name, "backendtype") &&
514                     attr->children && attr->children->type == XML_TEXT_NODE)
515                     match_backend_type = (const char *)
516                         attr->children->content;
517                 if (!strcmp((const char *) attr->name, "backendcharset") &&
518                     attr->children && attr->children->type == XML_TEXT_NODE)
519                     match_backend_charset = (const char *)
520                         attr->children->content;
521             }
522             if (match_type)
523             {
524                 if (!strcmp(match_type, "*"))
525                     match = 1;
526                 else if (!strcmp(match_type, "none"))
527                 {
528                     if (syntax == 0)
529                         match = 1;
530                 }
531                 else if (syntax)
532                 {
533                     int match_oid[OID_SIZE];
534                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
535                     if (oid_oidcmp(match_oid, syntax) == 0)
536                         match = 1;
537                 }
538             }
539             if (match)
540             {
541                 if (!match_error)
542                     syntax_has_matched = 1;
543                 match = m_cp->check_schema(ptr->children, comp,
544                                            match_identifier);
545             }
546             if (match)
547             {
548                 if (stylesheet && match_stylesheet)
549                 {
550                     xfree(*stylesheet);
551                     *stylesheet = xstrdup(match_stylesheet);
552                 }
553                 if (schema && match_identifier)
554                 {
555                     xfree(*schema);
556                     *schema = xstrdup(match_identifier);
557                 }
558                 if (backend_type && match_backend_type)
559                 {
560                     xfree(*backend_type);
561                     *backend_type = xstrdup(match_backend_type);
562                 }
563                 if (backend_charset && match_backend_charset)
564                 {
565                     xfree(*backend_charset);
566                     *backend_charset = xstrdup(match_backend_charset);
567                 }
568                 if (match_marcxml)
569                 {
570                     return -1;
571                 }
572                 if (match_error)
573                 {
574                     if (syntax_has_matched)  // if syntax OK, bad schema/ESN
575                         return 25;
576                     if (syntax)
577                     {
578                         char dotoid_str[100];
579                         oid_to_dotstring(syntax, dotoid_str);
580                         *addinfo = odr_strdup(odr, dotoid_str);
581                     }
582                     return atoi(match_error);
583                 }
584                 return 0;
585             }
586         }
587     }
588 #endif
589     return 0;
590 }
591
592 #if HAVE_XSLT
593 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
594 {
595     xmlNodePtr dptr;
596     if (!db)
597         return ptr;
598     if (!ptr)
599         return 0;
600     for (dptr = ptr->children; dptr; dptr = dptr->next)
601         if (dptr->type == XML_ELEMENT_NODE &&
602             !strcmp((const char *) dptr->name, "database"))
603         {
604             struct _xmlAttr *attr;
605             for (attr = dptr->properties; attr; attr = attr->next)
606                 if (!strcmp((const char *) attr->name, "name"))
607                 {
608                     if (attr->children
609                         && attr->children->type==XML_TEXT_NODE
610                         && attr->children->content 
611                         && (!strcmp((const char *) attr->children->content, db)
612                             || !strcmp((const char *) attr->children->content,
613                                        "*")))
614                         return dptr;
615                 }
616         }
617     return ptr;
618 }
619     
620 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
621 {
622     xmlNodePtr ptr;
623     if (!m_proxyPtr)
624         return 0;
625     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
626     {
627         if (ptr->type == XML_ELEMENT_NODE &&
628             !strcmp((const char *) ptr->name, "target"))
629         {
630             // default one ? 
631             if (!name)
632             {
633                 // <target default="1"> ?
634                 struct _xmlAttr *attr;
635                 for (attr = ptr->properties; attr; attr = attr->next)
636                     if (!strcmp((const char *) attr->name, "default") &&
637                         attr->children && attr->children->type == XML_TEXT_NODE)
638                     {
639                         xmlChar *t = attr->children->content;
640                         if (!t || *t == '1')
641                         {
642                             return find_target_db(ptr, db);
643                         }
644                     }
645             }
646             else
647             {
648                 // <target name="name"> ?
649                 struct _xmlAttr *attr;
650                 for (attr = ptr->properties; attr; attr = attr->next)
651                     if (!strcmp((const char *) attr->name, "name"))
652                     {
653                         if (attr->children
654                             && attr->children->type==XML_TEXT_NODE
655                             && attr->children->content 
656                             && (!strcmp((const char *) attr->children->content,
657                                         name)
658                                 || !strcmp((const char *) attr->children->content,
659                                            "*")))
660                         {
661                             return find_target_db(ptr, db);
662                         }
663                     }
664             }
665         }
666     }
667     return 0;
668 }
669 #endif
670
671 int Yaz_ProxyConfig::get_target_no(int no,
672                                    const char **name,
673                                    const char **url,
674                                    int *limit_bw,
675                                    int *limit_pdu,
676                                    int *limit_req,
677                                    int *target_idletime,
678                                    int *client_idletime,
679                                    int *max_clients,
680                                    int *keepalive_limit_bw,
681                                    int *keepalive_limit_pdu,
682                                    int *pre_init,
683                                    const char **cql2rpn)
684 {
685 #if HAVE_XSLT
686     xmlNodePtr ptr;
687     if (!m_cp->m_proxyPtr)
688         return 0;
689     int i = 0;
690     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
691         if (ptr->type == XML_ELEMENT_NODE &&
692             !strcmp((const char *) ptr->name, "target"))
693         {
694             if (i == no)
695             {
696                 struct _xmlAttr *attr;
697                 for (attr = ptr->properties; attr; attr = attr->next)
698                     if (!strcmp((const char *) attr->name, "name"))
699                     {
700                         if (attr->children
701                             && attr->children->type==XML_TEXT_NODE
702                             && attr->children->content)
703                             *name = (const char *) attr->children->content;
704                     }
705                 m_cp->return_target_info(
706                     ptr, url,
707                     limit_bw, limit_pdu, limit_req,
708                     target_idletime, client_idletime,
709                     keepalive_limit_bw, keepalive_limit_pdu,
710                     pre_init, cql2rpn);
711                 return 1;
712             }
713             i++;
714         }
715 #endif
716     return 0;
717 }
718
719 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
720 {
721     if (len == strlen(item) && memcmp(hay, item, len) == 0)
722         return 1;
723     return 0;
724 }
725
726 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
727                                        int *max_clients)
728 {
729 #if HAVE_XSLT
730     xmlNodePtr ptr;
731     if (!m_cp->m_proxyPtr)
732         return;
733     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
734     {
735         if (ptr->type == XML_ELEMENT_NODE 
736             && !strcmp((const char *) ptr->name, "log"))
737         {
738             const char *v = m_cp->get_text(ptr);
739             *log_mask = 0;
740             while (v && *v)
741             {
742                 const char *cp = v;
743                 while (*cp && *cp != ',' && !isspace(*cp))
744                     cp++;
745                 size_t len = cp - v;
746                 if (m_cp->mycmp(v, "client-apdu", len))
747                     *log_mask |= PROXY_LOG_APDU_CLIENT;
748                 if (m_cp->mycmp(v, "server-apdu", len))
749                     *log_mask |= PROXY_LOG_APDU_SERVER;
750                 if (m_cp->mycmp(v, "client-requests", len))
751                     *log_mask |= PROXY_LOG_REQ_CLIENT;
752                 if (m_cp->mycmp(v, "server-requests", len))
753                     *log_mask |= PROXY_LOG_REQ_SERVER;
754                 if (isdigit(*v))
755                     *log_mask |= atoi(v);
756                 if (*cp == ',')
757                     cp++;
758                 while (*cp && isspace(*cp))
759                     cp++;
760                 v = cp;
761             }
762         }
763         if (ptr->type == XML_ELEMENT_NODE &&
764             !strcmp((const char *) ptr->name, "max-clients"))
765         {
766             const char *t = m_cp->get_text(ptr);
767             if (t)
768             {
769                 *max_clients = atoi(t);
770                 if (*max_clients  < 1)
771                     *max_clients = 1;
772             }
773         }
774     }
775 #endif
776 }
777
778 #if HAVE_XSLT
779 int Yaz_ProxyConfigP::get_explain_ptr(const char *host, const char *db,
780                                       xmlNodePtr *ptr_target,
781                                       xmlNodePtr *ptr_explain)
782 {
783     xmlNodePtr ptr;
784     if (!m_proxyPtr)
785         return 0;
786     if (!db)
787         return 0;
788     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
789     {
790         if (ptr->type == XML_ELEMENT_NODE &&
791             !strcmp((const char *) ptr->name, "target"))
792         {
793             *ptr_target = ptr;
794             xmlNodePtr ptr = (*ptr_target)->children;
795             for (; ptr; ptr = ptr->next)
796             {
797                 if (ptr->type == XML_ELEMENT_NODE &&
798                     !strcmp((const char *) ptr->name, "explain"))
799                 {
800                     *ptr_explain = ptr;
801                     xmlNodePtr ptr = (*ptr_explain)->children;
802
803                     for (; ptr; ptr = ptr->next)
804                         if (ptr->type == XML_ELEMENT_NODE &&
805                             !strcmp((const char *) ptr->name, "serverInfo"))
806                             break;
807                     if (!ptr)
808                         continue;
809                     for (ptr = ptr->children; ptr; ptr = ptr->next)
810                         if (ptr->type == XML_ELEMENT_NODE &&
811                             !strcmp((const char *) ptr->name, "database"))
812                             break;
813                     
814                     if (!ptr)
815                         continue;
816                     for (ptr = ptr->children; ptr; ptr = ptr->next)
817                         if (ptr->type == XML_TEXT_NODE &&
818                             ptr->content &&
819                             !strcmp((const char *) ptr->content, db))
820                             break;
821                     if (!ptr)
822                         continue;
823                     return 1;
824                 }
825             }
826         }
827     }
828     return 0;
829 }
830 #endif
831
832 const char *Yaz_ProxyConfig::get_explain_name(const char *db,
833                                               const char **backend_db)
834 {
835 #if HAVE_XSLT
836     xmlNodePtr ptr_target, ptr_explain;
837     if (m_cp->get_explain_ptr(0, db, &ptr_target, &ptr_explain)
838         && ptr_target)
839     {
840         struct _xmlAttr *attr;
841         const char *name = 0;
842         
843         for (attr = ptr_target->properties; attr; attr = attr->next)
844             if (!strcmp((const char *) attr->name, "name")
845                 && attr->children
846                 && attr->children->type==XML_TEXT_NODE
847                 && attr->children->content 
848                 && attr->children->content[0])
849             {
850                 name = (const char *)attr->children->content;
851                 break;
852             }
853         if (name)
854         {
855             for (attr = ptr_target->properties; attr; attr = attr->next)
856                 if (!strcmp((const char *) attr->name, "database"))
857                 {
858                     if (attr->children
859                         && attr->children->type==XML_TEXT_NODE
860                         && attr->children->content)
861                         *backend_db = (const char *) attr->children->content;
862                 }
863             return name;
864         }
865     }
866 #endif
867     return 0;
868 }
869
870 char *Yaz_ProxyConfig::get_explain_doc(ODR odr, const char *name,
871                                        const char *db, int *len)
872 {
873 #if HAVE_XSLT
874     xmlNodePtr ptr_target, ptr_explain;
875     if (m_cp->get_explain_ptr(0 /* host */, db, &ptr_target, &ptr_explain))
876     {
877         xmlNodePtr ptr2 = xmlCopyNode(ptr_explain, 1);
878         
879         xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
880         
881         xmlDocSetRootElement(doc, ptr2);
882         
883         xmlChar *buf_out;
884         xmlDocDumpMemory(doc, &buf_out, len);
885         char *content = (char*) odr_malloc(odr, *len);
886         memcpy(content, buf_out, *len);
887         
888         xmlFree(buf_out);
889         xmlFreeDoc(doc);
890         return content;
891     }
892 #endif
893     return 0;
894 }
895
896 void Yaz_ProxyConfig::get_target_info(const char *name,
897                                       const char **url,
898                                       int *limit_bw,
899                                       int *limit_pdu,
900                                       int *limit_req,
901                                       int *target_idletime,
902                                       int *client_idletime,
903                                       int *max_clients,
904                                       int *keepalive_limit_bw,
905                                       int *keepalive_limit_pdu,
906                                       int *pre_init,
907                                       const char **cql2rpn)
908 {
909 #if HAVE_XSLT
910     xmlNodePtr ptr;
911     if (!m_cp->m_proxyPtr)
912     {
913         url[0] = name;
914         url[1] = 0;
915         return;
916     }
917     url[0] = 0;
918     for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
919     {
920         if (ptr->type == XML_ELEMENT_NODE &&
921             !strcmp((const char *) ptr->name, "max-clients"))
922         {
923             const char *t = m_cp->get_text(ptr);
924             if (t)
925             {
926                 *max_clients = atoi(t);
927                 if (*max_clients  < 1)
928                     *max_clients = 1;
929             }
930         }
931     }
932     ptr = m_cp->find_target_node(name, 0);
933     if (ptr)
934     {
935         if (name)
936         {
937             url[0] = name;
938             url[1] = 0;
939         }
940         m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
941                                  target_idletime, client_idletime,
942                                  keepalive_limit_bw, keepalive_limit_pdu,
943                                  pre_init, cql2rpn);
944     }
945 #else
946     *url = name;
947     return;
948 #endif
949 }
950
951