Use AM_LDFLAGS instead of LDFLAGS
[yazpp-moved-to-github.git] / src / yaz-proxy-config.cpp
1 /*
2  * Copyright (c) 1998-2004, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-proxy-config.cpp,v 1.25 2004-01-24 21:31:59 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_XSLT
16     m_docPtr = 0;
17     m_proxyPtr = 0;
18 #endif
19 }
20
21 Yaz_ProxyConfig::~Yaz_ProxyConfig()
22 {
23 #if HAVE_XSLT
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_XSLT
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_XSLT
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_XSLT
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_XSLT
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                                          int *pre_init,
121                                          const char **cql2rpn)
122 {
123     *pre_init = 0;
124     int no_url = 0;
125     ptr = ptr->children;
126     for (; ptr; ptr = ptr->next)
127     {
128         if (ptr->type == XML_ELEMENT_NODE 
129             && !strcmp((const char *) ptr->name, "preinit"))
130         {
131             const char *v = get_text(ptr);
132             *pre_init = v ? atoi(v) : 1;
133         }
134         if (ptr->type == XML_ELEMENT_NODE 
135             && !strcmp((const char *) ptr->name, "url"))
136         {
137             const char *t = get_text(ptr);
138             if (t && no_url < MAX_ZURL_PLEX)
139             {
140                 url[no_url++] = t;
141                 url[no_url] = 0;
142             }
143         }
144         if (ptr->type == XML_ELEMENT_NODE 
145             && !strcmp((const char *) ptr->name, "keepalive"))
146         {
147             int dummy;
148             *keepalive_limit_bw = 500000;
149             *keepalive_limit_pdu = 1000;
150             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
151                          &dummy);
152         }
153         if (ptr->type == XML_ELEMENT_NODE 
154             && !strcmp((const char *) ptr->name, "limit"))
155             return_limit(ptr, limit_bw, limit_pdu, limit_req);
156         if (ptr->type == XML_ELEMENT_NODE 
157             && !strcmp((const char *) ptr->name, "target-timeout"))
158         {
159             const char *t = get_text(ptr);
160             if (t)
161             {
162                 *target_idletime = atoi(t);
163                 if (*target_idletime < 0)
164                     *target_idletime = 0;
165             }
166         }
167         if (ptr->type == XML_ELEMENT_NODE 
168             && !strcmp((const char *) ptr->name, "client-timeout"))
169         {
170             const char *t = get_text(ptr);
171             if (t)
172             {
173                 *client_idletime = atoi(t);
174                 if (*client_idletime < 0)
175                     *client_idletime = 0;
176             }
177         }
178         if (ptr->type == XML_ELEMENT_NODE 
179             && !strcmp((const char *) ptr->name, "cql2rpn"))
180         {
181             const char *t = get_text(ptr);
182             if (t)
183                 *cql2rpn = t;
184         }
185     }
186 }
187 #endif
188
189 int Yaz_ProxyConfig::atoi_l(const char **cp)
190 {
191     int v = 0;
192     while (**cp && isdigit(**cp))
193     {
194         v = v*10 + (**cp - '0');
195         (*cp)++;
196     }
197     return v;
198 }
199
200 int Yaz_ProxyConfig::match_list(int v, const char *m)
201 {
202   while(m && *m)
203   {
204       while(*m && isspace(*m))
205           m++;
206       if (*m == '*')
207           return 1;
208       int l = atoi_l(&m);
209       int h = l;
210       if (*m == '-')
211       {
212           ++m;
213           h = atoi_l(&m);
214       }
215       if (v >= l && v <= h)
216           return 1;
217       if (*m == ',')
218           m++;
219   }
220   return 0;
221 }
222
223 #if HAVE_XSLT
224 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
225                                              Z_AttributeList *attrs,
226                                              char **addinfo)
227 {
228     int i;
229     for (i = 0; i<attrs->num_attributes; i++)
230     {
231         Z_AttributeElement *el = attrs->attributes[i];
232         
233         if (!el->attributeType)
234             continue;
235         int type = *el->attributeType;
236         int *value = 0;
237         
238         if (el->which == Z_AttributeValue_numeric && el->value.numeric)
239             value = el->value.numeric;
240         
241         xmlNodePtr ptr;
242         for(ptr = ptrl->children; ptr; ptr = ptr->next)
243         {
244             if (ptr->type == XML_ELEMENT_NODE &&
245                 !strcmp((const char *) ptr->name, "attribute"))
246             {
247                 const char *match_type = 0;
248                 const char *match_value = 0;
249                 const char *match_error = 0;
250                 struct _xmlAttr *attr;
251                 for (attr = ptr->properties; attr; attr = attr->next)
252                 {
253                     if (!strcmp((const char *) attr->name, "type") &&
254                         attr->children && attr->children->type == XML_TEXT_NODE)
255                         match_type = (const char *) attr->children->content;
256                     if (!strcmp((const char *) attr->name, "value") &&
257                         attr->children && attr->children->type == XML_TEXT_NODE)
258                         match_value = (const char *) attr->children->content;
259                     if (!strcmp((const char *) attr->name, "error") &&
260                         attr->children && attr->children->type == XML_TEXT_NODE)
261                         match_error = (const char *) attr->children->content;
262                 }
263                 if (match_type && match_value)
264                 {
265                     char addinfo_str[20];
266                     if (!match_list(type, match_type))
267                         continue;
268                     
269                     *addinfo_str = '\0';
270                     if (!strcmp(match_type, "*"))
271                         sprintf (addinfo_str, "%d", type);
272                     else if (value)
273                     {
274                         if (!match_list(*value, match_value))
275                             continue;
276                         sprintf (addinfo_str, "%d", *value);
277                     }
278                     else
279                         continue;
280                     
281                     if (match_error)
282                     {
283                         if (*addinfo_str)
284                             *addinfo = odr_strdup(odr, addinfo_str);
285                         return atoi(match_error);
286                     }
287                     break;
288                 }
289             }
290         }
291     }
292     return 0;
293 }
294 #endif
295
296 #if HAVE_XSLT
297 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
298                                             Z_RPNStructure *q,
299                                             char **addinfo)
300 {
301     if (q->which == Z_RPNStructure_complex)
302     {
303         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
304         if (e)
305             return e;
306         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
307         return e;
308     }
309     else if (q->which == Z_RPNStructure_simple)
310     {
311         if (q->u.simple->which == Z_Operand_APT)
312         {
313             return check_type_1_attributes(
314                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
315                 addinfo);
316         }
317     }
318     return 0;
319 }
320 #endif
321
322 #if HAVE_XSLT
323 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
324                                   char **addinfo)
325 {
326     // possibly check for Bib-1
327     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
328 }
329 #endif
330
331 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
332                                  char **addinfo)
333 {
334 #if HAVE_XSLT
335     xmlNodePtr ptr;
336     
337     ptr = find_target_node(name, 0);
338     if (ptr)
339     {
340         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
341             return check_type_1(odr, ptr, query->u.type_1, addinfo);
342     }
343 #endif
344     return 0;
345 }
346
347 #if HAVE_XSLT
348 int Yaz_ProxyConfig::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
349                                   const char *schema_identifier)
350 {
351     char *esn = 0;
352     int default_match = 1;
353     if (comp && comp->which == Z_RecordComp_simple &&
354         comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
355     {
356         esn = comp->u.simple->u.generic;
357     }
358     // if no ESN/schema was given accept..
359     if (!esn)
360         return 1;
361     // check if schema identifier match
362     if (schema_identifier && !strcmp(esn, schema_identifier))
363         return 1;
364     // Check each name element
365     for (; ptr; ptr = ptr->next)
366     {
367         if (ptr->type == XML_ELEMENT_NODE 
368             && !strcmp((const char *) ptr->name, "name"))
369         {
370             xmlNodePtr tptr = ptr->children;
371             default_match = 0;
372             for (; tptr; tptr = tptr->next)
373                 if (tptr->type == XML_TEXT_NODE && tptr->content)
374                 {
375                     xmlChar *t = tptr->content;
376                     while (*t && isspace(*t))
377                         t++;
378                     int i = 0;
379                     while (esn[i] && esn[i] == t[i])
380                         i++;
381                     if (!esn[i] && (!t[i] || isspace(t[i])))
382                         return 1;
383                 }
384         }
385     }
386     return default_match;
387 }
388 #endif
389
390 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
391                                   Odr_oid *syntax, Z_RecordComposition *comp,
392                                   char **addinfo,
393                                   char **stylesheet, char **schema)
394 {
395     if (stylesheet)
396     {
397         xfree (*stylesheet);
398         *stylesheet = 0;
399     }
400     if (schema)
401     {
402         xfree (*schema);
403         *schema = 0;
404     }
405 #if HAVE_XSLT
406     int syntax_has_matched = 0;
407     xmlNodePtr ptr;
408     
409     ptr = find_target_node(name, 0);
410     if (!ptr)
411         return 0;
412     for(ptr = ptr->children; ptr; ptr = ptr->next)
413     {
414         if (ptr->type == XML_ELEMENT_NODE &&
415             !strcmp((const char *) ptr->name, "syntax"))
416         {
417             int match = 0;  // if we match record syntax
418             const char *match_type = 0;
419             const char *match_error = 0;
420             const char *match_marcxml = 0;
421             const char *match_stylesheet = 0;
422             const char *match_identifier = 0;
423             struct _xmlAttr *attr;
424             for (attr = ptr->properties; attr; attr = attr->next)
425             {
426                 if (!strcmp((const char *) attr->name, "type") &&
427                     attr->children && attr->children->type == XML_TEXT_NODE)
428                     match_type = (const char *) attr->children->content;
429                 if (!strcmp((const char *) attr->name, "error") &&
430                     attr->children && attr->children->type == XML_TEXT_NODE)
431                     match_error = (const char *) attr->children->content;
432                 if (!strcmp((const char *) attr->name, "marcxml") &&
433                     attr->children && attr->children->type == XML_TEXT_NODE)
434                     match_marcxml = (const char *) attr->children->content;
435                 if (!strcmp((const char *) attr->name, "stylesheet") &&
436                     attr->children && attr->children->type == XML_TEXT_NODE)
437                     match_stylesheet = (const char *) attr->children->content;
438                 if (!strcmp((const char *) attr->name, "identifier") &&
439                     attr->children && attr->children->type == XML_TEXT_NODE)
440                     match_identifier = (const char *) attr->children->content;
441             }
442             if (match_type)
443             {
444                 if (!strcmp(match_type, "*"))
445                     match = 1;
446                 else if (!strcmp(match_type, "none"))
447                 {
448                     if (syntax == 0)
449                         match = 1;
450                 }
451                 else if (syntax)
452                 {
453                     int match_oid[OID_SIZE];
454                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
455                     if (oid_oidcmp(match_oid, syntax) == 0)
456                         match = 1;
457                 }
458             }
459             if (match)
460             {
461                 if (!match_error)
462                     syntax_has_matched = 1;
463                 match = check_schema(ptr->children, comp, match_identifier);
464             }
465             if (match)
466             {
467                 if (stylesheet && match_stylesheet)
468                 {
469                     xfree(*stylesheet);
470                     *stylesheet = xstrdup(match_stylesheet);
471                 }
472                 if (schema && match_identifier)
473                 {
474                     xfree(*schema);
475                     *schema = xstrdup(match_identifier);
476                 }
477                 if (match_marcxml)
478                 {
479                     return -1;
480                 }
481                 if (match_error)
482                 {
483                     if (syntax_has_matched)  // if syntax OK, bad schema/ESN
484                         return 25;
485                     if (syntax)
486                     {
487                         char dotoid_str[100];
488                         oid_to_dotstring(syntax, dotoid_str);
489                         *addinfo = odr_strdup(odr, dotoid_str);
490                     }
491                     return atoi(match_error);
492                 }
493                 return 0;
494             }
495         }
496     }
497 #endif
498     return 0;
499 }
500
501 #if HAVE_XSLT
502 xmlNodePtr Yaz_ProxyConfig::find_target_db(xmlNodePtr ptr, const char *db)
503 {
504     xmlNodePtr dptr;
505     if (!db)
506         return ptr;
507     if (!ptr)
508         return 0;
509     for (dptr = ptr->children; dptr; dptr = dptr->next)
510         if (dptr->type == XML_ELEMENT_NODE &&
511             !strcmp((const char *) dptr->name, "database"))
512         {
513             struct _xmlAttr *attr;
514             for (attr = dptr->properties; attr; attr = attr->next)
515                 if (!strcmp((const char *) attr->name, "name"))
516                 {
517                     if (attr->children
518                         && attr->children->type==XML_TEXT_NODE
519                         && attr->children->content 
520                         && (!strcmp((const char *) attr->children->content, db)
521                             || !strcmp((const char *) attr->children->content,
522                                        "*")))
523                         return dptr;
524                 }
525         }
526     return ptr;
527 }
528     
529 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name, const char *db)
530 {
531     xmlNodePtr ptr;
532     if (!m_proxyPtr)
533         return 0;
534     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
535     {
536         if (ptr->type == XML_ELEMENT_NODE &&
537             !strcmp((const char *) ptr->name, "target"))
538         {
539             // default one ? 
540             if (!name)
541             {
542                 // <target default="1"> ?
543                 struct _xmlAttr *attr;
544                 for (attr = ptr->properties; attr; attr = attr->next)
545                     if (!strcmp((const char *) attr->name, "default") &&
546                         attr->children && attr->children->type == XML_TEXT_NODE)
547                     {
548                         xmlChar *t = attr->children->content;
549                         if (!t || *t == '1')
550                         {
551                             return find_target_db(ptr, db);
552                         }
553                     }
554             }
555             else
556             {
557                 // <target name="name"> ?
558                 struct _xmlAttr *attr;
559                 for (attr = ptr->properties; attr; attr = attr->next)
560                     if (!strcmp((const char *) attr->name, "name"))
561                     {
562                         if (attr->children
563                             && attr->children->type==XML_TEXT_NODE
564                             && attr->children->content 
565                             && (!strcmp((const char *) attr->children->content,
566                                         name)
567                                 || !strcmp((const char *) attr->children->content,
568                                            "*")))
569                         {
570                             return find_target_db(ptr, db);
571                         }
572                     }
573             }
574         }
575     }
576     return 0;
577 }
578 #endif
579
580 int Yaz_ProxyConfig::get_target_no(int no,
581                                    const char **name,
582                                    const char **url,
583                                    int *limit_bw,
584                                    int *limit_pdu,
585                                    int *limit_req,
586                                    int *target_idletime,
587                                    int *client_idletime,
588                                    int *max_clients,
589                                    int *keepalive_limit_bw,
590                                    int *keepalive_limit_pdu,
591                                    int *pre_init,
592                                    const char **cql2rpn)
593 {
594 #if HAVE_XSLT
595     xmlNodePtr ptr;
596     if (!m_proxyPtr)
597         return 0;
598     int i = 0;
599     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
600         if (ptr->type == XML_ELEMENT_NODE &&
601             !strcmp((const char *) ptr->name, "target"))
602         {
603             if (i == no)
604             {
605                 struct _xmlAttr *attr;
606                 for (attr = ptr->properties; attr; attr = attr->next)
607                     if (!strcmp((const char *) attr->name, "name"))
608                     {
609                         if (attr->children
610                             && attr->children->type==XML_TEXT_NODE
611                             && attr->children->content)
612                             *name = (const char *) attr->children->content;
613                     }
614                 return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
615                                    target_idletime, client_idletime,
616                                    keepalive_limit_bw, keepalive_limit_pdu,
617                                    pre_init, cql2rpn);
618                 return 1;
619             }
620             i++;
621         }
622 #endif
623     return 0;
624 }
625
626 int Yaz_ProxyConfig::mycmp(const char *hay, const char *item, size_t len)
627 {
628     if (len == strlen(item) && memcmp(hay, item, len) == 0)
629         return 1;
630     return 0;
631 }
632
633 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
634                                        int *max_clients)
635 {
636 #if HAVE_XSLT
637     xmlNodePtr ptr;
638     if (!m_proxyPtr)
639         return;
640     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
641     {
642         if (ptr->type == XML_ELEMENT_NODE 
643             && !strcmp((const char *) ptr->name, "log"))
644         {
645             const char *v = get_text(ptr);
646             *log_mask = 0;
647             while (v && *v)
648             {
649                 const char *cp = v;
650                 while (*cp && *cp != ',' && !isspace(*cp))
651                     cp++;
652                 size_t len = cp - v;
653                 if (mycmp(v, "client-apdu", len))
654                     *log_mask |= PROXY_LOG_APDU_CLIENT;
655                 if (mycmp(v, "server-apdu", len))
656                     *log_mask |= PROXY_LOG_APDU_SERVER;
657                 if (mycmp(v, "client-requests", len))
658                     *log_mask |= PROXY_LOG_REQ_CLIENT;
659                 if (mycmp(v, "server-requests", len))
660                     *log_mask |= PROXY_LOG_REQ_SERVER;
661                 if (isdigit(*v))
662                     *log_mask |= atoi(v);
663                 if (*cp == ',')
664                     cp++;
665                 while (*cp && isspace(*cp))
666                     cp++;
667                 v = cp;
668             }
669         }
670         if (ptr->type == XML_ELEMENT_NODE &&
671             !strcmp((const char *) ptr->name, "max-clients"))
672         {
673             const char *t = get_text(ptr);
674             if (t)
675             {
676                 *max_clients = atoi(t);
677                 if (*max_clients  < 1)
678                     *max_clients = 1;
679             }
680         }
681     }
682 #endif
683 }
684
685 char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
686                                    int *len)
687 {
688 #if HAVE_XSLT
689     xmlNodePtr ptr = find_target_node(name, db);
690     if (ptr)
691     {
692         ptr = ptr->children;
693         for (; ptr; ptr = ptr->next)
694             if (ptr->type == XML_ELEMENT_NODE &&
695                 !strcmp((const char *) ptr->name, "explain"))
696             {
697                 xmlNodePtr ptr1 = ptr->children;
698                 if (db)
699                 {
700                     for (; ptr1; ptr1 = ptr1->next)
701                         if (ptr1->type == XML_ELEMENT_NODE &&
702                             !strcmp((const char *) ptr1->name, "serverInfo"))
703                             break;
704                     if (!ptr1)
705                         continue;
706                     for (ptr1 = ptr1->children; ptr; ptr1 = ptr1->next)
707                         if (ptr1->type == XML_ELEMENT_NODE &&
708                             !strcmp((const char *) ptr1->name, "database"))
709                             break;
710                     
711                     if (!ptr1)
712                         continue;
713                     for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
714                         if (ptr1->type == XML_TEXT_NODE &&
715                             ptr1->content &&
716                             !strcmp((const char *) ptr1->content, db))
717                             break;
718                     if (!ptr1)
719                         continue;
720                 }
721                 xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
722
723                 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
724                 
725                 xmlDocSetRootElement(doc, ptr2);
726                 
727                 xmlChar *buf_out;
728                 xmlDocDumpMemory(doc, &buf_out, len);
729                 char *content = (char*) odr_malloc(odr, *len);
730                 memcpy(content, buf_out, *len);
731                 
732                 xmlFree(buf_out);
733                 xmlFreeDoc(doc);
734                 return content;
735             }
736     }
737 #endif
738     yaz_log(LOG_WARN, "No explain node");
739     return 0;
740 }
741
742 void Yaz_ProxyConfig::get_target_info(const char *name,
743                                       const char **url,
744                                       int *limit_bw,
745                                       int *limit_pdu,
746                                       int *limit_req,
747                                       int *target_idletime,
748                                       int *client_idletime,
749                                       int *max_clients,
750                                       int *keepalive_limit_bw,
751                                       int *keepalive_limit_pdu,
752                                       int *pre_init,
753                                       const char **cql2rpn)
754 {
755 #if HAVE_XSLT
756     xmlNodePtr ptr;
757     if (!m_proxyPtr)
758     {
759         url[0] = name;
760         url[1] = 0;
761         return;
762     }
763     url[0] = 0;
764     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
765     {
766         if (ptr->type == XML_ELEMENT_NODE &&
767             !strcmp((const char *) ptr->name, "max-clients"))
768         {
769             const char *t = get_text(ptr);
770             if (t)
771             {
772                 *max_clients = atoi(t);
773                 if (*max_clients  < 1)
774                     *max_clients = 1;
775             }
776         }
777     }
778     ptr = find_target_node(name, 0);
779     if (ptr)
780     {
781         if (name)
782         {
783             url[0] = name;
784             url[1] = 0;
785         }
786         return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
787                            target_idletime, client_idletime,
788                            keepalive_limit_bw, keepalive_limit_pdu,
789                            pre_init, cql2rpn);
790     }
791 #else
792     *url = name;
793     return;
794 #endif
795 }
796
797