--- /dev/null
+<settings target="*">
+
+ <!-- Default query mapping -->
+ <!-- Note, individual fields can be overriden per-database and/or per-user -->
+
+ <!-- mapping for unqualified search -->
+ <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/>
+
+ <set name="pz:cclmap:ti" value="u=4 s=al"/>
+ <set name="pz:cclmap:su" value="u=21 s=al"/>
+ <set name="pz:cclmap:isbn" value="u=7"/>
+ <set name="pz:cclmap:issn" value="u=8"/>
+ <set name="pz:cclmap:date" value="u=30 r=r"/>
+
+</settings>
-/* $Id: config.c,v 1.18 2007-03-27 11:25:57 marc Exp $ */
+/* $Id: config.c,v 1.19 2007-03-30 02:45:07 quinn Exp $ */
#include <string.h>
return r;
}
+static char *parse_settings(xmlNode *node)
+{
+ xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
+ char *r;
+
+ if (src)
+ r = nmem_strdup(nmem, (const char *) src);
+ else
+ {
+ yaz_log(YLOG_FATAL, "Must specify src in targetprofile");
+ return 0;
+ }
+ xmlFree(src);
+ return r;
+}
+
static struct conf_server *parse_server(xmlNode *node)
{
xmlNode *n;
r->zproxy_port = 0;
r->service = 0;
r->next = 0;
+ r->settings = 0;
for (n = node->children; n; n = n->next)
{
r->proxy_host = nmem_strdup(nmem, (const char *) host);
if (myurl)
r->myurl = nmem_strdup(nmem, (const char *) myurl);
+#ifdef GAGA
else
{
yaz_log(YLOG_FATAL, "Must specify @myurl for proxy");
return 0;
}
+#endif
xmlFree(port);
xmlFree(host);
xmlFree(myurl);
xmlFree(port);
xmlFree(host);
}
+ else if (!strcmp((const char *) n->name, "settings"))
+ {
+ if (r->settings)
+ {
+ yaz_log(YLOG_FATAL, "Can't repeat 'settings'");
+ return 0;
+ }
+ if (!(r->settings = parse_settings(n)))
+ return 0;
+ }
else if (!strcmp((const char *) n->name, "service"))
{
struct conf_service *s = parse_service(n);
struct conf_retrievalprofile **rp = &r->retrievalprofiles;
r->servers = 0;
- r->queryprofiles = 0;
r->retrievalprofiles = 0;
r->targetprofiles = 0;
tmp->next = r->servers;
r->servers = tmp;
}
- else if (!strcmp((const char *) n->name, "queryprofile"))
- {
- }
else if (!strcmp((const char *) n->name, "retrievalprofile"))
{
if (!(*rp = parse_retrievalprofile(n)))
char *myurl;
char *zproxy_host;
int zproxy_port;
+ char *settings;
struct conf_service *service;
struct conf_server *next;
};
-struct conf_queryprofile
-{
- int dummy;
-};
-
struct conf_retrievalmap
{
enum {
struct conf_config
{
struct conf_server *servers;
- struct conf_queryprofile *queryprofiles;
struct conf_targetprofiles *targetprofiles;
struct conf_retrievalprofile *retrievalprofiles;
};
-/* $Id: database.c,v 1.5 2007-03-29 13:44:38 quinn Exp $ */
+/* $Id: database.c,v 1.6 2007-03-30 02:45:07 quinn Exp $ */
#include <libxml/parser.h>
#include <libxml/tree.h>
static struct database *load_database(const char *id)
{
xmlDoc *doc = get_explain_xml(id);
- struct zr_explain *explain;
+ struct zr_explain *explain = 0;
struct conf_retrievalprofile *retrieval;
- struct conf_queryprofile *query;
struct database *db;
struct host *host;
char hostport[256];
if (!explain)
return 0;
}
- if (!(retrieval = database_retrievalprofile(id)) ||
- !(query = database_queryprofile(id)))
+ if (!(retrieval = database_retrievalprofile(id)))
{
xmlFree(doc);
return 0;
db->databases[1] = 0;
db->errors = 0;
db->explain = explain;
- db->qprofile = query;
db->rprofile = retrieval;
db->settings = 0;
db->next = databases;
+ db->ccl_map = 0;
databases = db;
return db;
/*
- * $Id: http.c,v 1.16 2007-03-29 15:23:17 quinn Exp $
+ * $Id: http.c,v 1.17 2007-03-30 02:45:07 quinn Exp $
*/
#include <stdio.h>
}
}
+#ifdef GAGA
// If this hostname contains our proxy host as a prefix, replace with myurl
static char *sub_hostname(struct http_channel *c, char *buf)
{
}
return buf;
}
+#endif
// Handles I/O on a client connection to a backend web server (proxy mode)
static void proxy_io(IOCHAN pi, int event)
-/* $Id: pazpar2.c,v 1.56 2007-03-28 12:05:18 marc Exp $ */
+/* $Id: pazpar2.c,v 1.57 2007-03-30 02:45:07 quinn Exp $ */
#include <stdlib.h>
#include <stdio.h>
MAX_CHUNK,
0,
0,
- 0,
0
};
odr_reset(global_parameters.odr_out);
}
+static void pull_terms(NMEM nmem, struct ccl_rpn_node *n, char **termlist, int *num)
+{
+ switch (n->kind)
+ {
+ case CCL_RPN_AND:
+ case CCL_RPN_OR:
+ case CCL_RPN_NOT:
+ case CCL_RPN_PROX:
+ pull_terms(nmem, n->u.p[0], termlist, num);
+ pull_terms(nmem, n->u.p[1], termlist, num);
+ break;
+ case CCL_RPN_TERM:
+ termlist[(*num)++] = nmem_strdup(nmem, n->u.t.term);
+ break;
+ default: // NOOP
+ break;
+ }
+}
+
+// Extract terms from query into null-terminated termlist
+static void extract_terms(NMEM nmem, struct ccl_rpn_node *query, char **termlist)
+{
+ int num = 0;
+
+ pull_terms(nmem, query, termlist, &num);
+ termlist[num] = 0;
+}
+
static void send_search(IOCHAN i)
{
struct connection *co = iochan_getdata(i);
yaz_log(YLOG_DEBUG, "Sending search");
- cn = ccl_find_str(global_parameters.ccl_filter, se->query, &cerror, &cpos);
+ cn = ccl_find_str(db->ccl_map, se->query, &cerror, &cpos);
if (!cn)
return;
+
+ if (!se->relevance)
+ {
+ // Initialize relevance structure with query terms
+ char *p[512];
+ extract_terms(se->nmem, cn, p);
+ se->relevance = relevance_create(se->nmem, (const char **) p,
+ se->expected_maxrecs);
+ }
+
a->u.searchRequest->query = zquery = odr_malloc(global_parameters.odr_out,
sizeof(Z_Query));
zquery->which = Z_Query_type_1;
#endif
-static void pull_terms(NMEM nmem, struct ccl_rpn_node *n, char **termlist, int *num)
-{
- switch (n->kind)
- {
- case CCL_RPN_AND:
- case CCL_RPN_OR:
- case CCL_RPN_NOT:
- case CCL_RPN_PROX:
- pull_terms(nmem, n->u.p[0], termlist, num);
- pull_terms(nmem, n->u.p[1], termlist, num);
- break;
- case CCL_RPN_TERM:
- termlist[(*num)++] = nmem_strdup(nmem, n->u.t.term);
- break;
- default: // NOOP
- break;
- }
-}
-
-// Extract terms from query into null-terminated termlist
-static int extract_terms(NMEM nmem, char *query, char **termlist)
-{
- int error, pos;
- struct ccl_rpn_node *n;
- int num = 0;
-
- n = ccl_find_str(global_parameters.ccl_filter, query, &error, &pos);
- if (!n)
- return -1;
- pull_terms(nmem, n, termlist, &num);
- termlist[num] = 0;
- ccl_rpn_delete(n);
- return 0;
-}
-
static struct client *client_create(void)
{
struct client *r;
}
if (live_channels)
{
- char *p[512];
int maxrecs = live_channels * global_parameters.toget;
se->num_termlists = 0;
se->reclist = reclist_create(se->nmem, maxrecs);
- extract_terms(se->nmem, query, p);
- se->relevance = relevance_create(se->nmem, (const char **) p, maxrecs);
+ // This will be initialized in send_search()
+ se->relevance = 0;
se->total_records = se->total_hits = se->total_merged = 0;
se->expected_maxrecs = maxrecs;
}
stat->num_clients = count;
}
-static CCL_bibset load_cclfile(const char *fn)
-{
- CCL_bibset res = ccl_qual_mk();
- if (ccl_qual_fname(res, fn) < 0)
- {
- yaz_log(YLOG_FATAL|YLOG_ERRNO, "%s", fn);
- exit(1);
- }
- return res;
-}
-
static void start_http_listener(void)
{
char hp[128] = "";
http_init(hp);
}
+// Initialize CCL map for a target
+// Note: This approach ignores user-specific CCL maps, for which I
+// don't presently see any application.
+static void prepare_cclmap(void *context, struct database *db)
+{
+ struct setting *s;
+
+ if (!db->settings)
+ return;
+ db->ccl_map = ccl_qual_mk();
+ for (s = db->settings[PZ_CCLMAP]; s; s = s->next)
+ if (!*s->user)
+ {
+ char *p = strchr(s->name + 3, ':');
+ if (!p)
+ {
+ yaz_log(YLOG_FATAL, "Malformed cclmap name: %s", s->name);
+ exit(1);
+ }
+ p++;
+ ccl_qual_fitem(db->ccl_map, s->value, p);
+ }
+}
+
+// Read settings for each database, and prepare a CCL map for that database
+static void prepare_cclmaps(void)
+{
+ grep_databases(0, 0, prepare_cclmap);
+}
+
static void start_proxy(void)
{
char hp[128] = "";
yaz_log_init(YLOG_DEFAULT_LEVEL, "pazpar2", 0);
- while ((ret = options("t:f:x:h:p:z:C:s:d", argv, argc, &arg)) != -2)
+ while ((ret = options("t:f:x:h:p:z:s:d", argv, argc, &arg)) != -2)
{
switch (ret) {
case 'f':
case 'h':
strcpy(global_parameters.listener_override, arg);
break;
- case 'C':
- global_parameters.ccl_filter = load_cclfile(arg);
- break;
case 'p':
strcpy(global_parameters.proxy_override, arg);
break;
strcpy(global_parameters.zproxy_override, arg);
break;
case 't':
- strcpy(global_parameters.settings_path, arg);
+ strcpy(global_parameters.settings_path_override, arg);
break;
case 's':
load_simpletargets(arg);
start_proxy();
start_zproxy();
- if (*global_parameters.settings_path)
- settings_read(global_parameters.settings_path);
- if (!global_parameters.ccl_filter)
- global_parameters.ccl_filter = load_cclfile("../etc/default.bib");
+ if (*global_parameters.settings_path_override)
+ settings_read(global_parameters.settings_path_override);
+ else if (global_parameters.server->settings)
+ settings_read(global_parameters.server->settings);
+ else
+ yaz_log(YLOG_WARN, "No settings-directory specified. Problems may ensue!");
+ prepare_cclmaps();
global_parameters.yaz_marc = yaz_marc_create();
yaz_marc_subfield_str(global_parameters.yaz_marc, "\t");
global_parameters.odr_in = odr_createmem(ODR_DECODE);
char **databases;
int errors;
struct zr_explain *explain;
- struct conf_queryprofile *qprofile;
struct conf_retrievalprofile *rprofile;
struct setting **settings;
struct database *next;
+ CCL_bibset ccl_map;
};
struct database_criterion_value {
char proxy_override[128];
char listener_override[128];
char zproxy_override[128];
- char settings_path[128];
+ char settings_path_override[128];
struct conf_server *server;
int dump_records;
int timeout; /* operations timeout, in seconds */
int session_timeout;
int toget;
int chunk;
- CCL_bibset ccl_filter;
yaz_marc_t yaz_marc;
ODR odr_out;
ODR odr_in;
-// $Id: settings.c,v 1.3 2007-03-29 13:44:19 quinn Exp $
+// $Id: settings.c,v 1.4 2007-03-30 02:45:07 quinn Exp $
// This module implements a generic system of settings (attribute-value) that can
// be associated with search targets. The system supports both default values,
// per-target overrides, and per-user settings.
-//
#include <string.h>
#include <stdio.h>
static char *hard_settings[] = {
"pz:piggyback",
"pz:elements",
- "pz::syntax",
+ "pz:syntax",
+ "pz:cclmap:",
0
};
return -1;
}
+// Ignores everything after second colon, if present
+// A bit of a hack to support the pz:cclmap: scheme (and more to come?)
+static int settings_offset_cprefix(const char *name)
+{
+ const char *p;
+ int maxlen = 100;
+ int i;
+
+ if (!strncmp("pz:", name, 3) && (p = strchr(name + 3, ':')))
+ maxlen = (p - name) + 1;
+ for (i = 0; i < dictionary->num; i++)
+ if (!strncmp(name, dictionary->dict[i], maxlen))
+ return i;
+ return -1;
+}
+
char *settings_name(int offset)
{
return dictionary->dict[offset];
static void prepare_dictionary(struct setting *set)
{
int i;
+ char *p;
+ if (!strncmp(set->name, "pz:", 3) && (p = strchr(set->name + 3, ':')))
+ *(p + 1) = '\0';
for (i = 0; i < dictionary->num; i++)
if (!strcmp(dictionary->dict[i], set->name))
return;
if (!db->settings)
{
db->settings = nmem_malloc(nmem, sizeof(struct settings*) * dictionary->num);
- memset(db->settings, sizeof(struct settings*) * dictionary->num, 0);
+ memset(db->settings, 0, sizeof(struct settings*) * dictionary->num);
}
- if ((offset = settings_offset(set->name)) < 0)
+ if ((offset = settings_offset_cprefix(set->name)) < 0)
abort(); // Should never get here
// First we determine if this setting is overriding any existing settings
// with the same name.
for (s = db->settings[offset], sp = &db->settings[offset]; s;
sp = &s->next, s = s->next)
- if (!strcmp(s->user, set->user))
+ if (!strcmp(s->user, set->user) && !strcmp(s->name, set->name))
{
if (s->precedence < set->precedence)
// We discard the value (nmem keeps track of the space)
{
struct setting *new = nmem_malloc(nmem, sizeof(*new));
- memset(new, sizeof(*new), 0);
+ memset(new, 0, sizeof(*new));
new->precedence = set->precedence;
new->target = nmem_strdup(nmem, set->target);
new->name = nmem_strdup(nmem, set->name);
else
nmem_reset(nmem);
new = nmem_malloc(nmem, sizeof(*new));
+ memset(new, 0, sizeof(*new));
initialize_hard_settings(new);
- memset(new, sizeof(*new), 0);
dictionary = new;
read_settings(path, prepare_dictionary);
read_settings(path, update_databases);
#define PZ_PIGGYBACK 0
#define PZ_ELEMENTS 1
#define PZ_SYNTAX 2
+#define PZ_CCLMAP 3
struct setting
{