Moved CCL Map, record syntax, charset normalization, record syntax normalization...
[pazpar2-moved-to-github.git] / src / pazpar2.c
index e8d0d8e..63966b1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pazpar2.c,v 1.53 2007-03-26 14:00:21 marc Exp $ */
+/* $Id: pazpar2.c,v 1.64 2007-04-08 20:52:09 quinn Exp $ */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -17,6 +17,7 @@
 #include <yaz/proto.h>
 #include <yaz/readconf.h>
 #include <yaz/pquery.h>
+#include <yaz/otherinfo.h>
 #include <yaz/yaz-util.h>
 #include <yaz/nmem.h>
 
@@ -39,6 +40,7 @@
 #include "relevance.h"
 #include "config.h"
 #include "database.h"
+#include "settings.h"
 
 #define MAX_CHUNK 15
 
@@ -48,6 +50,7 @@ static int client_prep_connection(struct client *cl);
 static void ingest_records(struct client *cl, Z_Records *r);
 //static struct conf_retrievalprofile *database_retrieval_profile(struct database *db);
 void session_alert_watch(struct session *s, int what);
+char *session_setting_oneval(struct session *s, struct database *db, int offset);
 
 IOCHAN channel_list = 0;  // Master list of connections we're handling events to
 
@@ -73,6 +76,7 @@ struct parameters global_parameters =
     "",
     "",
     "",
+    "",
     0,
     0,
     30,
@@ -84,8 +88,6 @@ struct parameters global_parameters =
     100,
     MAX_CHUNK,
     0,
-    0,
-    0,
     0
 };
 
@@ -158,6 +160,34 @@ static void send_init(IOCHAN i)
     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);
@@ -170,12 +200,24 @@ static void send_search(IOCHAN i)
     Z_Query *zquery;
     struct ccl_rpn_node *cn;
     int ssub = 0, lslb = 100000, mspn = 10;
+    char *recsyn;
+    char *piggyback;
 
     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;
@@ -188,12 +230,16 @@ static void send_search(IOCHAN i)
     for (ndb = 0; db->databases[ndb]; ndb++)
        databaselist[ndb] = db->databases[ndb];
 
-    a->u.searchRequest->preferredRecordSyntax =
-            yaz_oidval_to_z3950oid(global_parameters.odr_out,
-            CLASS_RECSYN, VAL_USMARC);
-    a->u.searchRequest->smallSetUpperBound = &ssub;
-    a->u.searchRequest->largeSetLowerBound = &lslb;
-    a->u.searchRequest->mediumSetPresentNumber = &mspn;
+    if (!(piggyback = session_setting_oneval(se, db, PZ_PIGGYBACK)) || *piggyback == '1')
+    {
+        if ((recsyn = session_setting_oneval(se, db, PZ_NATIVESYNTAX)))
+            a->u.searchRequest->preferredRecordSyntax =
+                    yaz_str_to_z3950oid(global_parameters.odr_out,
+                    CLASS_RECSYN, recsyn);
+        a->u.searchRequest->smallSetUpperBound = &ssub;
+        a->u.searchRequest->largeSetLowerBound = &lslb;
+        a->u.searchRequest->mediumSetPresentNumber = &mspn;
+    }
     a->u.searchRequest->resultSetName = "Default";
     a->u.searchRequest->databaseNames = databaselist;
     a->u.searchRequest->num_databaseNames = ndb;
@@ -214,9 +260,12 @@ static void send_present(IOCHAN i)
 {
     struct connection *co = iochan_getdata(i);
     struct client *cl = co->client; 
+    struct session *se = cl->session;
+    struct database *db = cl->database;
     Z_APDU *a = zget_APDU(global_parameters.odr_out, Z_APDU_presentRequest);
     int toget;
     int start = cl->records + 1;
+    char *recsyn;
 
     toget = global_parameters.chunk;
     if (toget > global_parameters.toget - cl->records)
@@ -231,9 +280,10 @@ static void send_present(IOCHAN i)
 
     a->u.presentRequest->resultSetId = "Default";
 
-    a->u.presentRequest->preferredRecordSyntax =
-            yaz_oidval_to_z3950oid(global_parameters.odr_out,
-            CLASS_RECSYN, VAL_USMARC);
+    if ((recsyn = session_setting_oneval(se, db, PZ_NATIVESYNTAX)))
+        a->u.presentRequest->preferredRecordSyntax =
+                yaz_str_to_z3950oid(global_parameters.odr_out,
+                CLASS_RECSYN, recsyn);
 
     if (send_apdu(cl, a) >= 0)
     {
@@ -251,7 +301,7 @@ static void do_initResponse(IOCHAN i, Z_APDU *a)
     struct client *cl = co->client;
     Z_InitResponse *r = a->u.initResponse;
 
-    yaz_log(YLOG_DEBUG, "Received init response");
+    yaz_log(YLOG_DEBUG, "Init response %s", cl->database->url);
 
     if (*r->result)
     {
@@ -268,7 +318,8 @@ static void do_searchResponse(IOCHAN i, Z_APDU *a)
     struct session *se = cl->session;
     Z_SearchResponse *r = a->u.searchResponse;
 
-    yaz_log(YLOG_DEBUG, "Searchresponse (status=%d)", *r->searchStatus);
+    yaz_log(YLOG_DEBUG, "Search response %s (status=%d)", 
+            cl->database->url, *r->searchStatus);
 
     if (*r->searchStatus)
     {
@@ -276,7 +327,8 @@ static void do_searchResponse(IOCHAN i, Z_APDU *a)
         se->total_hits += cl->hits;
         if (r->presentStatus && !*r->presentStatus && r->records)
         {
-            yaz_log(YLOG_DEBUG, "Records in search response");
+            yaz_log(YLOG_DEBUG, "Records in search response %s", 
+                    cl->database->url);
             ingest_records(cl, r->records);
         }
         cl->state = Client_Idle;
@@ -289,7 +341,9 @@ static void do_searchResponse(IOCHAN i, Z_APDU *a)
             Z_Records *recs = r->records;
             if (recs->which == Z_Records_NSD)
             {
-                yaz_log(YLOG_WARN, "Non-surrogate diagnostic");
+                yaz_log(YLOG_WARN, 
+                        "Search response: Non-surrogate diagnostic %s",
+                        cl->database->url);
                 cl->diagnostic = *recs->u.nonSurrogateDiagnostic->condition;
                 cl->state = Client_Error;
             }
@@ -297,6 +351,19 @@ static void do_searchResponse(IOCHAN i, Z_APDU *a)
     }
 }
 
+static void do_closeResponse(IOCHAN i, Z_APDU *a)
+{
+    struct connection *co = iochan_getdata(i);
+    struct client *cl = co->client;
+    /* Z_Close *r = a->u.close; */
+
+    yaz_log(YLOG_WARN, "Close response %s", cl->database->url);
+
+    cl->state = Client_Failed;
+    connection_destroy(co);
+}
+
+
 char *normalize_mergekey(char *buf, int skiparticle)
 {
     char *p = buf, *pout = buf;
@@ -338,42 +405,6 @@ char *normalize_mergekey(char *buf, int skiparticle)
     return buf;
 }
 
-
-#ifdef GAGA
-// FIXME needs to be generalized. Should flexibly generate X lists per search
-static void extract_subject(struct session *s, const char *rec)
-{
-    const char *field, *subfield;
-
-    while ((field = find_field(rec, "650")))
-    {
-        rec = field; 
-        if ((subfield = find_subfield(field, 'a')))
-        {
-            char *e, *ef;
-            char buf[1024];
-            int len;
-
-            ef = index(subfield, '\n');
-            if (!ef)
-                return;
-            if ((e = index(subfield, '\t')) && e < ef)
-                ef = e;
-            while (ef > subfield && !isalpha(*(ef - 1)) && *(ef - 1) != ')')
-                ef--;
-            len = ef - subfield;
-            assert(len < 1023);
-            memcpy(buf, subfield, len);
-            buf[len] = '\0';
-#ifdef FIXME
-            if (*buf)
-                termlist_insert(s->termlist, buf);
-#endif
-        }
-    }
-}
-#endif
-
 static void add_facet(struct session *s, const char *type, const char *value)
 {
     int i;
@@ -399,35 +430,38 @@ static void add_facet(struct session *s, const char *type, const char *value)
 
 static xmlDoc *normalize_record(struct client *cl, Z_External *rec)
 {
-    struct conf_retrievalprofile *rprofile = cl->database->rprofile;
-    struct conf_retrievalmap *m;
+    struct database_retrievalmap *m;
+    struct database *db = cl->database;
     xmlNode *res;
     xmlDoc *rdoc;
 
     // First normalize to XML
-    if (rprofile->native_syntax == Nativesyn_iso2709)
+    if (db->yaz_marc)
     {
         char *buf;
         int len;
         if (rec->which != Z_External_octet)
         {
-            yaz_log(YLOG_WARN, "Unexpected external branch, probably BER");
+            yaz_log(YLOG_WARN, "Unexpected external branch, probably BER %s",
+                    cl->database->url);
             return 0;
         }
         buf = (char*) rec->u.octet_aligned->buf;
         len = rec->u.octet_aligned->len;
-        if (yaz_marc_read_iso2709(rprofile->yaz_marc, buf, len) < 0)
+        if (yaz_marc_read_iso2709(db->yaz_marc, buf, len) < 0)
         {
-            yaz_log(YLOG_WARN, "Failed to decode MARC");
+            yaz_log(YLOG_WARN, "Failed to decode MARC %s",
+                    cl->database->url);
             return 0;
         }
-        if (yaz_marc_write_xml(rprofile->yaz_marc, &res,
+        if (yaz_marc_write_xml(db->yaz_marc, &res,
                     "http://www.loc.gov/MARC21/slim", 0, 0) < 0)
         {
-            yaz_log(YLOG_WARN, "Failed to encode as XML");
+            yaz_log(YLOG_WARN, "Failed to encode as XML %s",
+                    cl->database->url);
             return 0;
         }
-        rdoc = xmlNewDoc("1.0");
+        rdoc = xmlNewDoc((xmlChar *) "1.0");
         xmlDocSetRootElement(rdoc, res);
     }
     else
@@ -446,14 +480,9 @@ static xmlDoc *normalize_record(struct client *cl, Z_External *rec)
 #endif
     }
 
-    for (m = rprofile->maplist; m; m = m->next)
+    for (m = db->map; m; m = m->next)
     {
         xmlDoc *new;
-        if (m->type != Map_xslt)
-        {
-            yaz_log(YLOG_WARN, "Unknown map type");
-            return 0;
-        }
         if (!(new = xsltApplyStylesheet(m->stylesheet, rdoc, 0)))
         {
             yaz_log(YLOG_WARN, "XSLT transformation failed");
@@ -519,7 +548,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
         return 0;
 
     root = xmlDocGetRootElement(xdoc);
-    if (!(mergekey = xmlGetProp(root, "mergekey")))
+    if (!(mergekey = xmlGetProp(root, (xmlChar *) "mergekey")))
     {
         yaz_log(YLOG_WARN, "No mergekey found in record");
         xmlFreeDoc(xdoc);
@@ -533,11 +562,12 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
             sizeof(struct record_metadata*) * service->num_metadata);
     memset(res->metadata, 0, sizeof(struct record_metadata*) * service->num_metadata);
 
-    mergekey_norm = nmem_strdup(se->nmem, (char*) mergekey);
+    mergekey_norm = (xmlChar *) nmem_strdup(se->nmem, (char*) mergekey);
     xmlFree(mergekey);
-    normalize_mergekey(mergekey_norm, 0);
+    normalize_mergekey((char *) mergekey_norm, 0);
 
-    cluster = reclist_insert(se->reclist, res, mergekey_norm, &se->total_merged);
+    cluster = reclist_insert(se->reclist, res, (char *) mergekey_norm, 
+                             &se->total_merged);
     if (global_parameters.dump_records)
         yaz_log(YLOG_LOG, "Cluster id %d from %s (#%d)", cluster->recid,
                 cl->database->url, cl->records);
@@ -559,7 +589,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
 
         if (n->type != XML_ELEMENT_NODE)
             continue;
-        if (!strcmp(n->name, "metadata"))
+        if (!strcmp((const char *) n->name, "metadata"))
         {
             struct conf_metadata *md = 0;
             struct conf_sortkey *sk = 0;
@@ -567,7 +597,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
             int imeta;
             int first, last;
 
-            type = xmlGetProp(n, "type");
+            type = xmlGetProp(n, (xmlChar *) "type");
             value = xmlNodeListGetString(xdoc, n->children, 0);
 
             if (!type || !value)
@@ -575,7 +605,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
 
             // First, find out what field we're looking at
             for (imeta = 0; imeta < service->num_metadata; imeta++)
-                if (!strcmp(type, service->metadata[imeta].name))
+                if (!strcmp((const char *) type, service->metadata[imeta].name))
                 {
                     md = &service->metadata[imeta];
                     if (md->sortkey_offset >= 0)
@@ -600,7 +630,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
             if (md->type == Metadata_type_generic)
             {
                 char *p, *pe;
-                for (p = value; *p && isspace(*p); p++)
+                for (p = (char *) value; *p && isspace(*p); p++)
                     ;
                 for (pe = p + strlen(p) - 1;
                         pe > p && strchr(" ,/.:([", *pe); pe--)
@@ -610,7 +640,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
             }
             else if (md->type == Metadata_type_year)
             {
-                if (extract_years(value, &first, &last) < 0)
+                if (extract_years((char *) value, &first, &last) < 0)
                     continue;
             }
             else
@@ -627,7 +657,7 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
             {
                 struct record_metadata *mnode;
                 for (mnode = *wheretoput; mnode; mnode = mnode->next)
-                    if (!strcmp(mnode->data.text, newm->data.text))
+                    if (!strcmp((const char *) mnode->data.text, newm->data.text))
                         break;
                 if (!mnode)
                 {
@@ -688,22 +718,23 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
                 yaz_log(YLOG_WARN, "Don't know how to merge on element name %s", md->name);
 
             if (md->rank)
-                relevance_countwords(se->relevance, cluster, value, md->rank);
+                relevance_countwords(se->relevance, cluster, 
+                                     (char *) value, md->rank);
             if (md->termlist)
             {
                 if (md->type == Metadata_type_year)
                 {
                     char year[64];
                     sprintf(year, "%d", last);
-                    add_facet(se, type, year);
+                    add_facet(se, (char *) type, year);
                     if (first != last)
                     {
                         sprintf(year, "%d", first);
-                        add_facet(se, type, year);
+                        add_facet(se, (char *) type, year);
                     }
                 }
                 else
-                    add_facet(se, type, value);
+                    add_facet(se, (char *) type, (char *) value);
             }
             xmlFree(type);
             xmlFree(value);
@@ -725,6 +756,15 @@ static struct record *ingest_record(struct client *cl, Z_External *rec)
     return res;
 }
 
+// Retrieve first defined value for 'name' for given database.
+// Will be extended to take into account user associated with session
+char *session_setting_oneval(struct session *s, struct database *db, int offset)
+{
+    if (!db->settings[offset])
+        return 0;
+    return db->settings[offset]->value;
+}
+
 static void ingest_records(struct client *cl, Z_Records *r)
 {
 #if USE_TIMING
@@ -745,7 +785,9 @@ static void ingest_records(struct client *cl, Z_Records *r)
         cl->records++;
         if (npr->which != Z_NamePlusRecord_databaseRecord)
         {
-            yaz_log(YLOG_WARN, "Unexpected record type, probably diagnostic");
+            yaz_log(YLOG_WARN, 
+                    "Unexpected record type, probably diagnostic %s",
+                    cl->database->url);
             continue;
         }
 
@@ -775,7 +817,8 @@ static void do_presentResponse(IOCHAN i, Z_APDU *a)
         Z_Records *recs = r->records;
         if (recs->which == Z_Records_NSD)
         {
-            yaz_log(YLOG_WARN, "Non-surrogate diagnostic");
+            yaz_log(YLOG_WARN, "Non-surrogate diagnostic %s",
+                    cl->database->url);
             cl->diagnostic = *recs->u.nonSurrogateDiagnostic->condition;
             cl->state = Client_Error;
         }
@@ -783,13 +826,15 @@ static void do_presentResponse(IOCHAN i, Z_APDU *a)
 
     if (!*r->presentStatus && cl->state != Client_Error)
     {
-        yaz_log(YLOG_DEBUG, "Good Present response");
+        yaz_log(YLOG_DEBUG, "Good Present response %s",
+                cl->database->url);
         ingest_records(cl, r->records);
         cl->state = Client_Idle;
     }
     else if (*r->presentStatus) 
     {
-        yaz_log(YLOG_WARN, "Bad Present response");
+        yaz_log(YLOG_WARN, "Bad Present response %s",
+                cl->database->url);
         cl->state = Client_Error;
     }
 }
@@ -835,13 +880,14 @@ static void handler(IOCHAN i, int event)
 
        if (len < 0)
        {
-            yaz_log(YLOG_WARN|YLOG_ERRNO, "Error reading from Z server");
+            yaz_log(YLOG_WARN|YLOG_ERRNO, "Error reading from %s", 
+                    cl->database->url);
             connection_destroy(co);
            return;
        }
         else if (len == 0)
        {
-            yaz_log(YLOG_WARN, "EOF reading from Z server");
+            yaz_log(YLOG_WARN, "EOF reading from %s", cl->database->url);
             connection_destroy(co);
            return;
        }
@@ -871,8 +917,13 @@ static void handler(IOCHAN i, int event)
                     case Z_APDU_presentResponse:
                         do_presentResponse(i, a);
                         break;
+                    case Z_APDU_close:
+                        do_closeResponse(i, a);
+                        break;
                     default:
-                        yaz_log(YLOG_WARN, "Unexpected result from server");
+                        yaz_log(YLOG_WARN, 
+                                "Unexpected Z39.50 response from %s",  
+                                cl->database->url);
                         client_fatal(cl);
                         return;
                 }
@@ -980,9 +1031,6 @@ static struct connection *connection_create(struct client *cl)
         yaz_log(YLOG_DEBUG, "Connection create %s proxy %s", 
                 cl->database->url, global_parameters.zproxy_override);
 
-        yaz_log(YLOG_LOG, "Connection cs_create_host %s proxy %s", 
-                cl->database->url, global_parameters.zproxy_override);
-        
         if (!(addr = cs_straddr(link, global_parameters.zproxy_override)))
             {
                 yaz_log(YLOG_WARN|YLOG_ERRNO, 
@@ -1015,7 +1063,7 @@ static struct connection *connection_create(struct client *cl)
     cl->connection = new;
     new->link = link;
 
-    new->iochan = iochan_create(cs_fileno(link), handler, 0);
+    new->iochan = iochan_create(cs_fileno(link), 0, handler, 0);
     iochan_setdata(new->iochan, new);
     new->iochan->next = channel_list;
     channel_list = new->iochan;
@@ -1113,7 +1161,7 @@ void load_simpletargets(const char *fn)
 
         yaz_log(YLOG_LOG, "Target: %s, '%s'", url, db);
         for (host = hosts; host; host = host->next)
-            if (!strcmp(url, host->hostport))
+            if (!strcmp((const char *) url, host->hostport))
                 break;
         if (!host)
         {
@@ -1184,41 +1232,6 @@ void load_simpletargets(const char *fn)
 
 #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;
@@ -1373,12 +1386,11 @@ char *search(struct session *se, char *query, char *filter)
     }
     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;
     }
@@ -1449,7 +1461,7 @@ struct termlist_score **termlist(struct session *s, const char *name, int *num)
     int i;
 
     for (i = 0; i < s->num_termlists; i++)
-        if (!strcmp(s->termlists[i].name, name))
+        if (!strcmp((const char *) s->termlists[i].name, name))
             return termlist_highscore(s->termlists[i].termlist, num);
     return 0;
 }
@@ -1557,17 +1569,6 @@ void statistics(struct session *se, struct statistics *stat)
     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] = "";
@@ -1611,6 +1612,41 @@ static void start_proxy(void)
     http_set_proxyaddr(hp, ser->myurl ? ser->myurl : "");
 }
 
+static void start_zproxy(void)
+{
+    struct conf_server *ser = global_parameters.server;
+
+    if (*global_parameters.zproxy_override){
+        yaz_log(YLOG_LOG, "Z39.50 proxy  %s", 
+                global_parameters.zproxy_override);
+        return;
+    }
+
+    else if (ser->zproxy_host || ser->zproxy_port)
+    {
+        char hp[128] = "";
+
+        strcpy(hp, ser->zproxy_host ? ser->zproxy_host : "");
+        if (ser->zproxy_port)
+        {
+            if (*hp)
+                strcat(hp, ":");
+            else
+                strcat(hp, "@:");
+
+            sprintf(hp + strlen(hp), "%d", ser->zproxy_port);
+        }
+        strcpy(global_parameters.zproxy_override, hp);
+        yaz_log(YLOG_LOG, "Z39.50 proxy  %s", 
+                global_parameters.zproxy_override);
+
+    }
+    else
+        return;
+}
+
+
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -1621,7 +1657,7 @@ int main(int argc, char **argv)
 
     yaz_log_init(YLOG_DEFAULT_LEVEL, "pazpar2", 0);
 
-    while ((ret = options("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':
@@ -1631,15 +1667,15 @@ int main(int argc, char **argv)
             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;
             case 'z':
                 strcpy(global_parameters.zproxy_override, arg);
                 break;
+            case 't':
+                strcpy(global_parameters.settings_path_override, arg);
+                break;
             case 's':
                 load_simpletargets(arg);
                 break;
@@ -1668,10 +1704,15 @@ int main(int argc, char **argv)
 
     start_http_listener();
     start_proxy();
-    if (!global_parameters.ccl_filter)
-        global_parameters.ccl_filter = load_cclfile("../etc/default.bib");
-    global_parameters.yaz_marc = yaz_marc_create();
-    yaz_marc_subfield_str(global_parameters.yaz_marc, "\t");
+    start_zproxy();
+
+    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 well ensue!");
+    prepare_databases();
     global_parameters.odr_in = odr_createmem(ODR_DECODE);
     global_parameters.odr_out = odr_createmem(ODR_ENCODE);