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