get hostname from system call 'gethostname()' if not set in
[pazpar2-moved-to-github.git] / src / config.c
1 /* $Id: config.c,v 1.20 2007-03-31 20:55:19 marc Exp $ */
2
3 #include <string.h>
4 #include <unistd.h>
5
6 #include <libxml/parser.h>
7 #include <libxml/tree.h>
8 #include <libxslt/xslt.h>
9 #include <libxslt/transform.h>
10 #include <libxslt/xsltutils.h>
11
12 #if HAVE_CONFIG_H
13 #include <cconfig.h>
14 #endif
15
16 #include <yaz/yaz-util.h>
17 #include <yaz/nmem.h>
18
19 #define CONFIG_NOEXTERNS
20 #include "config.h"
21
22 static NMEM nmem = 0;
23 static char confdir[256] = ".";
24
25 struct conf_config *config = 0;
26
27 /* Code to parse configuration file */
28 /* ==================================================== */
29
30 static struct conf_service *parse_service(xmlNode *node)
31 {
32     xmlNode *n;
33     struct conf_service *r = nmem_malloc(nmem, sizeof(struct conf_service));
34     int md_node = 0;
35     int sk_node = 0;
36
37     r->num_sortkeys = r->num_metadata = 0;
38     // Allocate array of conf metadata and sortkey tructs, if necessary
39     for (n = node->children; n; n = n->next)
40         if (n->type == XML_ELEMENT_NODE && !strcmp((const char *)
41                                                    n->name, "metadata"))
42         {
43             xmlChar *sortkey = xmlGetProp(n, (xmlChar *) "sortkey");
44             r->num_metadata++;
45             if (sortkey && strcmp((const char *) sortkey, "no"))
46                 r->num_sortkeys++;
47             xmlFree(sortkey);
48         }
49     if (r->num_metadata)
50         r->metadata = nmem_malloc(nmem, sizeof(struct conf_metadata) * r->num_metadata);
51     else
52         r->metadata = 0;
53     if (r->num_sortkeys)
54         r->sortkeys = nmem_malloc(nmem, sizeof(struct conf_sortkey) * r->num_sortkeys);
55     else
56         r->sortkeys = 0;
57
58     for (n = node->children; n; n = n->next)
59     {
60         if (n->type != XML_ELEMENT_NODE)
61             continue;
62         if (!strcmp((const char *) n->name, (const char *) "metadata"))
63         {
64             struct conf_metadata *md = &r->metadata[md_node];
65             xmlChar *name = xmlGetProp(n, (xmlChar *) "name");
66             xmlChar *brief = xmlGetProp(n, (xmlChar *) "brief");
67             xmlChar *sortkey = xmlGetProp(n, (xmlChar *) "sortkey");
68             xmlChar *merge = xmlGetProp(n, (xmlChar *) "merge");
69             xmlChar *type = xmlGetProp(n, (xmlChar *) "type");
70             xmlChar *termlist = xmlGetProp(n, (xmlChar *) "termlist");
71             xmlChar *rank = xmlGetProp(n, (xmlChar *) "rank");
72
73             if (!name)
74             {
75                 yaz_log(YLOG_FATAL, "Must specify name in metadata element");
76                 return 0;
77             }
78             md->name = nmem_strdup(nmem, (const char *) name);
79             if (brief)
80             {
81                 if (!strcmp((const char *) brief, "yes"))
82                     md->brief = 1;
83                 else if (strcmp((const char *) brief, "no"))
84                 {
85                     yaz_log(YLOG_FATAL, "metadata/brief must be yes or no");
86                     return 0;
87                 }
88             }
89             else
90                 md->brief = 0;
91
92             if (termlist)
93             {
94                 if (!strcmp((const char *) termlist, "yes"))
95                     md->termlist = 1;
96                 else if (strcmp((const char *) termlist, "no"))
97                 {
98                     yaz_log(YLOG_FATAL, "metadata/termlist must be yes or no");
99                     return 0;
100                 }
101             }
102             else
103                 md->termlist = 0;
104
105             if (rank)
106                 md->rank = atoi((const char *) rank);
107             else
108                 md->rank = 0;
109
110             if (type)
111             {
112                 if (!strcmp((const char *) type, "generic"))
113                     md->type = Metadata_type_generic;
114                 else if (!strcmp((const char *) type, "year"))
115                     md->type = Metadata_type_year;
116                 else
117                 {
118                     yaz_log(YLOG_FATAL, "Unknown value for metadata/type: %s", type);
119                     return 0;
120                 }
121             }
122             else
123                 md->type = Metadata_type_generic;
124
125             if (merge)
126             {
127                 if (!strcmp((const char *) merge, "no"))
128                     md->merge = Metadata_merge_no;
129                 else if (!strcmp((const char *) merge, "unique"))
130                     md->merge = Metadata_merge_unique;
131                 else if (!strcmp((const char *) merge, "longest"))
132                     md->merge = Metadata_merge_longest;
133                 else if (!strcmp((const char *) merge, "range"))
134                     md->merge = Metadata_merge_range;
135                 else if (!strcmp((const char *) merge, "all"))
136                     md->merge = Metadata_merge_all;
137                 else
138                 {
139                     yaz_log(YLOG_FATAL, "Unknown value for metadata/merge: %s", merge);
140                     return 0;
141                 }
142             }
143             else
144                 md->merge = Metadata_merge_no;
145
146             if (sortkey && strcmp((const char *) sortkey, "no"))
147             {
148                 struct conf_sortkey *sk = &r->sortkeys[sk_node];
149                 if (md->merge == Metadata_merge_no)
150                 {
151                     yaz_log(YLOG_FATAL, "Can't specify sortkey on a non-merged field");
152                     return 0;
153                 }
154                 if (!strcmp((const char *) sortkey, "numeric"))
155                     sk->type = Metadata_sortkey_numeric;
156                 else if (!strcmp((const char *) sortkey, "skiparticle"))
157                     sk->type = Metadata_sortkey_skiparticle;
158                 else
159                 {
160                     yaz_log(YLOG_FATAL, "Unknown sortkey in metadata element: %s", sortkey);
161                     return 0;
162                 }
163                 sk->name = md->name;
164                 md->sortkey_offset = sk_node;
165                 sk_node++;
166             }
167             else
168                 md->sortkey_offset = -1;
169
170             xmlFree(name);
171             xmlFree(brief);
172             xmlFree(sortkey);
173             xmlFree(merge);
174             xmlFree(termlist);
175             xmlFree(rank);
176             md_node++;
177         }
178         else
179         {
180             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
181             return 0;
182         }
183     }
184     return r;
185 }
186
187 static char *parse_settings(xmlNode *node)
188 {
189     xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
190     char *r;
191
192     if (src)
193         r = nmem_strdup(nmem, (const char *) src);
194     else
195     {
196         yaz_log(YLOG_FATAL, "Must specify src in targetprofile");
197         return 0;
198     }
199     xmlFree(src);
200     return r;
201 }
202
203 static struct conf_server *parse_server(xmlNode *node)
204 {
205     xmlNode *n;
206     struct conf_server *r = nmem_malloc(nmem, sizeof(struct conf_server));
207
208     r->host = 0;
209     r->port = 0;
210     r->proxy_host = 0;
211     r->proxy_port = 0;
212     r->myurl = 0;
213     r->zproxy_host = 0;
214     r->zproxy_port = 0;
215     r->service = 0;
216     r->next = 0;
217     r->settings = 0;
218
219     for (n = node->children; n; n = n->next)
220     {
221         if (n->type != XML_ELEMENT_NODE)
222             continue;
223         if (!strcmp((const char *) n->name, "listen"))
224         {
225             xmlChar *port = xmlGetProp(n, (xmlChar *) "port");
226             xmlChar *host = xmlGetProp(n, (xmlChar *) "host");
227             if (port)
228                 r->port = atoi((const char *) port);
229             if (host)
230                 r->host = nmem_strdup(nmem, (const char *) host);
231             else { // get hostname from system
232                 size_t len = 128;
233                 char h[len];
234                 if (0 == gethostname(h, len)){
235                     h[len - 1] = '\0';
236                     r->host = nmem_strdup(nmem, h);
237                 } else 
238                     yaz_log(YLOG_WARN, "Could not get host name");
239             }
240             xmlFree(port);
241             xmlFree(host);
242         }
243         else if (!strcmp((const char *) n->name, "proxy"))
244         {
245             xmlChar *port = xmlGetProp(n, (xmlChar *) "port");
246             xmlChar *host = xmlGetProp(n, (xmlChar *) "host");
247             xmlChar *myurl = xmlGetProp(n, (xmlChar *) "myurl");
248             if (port)
249                 r->proxy_port = atoi((const char *) port);
250             if (host)
251                 r->proxy_host = nmem_strdup(nmem, (const char *) host);
252             if (myurl)
253                 r->myurl = nmem_strdup(nmem, (const char *) myurl);
254 #ifdef GAGA
255             else
256             {
257                 yaz_log(YLOG_FATAL, "Must specify @myurl for proxy");
258                 return 0;
259             }
260 #endif
261             xmlFree(port);
262             xmlFree(host);
263             xmlFree(myurl);
264         }
265         else if (!strcmp((const char *) n->name, "zproxy"))
266         {
267             xmlChar *port = 0;
268             xmlChar *host = 0;
269
270             port = xmlGetProp(n, (xmlChar *) "port");
271             host = xmlGetProp(n, (xmlChar *) "host");
272
273             if (port)
274                 r->zproxy_port = atoi((const char *) port);
275             if (host)
276                 r->zproxy_host = nmem_strdup(nmem, (const char *) host);
277
278             xmlFree(port);
279             xmlFree(host);
280         }
281         else if (!strcmp((const char *) n->name, "settings"))
282         {
283             if (r->settings)
284             {
285                 yaz_log(YLOG_FATAL, "Can't repeat 'settings'");
286                 return 0;
287             }
288             if (!(r->settings = parse_settings(n)))
289                 return 0;
290         }
291         else if (!strcmp((const char *) n->name, "service"))
292         {
293             struct conf_service *s = parse_service(n);
294             if (!s)
295                 return 0;
296             r->service = s;
297         }
298         else
299         {
300             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
301             return 0;
302         }
303     }
304     return r;
305 }
306
307 static xsltStylesheet *load_stylesheet(const char *fname)
308 {
309     char path[256];
310     sprintf(path, "%s/%s", confdir, fname);
311     return xsltParseStylesheetFile((xmlChar *) path);
312 }
313
314 static void setup_marc(struct conf_retrievalprofile *r)
315 {
316     yaz_iconv_t cm;
317     r->yaz_marc = yaz_marc_create();
318     if (!(cm = yaz_iconv_open("utf-8", r->native_encoding)))
319     {
320         yaz_log(YLOG_WARN, "Unable to support mapping from %s", r->native_encoding);
321         return;
322     }
323     yaz_marc_iconv(r->yaz_marc, cm);
324 }
325
326 static struct conf_retrievalprofile *parse_retrievalprofile(xmlNode *node)
327 {
328     struct conf_retrievalprofile *r = nmem_malloc(nmem, sizeof(struct conf_retrievalprofile));
329     xmlNode *n;
330     struct conf_retrievalmap **rm = &r->maplist;
331
332     r->requestsyntax = 0;
333     r->native_syntax = Nativesyn_xml;
334     r->native_format = Nativeform_na;
335     r->native_encoding = 0;
336     r->native_mapto = Nativemapto_na;
337     r->yaz_marc = 0;
338     r->maplist = 0;
339     r->next = 0;
340
341     for (n = node->children; n; n = n->next)
342     {
343         if (n->type != XML_ELEMENT_NODE)
344             continue;
345         if (!strcmp((const char *) n->name, "requestsyntax"))
346         {
347             xmlChar *content = xmlNodeGetContent(n);
348             if (content)
349                 r->requestsyntax = nmem_strdup(nmem, (const char *) content);
350         }
351         else if (!strcmp((const char *) n->name, "nativesyntax"))
352         {
353             xmlChar *name = xmlGetProp(n, (xmlChar *) "name");
354             xmlChar *format = xmlGetProp(n, (xmlChar *) "format");
355             xmlChar *encoding = xmlGetProp(n, (xmlChar *) "encoding");
356             xmlChar *mapto = xmlGetProp(n, (xmlChar *) "mapto");
357             if (!name)
358             {
359                 yaz_log(YLOG_WARN, "Missing name in 'nativesyntax' element");
360                 return 0;
361             }
362             if (encoding)
363                 r->native_encoding = (char *) encoding;
364             if (!strcmp((const char *) name, "iso2709"))
365             {
366                 r->native_syntax = Nativesyn_iso2709;
367                 // Set a few defaults, too
368                 r->native_format = Nativeform_marc21;
369                 r->native_mapto = Nativemapto_marcxml;
370                 if (!r->native_encoding)
371                     r->native_encoding = "marc-8";
372                 setup_marc(r);
373             }
374             else if (!strcmp((const char *) name, "xml"))
375                 r->native_syntax = Nativesyn_xml;
376             else
377             {
378                 yaz_log(YLOG_WARN, "Unknown native syntax name %s", name);
379                 return 0;
380             }
381             if (format)
382             {
383                 if (!strcmp((const char *) format, "marc21") 
384                     || !strcmp((const char *) format, "usmarc"))
385                     r->native_format = Nativeform_marc21;
386                 else
387                 {
388                     yaz_log(YLOG_WARN, "Unknown native format name %s", format);
389                     return 0;
390                 }
391             }
392             if (mapto)
393             {
394                 if (!strcmp((const char *) mapto, "marcxml"))
395                     r->native_mapto = Nativemapto_marcxml;
396                 else if (!strcmp((const char *)mapto, "marcxchange"))
397                     r->native_mapto = Nativemapto_marcxchange;
398                 else
399                 {
400                     yaz_log(YLOG_WARN, "Unknown mapto target %s", format);
401                     return 0;
402                 }
403             }
404             xmlFree(name);
405             xmlFree(format);
406             xmlFree(encoding);
407             xmlFree(mapto);
408         }
409         else if (!strcmp((const char *) n->name, "map"))
410         {
411             struct conf_retrievalmap *m = nmem_malloc(nmem, sizeof(struct conf_retrievalmap));
412             xmlChar *type = xmlGetProp(n, (xmlChar *) "type");
413             xmlChar *charset = xmlGetProp(n, (xmlChar *) "charset");
414             xmlChar *format = xmlGetProp(n, (xmlChar *) "format");
415             xmlChar *stylesheet = xmlGetProp(n, (xmlChar *) "stylesheet");
416             memset(m, 0, sizeof(*m));
417             if (type)
418             {
419                 if (!strcmp((const char *) type, "xslt"))
420                     m->type = Map_xslt;
421                 else
422                 {
423                     yaz_log(YLOG_WARN, "Unknown map type: %s", type);
424                     return 0;
425                 }
426             }
427             if (charset)
428                 m->charset = nmem_strdup(nmem, (const char *) charset);
429             if (format)
430                 m->format = nmem_strdup(nmem, (const char *) format);
431             if (stylesheet)
432             {
433                 if (!(m->stylesheet = load_stylesheet((char *) stylesheet)))
434                     return 0;
435             }
436             *rm = m;
437             rm = &m->next;
438             xmlFree(type);
439             xmlFree(charset);
440             xmlFree(format);
441             xmlFree(stylesheet);
442         }
443         else
444         {
445             yaz_log(YLOG_FATAL, "Bad element in retrievalprofile: %s", n->name);
446             return 0;
447         }
448     }
449
450     return r;
451 }
452
453 static struct conf_targetprofiles *parse_targetprofiles(xmlNode *node)
454 {
455     struct conf_targetprofiles *r = nmem_malloc(nmem, sizeof(*r));
456     xmlChar *type = xmlGetProp(node, (xmlChar *) "type");
457     xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
458
459     memset(r, 0, sizeof(*r));
460
461     if (type)
462     {
463         if (!strcmp((const char *) type, "local"))
464             r->type = Targetprofiles_local;
465         else
466         {
467             yaz_log(YLOG_FATAL, "Unknown targetprofile type");
468             return 0;
469         }
470     }
471     else
472     {
473         yaz_log(YLOG_FATAL, "Must specify type for targetprofile");
474         return 0;
475     }
476
477     if (src)
478         r->src = nmem_strdup(nmem, (const char *) src);
479     else
480     {
481         yaz_log(YLOG_FATAL, "Must specify src in targetprofile");
482         return 0;
483     }
484     xmlFree(type);
485     xmlFree(src);
486     return r;
487 }
488
489 static struct conf_config *parse_config(xmlNode *root)
490 {
491     xmlNode *n;
492     struct conf_config *r = nmem_malloc(nmem, sizeof(struct conf_config));
493     struct conf_retrievalprofile **rp = &r->retrievalprofiles;
494
495     r->servers = 0;
496     r->retrievalprofiles = 0;
497     r->targetprofiles = 0;
498
499     for (n = root->children; n; n = n->next)
500     {
501         if (n->type != XML_ELEMENT_NODE)
502             continue;
503         if (!strcmp((const char *) n->name, "server"))
504         {
505             struct conf_server *tmp = parse_server(n);
506             if (!tmp)
507                 return 0;
508             tmp->next = r->servers;
509             r->servers = tmp;
510         }
511         else if (!strcmp((const char *) n->name, "retrievalprofile"))
512         {
513             if (!(*rp = parse_retrievalprofile(n)))
514                 return 0;
515             rp = &(*rp)->next;
516         }
517         else if (!strcmp((const char *) n->name, "targetprofiles"))
518         {
519             // It would be fun to be able to fix this sometime
520             if (r->targetprofiles)
521             {
522                 yaz_log(YLOG_FATAL, "Can't repeat targetprofiles");
523                 return 0;
524             }
525             if (!(r->targetprofiles = parse_targetprofiles(n)))
526                 return 0;
527         }
528         else
529         {
530             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
531             return 0;
532         }
533     }
534     return r;
535 }
536
537 int read_config(const char *fname)
538 {
539     xmlDoc *doc = xmlParseFile(fname);
540     const char *p;
541
542     if (!nmem)  // Initialize
543     {
544         nmem = nmem_create();
545         xmlSubstituteEntitiesDefault(1);
546         xmlLoadExtDtdDefaultValue = 1;
547     }
548     if (!doc)
549     {
550         yaz_log(YLOG_FATAL, "Failed to read %s", fname);
551         exit(1);
552     }
553     if ((p = strrchr(fname, '/')))
554     {
555         int len = p - fname;
556         strncpy(confdir, fname, len);
557         confdir[len] = '\0';
558     }
559     config = parse_config(xmlDocGetRootElement(doc));
560     xmlFreeDoc(doc);
561
562     if (config)
563         return 1;
564     else
565         return 0;
566 }
567
568
569 /*
570  * Local variables:
571  * c-basic-offset: 4
572  * indent-tabs-mode: nil
573  * End:
574  * vim: shiftwidth=4 tabstop=8 expandtab
575  */