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