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