USMARC to MARCXML conversion. Check for reconfigure in more places
[yazpp-moved-to-github.git] / src / yaz-proxy-config.cpp
1 /*
2  * Copyright (c) 1998-2003, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-proxy-config.cpp,v 1.8 2003-10-10 17:58:29 adam Exp $
6  */
7
8 #include <ctype.h>
9 #include <yaz/log.h>
10 #include <yaz++/proxy.h>
11
12 Yaz_ProxyConfig::Yaz_ProxyConfig()
13 {
14     m_copy = 0;
15 #if HAVE_XML2
16     m_docPtr = 0;
17     m_proxyPtr = 0;
18 #endif
19 }
20
21 Yaz_ProxyConfig::~Yaz_ProxyConfig()
22 {
23 #if HAVE_XML2
24     if (!m_copy && m_docPtr)
25         xmlFreeDoc(m_docPtr);
26 #endif
27 }
28
29 int Yaz_ProxyConfig::read_xml(const char *fname)
30 {
31 #if HAVE_XML2
32     xmlDocPtr ndoc = xmlParseFile(fname);
33
34     if (!ndoc)
35     {
36         yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
37         return -1;  // no good
38     }
39     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
40     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
41         strcmp((const char *) proxyPtr->name, "proxy"))
42     {
43         yaz_log(LOG_WARN, "No proxy element in %s", fname);
44         xmlFreeDoc(ndoc);
45         return -1;
46     }
47     m_proxyPtr = proxyPtr;
48
49     // OK: release previous and make it the current one.
50     if (m_docPtr)
51         xmlFreeDoc(m_docPtr);
52     m_docPtr = ndoc;
53     return 0;
54 #else
55     return -2;
56 #endif
57 }
58
59 #if HAVE_XML2
60 const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
61 {
62     for(ptr = ptr->children; ptr; ptr = ptr->next)
63         if (ptr->type == XML_TEXT_NODE)
64         {
65             xmlChar *t = ptr->content;
66             if (t)
67             {
68                 while (*t == ' ')
69                     t++;
70                 return (const char *) t;
71             }
72         }
73     return 0;
74 }
75 #endif
76
77 #if HAVE_XML2
78 void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
79                                    int *limit_bw,
80                                    int *limit_pdu,
81                                    int *limit_req)
82 {
83     for (ptr = ptr->children; ptr; ptr = ptr->next)
84     {
85         if (ptr->type == XML_ELEMENT_NODE 
86             && !strcmp((const char *) ptr->name, "bandwidth"))
87         {
88             const char *t = get_text(ptr);
89             if (t)
90                 *limit_bw = atoi(t);
91         }
92         if (ptr->type == XML_ELEMENT_NODE 
93             && !strcmp((const char *) ptr->name, "retrieve"))
94         {
95             const char *t = get_text(ptr);
96             if (t)
97                 *limit_req = atoi(t);
98         }
99         if (ptr->type == XML_ELEMENT_NODE 
100             && !strcmp((const char *) ptr->name, "pdu"))
101         {
102             const char *t = get_text(ptr);
103             if (t)
104                 *limit_pdu = atoi(t);
105         }
106     }
107 }
108 #endif
109
110 #if HAVE_XML2
111 void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
112                                          const char **url,
113                                          int *limit_bw,
114                                          int *limit_pdu,
115                                          int *limit_req,
116                                          int *target_idletime,
117                                          int *client_idletime,
118                                          int *keepalive_limit_bw,
119                                          int *keepalive_limit_pdu)
120 {
121     int no_url = 0;
122     ptr = ptr->children;
123     for (; ptr; ptr = ptr->next)
124     {
125         if (ptr->type == XML_ELEMENT_NODE 
126             && !strcmp((const char *) ptr->name, "url"))
127         {
128             const char *t = get_text(ptr);
129             if (t && no_url < MAX_ZURL_PLEX)
130             {
131                 url[no_url++] = t;
132                 url[no_url] = 0;
133             }
134         }
135         if (ptr->type == XML_ELEMENT_NODE 
136             && !strcmp((const char *) ptr->name, "keepalive"))
137         {
138             int dummy;
139             *keepalive_limit_bw = 500000;
140             *keepalive_limit_pdu = 1000;
141             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
142                          &dummy);
143         }
144         if (ptr->type == XML_ELEMENT_NODE 
145             && !strcmp((const char *) ptr->name, "limit"))
146             return_limit(ptr, limit_bw, limit_pdu, limit_req);
147         if (ptr->type == XML_ELEMENT_NODE 
148             && !strcmp((const char *) ptr->name, "target-timeout"))
149         {
150             const char *t = get_text(ptr);
151             if (t)
152             {
153                 *target_idletime = atoi(t);
154                 if (*target_idletime < 0)
155                     *target_idletime = 0;
156             }
157         }
158         if (ptr->type == XML_ELEMENT_NODE 
159             && !strcmp((const char *) ptr->name, "client-timeout"))
160         {
161             const char *t = get_text(ptr);
162             if (t)
163             {
164                 *client_idletime = atoi(t);
165                 if (*client_idletime < 0)
166                     *client_idletime = 0;
167             }
168         }
169     }
170 }
171 #endif
172
173 int Yaz_ProxyConfig::atoi_l(const char **cp)
174 {
175     int v = 0;
176     while (**cp && isdigit(**cp))
177     {
178         v = v*10 + (**cp - '0');
179         (*cp)++;
180     }
181     return v;
182 }
183
184 int Yaz_ProxyConfig::match_list(int v, const char *m)
185 {
186   while(m && *m)
187   {
188       while(*m && isspace(*m))
189           m++;
190       if (*m == '*')
191           return 1;
192       int l = atoi_l(&m);
193       int h = l;
194       if (*m == '-')
195       {
196           ++m;
197           h = atoi_l(&m);
198       }
199       if (v >= l && v <= h)
200           return 1;
201       if (*m == ',')
202           m++;
203   }
204   return 0;
205 }
206
207 #if HAVE_XML2
208 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptr,
209                                              Z_AttributeList *attrs,
210                                              char **addinfo)
211 {
212     for(ptr = ptr->children; ptr; ptr = ptr->next)
213     {
214         if (ptr->type == XML_ELEMENT_NODE &&
215             !strcmp((const char *) ptr->name, "attribute"))
216         {
217             const char *match_type = 0;
218             const char *match_value = 0;
219             const char *match_error = 0;
220             struct _xmlAttr *attr;
221             for (attr = ptr->properties; attr; attr = attr->next)
222             {
223                 if (!strcmp((const char *) attr->name, "type") &&
224                     attr->children && attr->children->type == XML_TEXT_NODE)
225                     match_type = (const char *) attr->children->content;
226                 if (!strcmp((const char *) attr->name, "value") &&
227                     attr->children && attr->children->type == XML_TEXT_NODE)
228                     match_value = (const char *) attr->children->content;
229                 if (!strcmp((const char *) attr->name, "error") &&
230                     attr->children && attr->children->type == XML_TEXT_NODE)
231                     match_error = (const char *) attr->children->content;
232             }
233             int i;
234
235             if (match_type && match_value)
236             {
237                 for (i = 0; i<attrs->num_attributes; i++)
238                 {
239                     Z_AttributeElement *el = attrs->attributes[i];
240                     char value_str[20];
241                     
242                     value_str[0] = '\0';
243                     if (!el->attributeType)
244                         continue;
245                     int type = *el->attributeType;
246
247                     if (!match_list(type, match_type))
248                         continue;
249                     if (el->which == Z_AttributeValue_numeric && 
250                         el->value.numeric)
251                     {
252                         if (!match_list(*el->value.numeric, match_value))
253                             continue;
254                         sprintf (value_str, "%d", *el->value.numeric);
255                     }
256                     else
257                         continue;
258                     if (match_error)
259                     {
260                         if (*value_str)
261                             *addinfo = odr_strdup(odr, value_str);
262                         return atoi(match_error);
263                     }
264                     return 0;
265                 }
266             }
267         }
268     }
269     return 0;
270 }
271 #endif
272
273 #if HAVE_XML2
274 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
275                                             Z_RPNStructure *q,
276                                             char **addinfo)
277 {
278     int c;
279     if (q->which == Z_RPNStructure_complex)
280     {
281         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
282         if (e)
283             return e;
284         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
285         return e;
286     }
287     else if (q->which == Z_RPNStructure_simple)
288     {
289         if (q->u.simple->which == Z_Operand_APT)
290         {
291             return check_type_1_attributes(
292                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
293                 addinfo);
294         }
295     }
296     return 0;
297 }
298 #endif
299
300 #if HAVE_XML2
301 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
302                                   char **addinfo)
303 {
304     // possibly check for Bib-1
305     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
306 }
307 #endif
308
309 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
310                                  char **addinfo)
311 {
312 #if HAVE_XML2
313     xmlNodePtr ptr;
314     
315     ptr = find_target_node(name);
316     if (ptr)
317     {
318         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
319             return check_type_1(odr, ptr, query->u.type_1, addinfo);
320     }
321 #endif
322     return 0;
323 }
324
325 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
326                                   Odr_oid *syntax, char **addinfo)
327 {
328 #if HAVE_XML2
329     xmlNodePtr ptr;
330     
331     ptr = find_target_node(name);
332     if (!ptr)
333         return 0;
334     for(ptr = ptr->children; ptr; ptr = ptr->next)
335     {
336         if (ptr->type == XML_ELEMENT_NODE &&
337             !strcmp((const char *) ptr->name, "syntax"))
338         {
339             int match = 0;  // if we match record syntax
340             const char *match_type = 0;
341             const char *match_error = 0;
342             const char *match_marcxml = 0;
343             struct _xmlAttr *attr;
344             for (attr = ptr->properties; attr; attr = attr->next)
345             {
346                 if (!strcmp((const char *) attr->name, "type") &&
347                     attr->children && attr->children->type == XML_TEXT_NODE)
348                     match_type = (const char *) attr->children->content;
349                 if (!strcmp((const char *) attr->name, "error") &&
350                     attr->children && attr->children->type == XML_TEXT_NODE)
351                     match_error = (const char *) attr->children->content;
352                 if (!strcmp((const char *) attr->name, "marcxml") &&
353                     attr->children && attr->children->type == XML_TEXT_NODE)
354                     match_marcxml = (const char *) attr->children->content;
355             }
356             if (match_type)
357             {
358                 if (!strcmp(match_type, "*"))
359                     match = 1;
360                 else if (!strcmp(match_type, "none"))
361                 {
362                     if (syntax == 0)
363                         match = 1;
364                 }
365                 else if (syntax)
366                 {
367                     int match_oid[OID_SIZE];
368                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
369                     if (oid_oidcmp(match_oid, syntax) == 0)
370                         match = 1;
371                 }
372             }
373             if (match)
374             {
375                 if (match_marcxml)
376                 {
377                     return -1;
378                 }
379                 if (match_error)
380                 {
381                     if (syntax)
382                     {
383                         char dotoid_str[100];
384                         oid_to_dotstring(syntax, dotoid_str);
385                         *addinfo = odr_strdup(odr, dotoid_str);
386                     }
387                     return atoi(match_error);
388                 }
389                 return 0;
390             }
391         }
392     }
393 #endif
394     return 0;
395 }
396
397 #if HAVE_XML2
398 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
399 {
400     xmlNodePtr ptr;
401     if (!m_proxyPtr)
402         return 0;
403     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
404     {
405         if (ptr->type == XML_ELEMENT_NODE &&
406             !strcmp((const char *) ptr->name, "target"))
407         {
408             // default one ? 
409             if (!name)
410             {
411                 // <target default="1"> ?
412                 struct _xmlAttr *attr;
413                 for (attr = ptr->properties; attr; attr = attr->next)
414                     if (!strcmp((const char *) attr->name, "default") &&
415                         attr->children && attr->children->type == XML_TEXT_NODE)
416                     {
417                         xmlChar *t = attr->children->content;
418                         if (!t || *t == '1')
419                             return ptr;
420                     }
421             }
422             else
423             {
424                 // <target name="name"> ?
425                 struct _xmlAttr *attr;
426                 for (attr = ptr->properties; attr; attr = attr->next)
427                     if (!strcmp((const char *) attr->name, "name"))
428                     {
429                         if (attr->children
430                             && attr->children->type==XML_TEXT_NODE
431                             && attr->children->content 
432                             && (!strcmp((const char *) attr->children->content,
433                                         name)
434                                 || !strcmp((const char *) attr->children->content,
435                                            "*")))
436                         {
437                             return ptr;
438                         }
439                     }
440             }
441         }
442     }
443     return 0;
444 }
445 #endif
446
447 void Yaz_ProxyConfig::get_target_info(const char *name,
448                                       const char **url,
449                                       int *limit_bw,
450                                       int *limit_pdu,
451                                       int *limit_req,
452                                       int *target_idletime,
453                                       int *client_idletime,
454                                       int *max_clients,
455                                       int *keepalive_limit_bw,
456                                       int *keepalive_limit_pdu)
457 {
458 #if HAVE_XML2
459     xmlNodePtr ptr;
460     if (!m_proxyPtr)
461     {
462         url[0] = name;
463         url[1] = 0;
464         return;
465     }
466     url[0] = 0;
467     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
468     {
469         if (ptr->type == XML_ELEMENT_NODE &&
470             !strcmp((const char *) ptr->name, "max-clients"))
471         {
472             const char *t = get_text(ptr);
473             if (t)
474             {
475                 *max_clients = atoi(t);
476                 if (*max_clients  < 1)
477                     *max_clients = 1;
478             }
479         }
480     }
481     ptr = find_target_node(name);
482     if (ptr)
483     {
484         if (name)
485         {
486             url[0] = name;
487             url[1] = 0;
488         }
489         return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
490                            target_idletime, client_idletime,
491                            keepalive_limit_bw, keepalive_limit_pdu);
492     }
493 #else
494     *url = name;
495     return;
496 #endif
497 }
498
499