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