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