Removed redundant xslt includes
[pazpar2-moved-to-github.git] / src / database.c
1 /* This file is part of Pazpar2.
2    Copyright (C) 2006-2009 Index Data
3
4 Pazpar2 is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include "pazpar2.h"
31 #include "host.h"
32 #include "settings.h"
33 #include "http.h"
34 #include "zeerex.h"
35
36 #include <sys/types.h>
37 #if HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 #if HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #if HAVE_NETINET_IN_H
44 #include <netinet/in.h>
45 #endif
46
47 static struct host *hosts = 0;  // The hosts we know about 
48 static struct database *databases = 0; // The databases we know about
49 static NMEM nmem = 0;
50
51 static xmlDoc *get_explain_xml(const char *id)
52 {
53     struct stat st;
54     char *dir;
55     char path[256];
56     char ide[256];
57     if (!config || !config->targetprofiles)
58     {
59         yaz_log(YLOG_WARN, "Config must be loaded and specify targetprofiles");
60         return 0;
61     }
62     if (config->targetprofiles->type != Targetprofiles_local)
63     {
64         yaz_log(YLOG_FATAL, "Only supports local type");
65         return 0;
66     }
67     dir = config->targetprofiles->src;
68     urlencode(id, ide);
69     sprintf(path, "%s/%s", dir, ide);
70     if (!stat(path, &st))
71         return xmlParseFile(path);
72     else
73         return 0;
74 }
75
76 // Create a new host structure for hostport
77 static struct host *create_host(const char *hostport)
78 {
79     struct host *host;
80
81     host = xmalloc(sizeof(struct host));
82     host->hostport = xstrdup(hostport);
83     host->connections = 0;
84     host->ipport = 0;
85
86     if (host_getaddrinfo(host))
87     {
88         xfree(host->hostport);
89         xfree(host);
90         return 0;
91     }
92     host->next = hosts;
93     hosts = host;
94     return host;
95 }
96
97 static struct host *find_host(const char *hostport)
98 {
99     struct host *p;
100     for (p = hosts; p; p = p->next)
101         if (!strcmp(p->hostport, hostport))
102             return p;
103     return create_host(hostport);
104 }
105
106 static struct database *load_database(const char *id)
107 {
108     xmlDoc *doc = 0;
109     struct zr_explain *explain = 0;
110     struct database *db;
111     struct host *host;
112     char hostport[256];
113     char *dbname;
114     struct setting *idset;
115
116     yaz_log(YLOG_LOG, "New database: %s", id);
117     if (!nmem)
118         nmem = nmem_create();
119
120     if (config && config->targetprofiles 
121         && (doc = get_explain_xml(id)))
122     {
123         explain = zr_read_xml(nmem, xmlDocGetRootElement(doc));
124         if (!explain)
125             return 0;
126     }
127
128     if (strlen(id) > 255)
129         return 0;
130     strcpy(hostport, id);
131     if ((dbname = strchr(hostport, '/')))
132         *(dbname++) = '\0';
133     else
134         dbname = "";
135     if (!(host = find_host(hostport)))
136         return 0;
137     db = nmem_malloc(nmem, sizeof(*db));
138     memset(db, 0, sizeof(*db));
139     db->host = host;
140     db->url = nmem_strdup(nmem, id);
141     db->databases = xmalloc(2 * sizeof(char *));
142     db->databases[0] = nmem_strdup(nmem, dbname);
143     db->databases[1] = 0;
144     db->errors = 0;
145     db->explain = explain;
146
147     db->settings = 0;
148
149     db->settings = nmem_malloc(nmem, sizeof(struct settings*) * settings_num());
150     memset(db->settings, 0, sizeof(struct settings*) * settings_num());
151     idset = nmem_malloc(nmem, sizeof(*idset));
152     idset->precedence = 0;
153     idset->name = "pz:id";
154     idset->target = idset->value = db->url;
155     idset->next = 0;
156     db->settings[PZ_ID] = idset;
157
158     db->next = databases;
159     databases = db;
160
161     return db;
162 }
163
164 // Return a database structure by ID. Load and add to list if necessary
165 // new==1 just means we know it's not in the list
166 struct database *find_database(const char *id, int new)
167 {
168     struct database *p;
169     if (!new)
170     {
171         for (p = databases; p; p = p->next)
172             if (!strcmp(p->url, id))
173                 return p;
174     }
175     return load_database(id);
176 }
177
178 // This whole session_grep database thing should be moved elsewhere
179
180 int match_zurl(const char *zurl, const char *pattern)
181 {
182     int len;
183
184     if (!strcmp(pattern, "*"))
185         return 1;
186     else if (!strncmp(pattern, "*/", 2))   // host wildcard.. what the heck is that for?
187     {
188         char *db = strchr(zurl, '/');
189         if (!db)
190             return 0;
191         if (!strcmp(pattern + 2, db))
192             return 1;
193         else
194             return 0;
195     }
196     else if (*(pattern + (len = strlen(pattern) - 1)) == '*')  // db wildcard
197     {
198         if (!strncmp(pattern, zurl, len))
199             return 1;
200         else
201             return 2;
202     }
203     else if (!strcmp(pattern, zurl))
204         return 1;
205     else
206         return 0;
207 }
208
209 // This will be generalized at some point
210 static int match_criterion(struct setting **settings, struct database_criterion *c)
211 {
212     int offset = settings_offset(c->name);
213     struct database_criterion_value *v;
214
215     if (offset < 0)
216     {
217         yaz_log(YLOG_WARN, "Criterion not found: %s", c->name);
218         return 0;
219     }
220     if (!settings[offset])
221         return 0;
222     for (v = c->values; v; v = v->next)
223     {
224         if (offset == PZ_ID)
225         {
226             if (match_zurl(settings[offset]->value, v->value))
227                 break;
228         }
229         else 
230         {
231             if (!strcmp(settings[offset]->value, v->value))
232                 break;
233         }
234     }
235     if (v)
236         return 1;
237     else
238         return 0;
239 }
240
241 int database_match_criteria(struct setting **settings, struct database_criterion *cl)
242 {
243     for (; cl; cl = cl->next)
244         if (!match_criterion(settings, cl))
245             break;
246     if (cl) // one of the criteria failed to match -- skip this db
247         return 0;
248     else
249         return 1;
250 }
251
252 // Cycles through databases, calling a handler function on the ones for
253 // which all criteria matched.
254 int session_grep_databases(struct session *se, struct database_criterion *cl,
255         void (*fun)(void *context, struct session_database *db))
256 {
257     struct session_database *p;
258     int i = 0;
259
260     for (p = se->databases; p; p = p->next)
261     {
262         if (p->settings && p->settings[PZ_ALLOW] && *p->settings[PZ_ALLOW]->value == '0')
263             continue;
264         if (!p->settings[PZ_NAME])
265             continue;
266         if (database_match_criteria(p->settings, cl))
267         {
268             (*fun)(se, p);
269             i++;
270         }
271     }
272     return i;
273 }
274
275 int predef_grep_databases(void *context, struct database_criterion *cl,
276                           void (*fun)(void *context, struct database *db))
277 {
278     struct database *p;
279     int i = 0;
280
281     for (p = databases; p; p = p->next)
282         if (database_match_criteria(p->settings, cl))
283         {
284             (*fun)(context, p);
285             i++;
286         }
287     return i;
288 }
289
290 /*
291  * Local variables:
292  * c-basic-offset: 4
293  * c-file-style: "Stroustrup"
294  * indent-tabs-mode: nil
295  * End:
296  * vim: shiftwidth=4 tabstop=8 expandtab
297  */
298