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