-/*
- * Copyright (C) 1995-2007, Index Data ApS
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2010 Index Data
* See the file LICENSE for details.
- *
- * $Id: zoom-c.c,v 1.151 2007-09-21 16:04:48 adam Exp $
*/
/**
* \file zoom-c.c
#include <yaz/query-charset.h>
#include <yaz/copy_types.h>
#include <yaz/snprintf.h>
+#include <yaz/facet.h>
+
+#include <yaz/shptr.h>
+
+#if SHPTR
+YAZ_SHPTR_TYPE(WRBUF)
+#endif
static int log_api = 0;
static int log_details = 0;
static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out);
static char *cql2pqf(ZOOM_connection c, const char *cql);
+ZOOM_API(const char *) ZOOM_get_event_str(int event)
+{
+ static const char *ar[] = {
+ "NONE",
+ "CONNECT",
+ "SEND_DATA",
+ "RECV_DATA",
+ "TIMEOUT",
+ "UNKNOWN",
+ "SEND_APDU",
+ "RECV_APDU",
+ "RECV_RECORD",
+ "RECV_SEARCH",
+ "END"
+ };
+ return ar[event];
+}
/*
* This wrapper is just for logging failed lookups. It would be nicer
* if it could cause failure when a lookup fails, but that's hard.
*/
static Odr_oid *zoom_yaz_str_to_z3950oid(ZOOM_connection c,
- int oid_class, const char *str) {
+ oid_class oid_class, const char *str) {
Odr_oid *res = yaz_string_to_oid_odr(yaz_oid_std(), oid_class, str,
c->odr_out);
if (res == 0)
yaz_log(YLOG_LOG, "connect p=%p", task);
break;
case ZOOM_TASK_SCAN:
- yaz_log(YLOG_LOG, "scant p=%p", task);
+ yaz_log(YLOG_LOG, "scan p=%p", task);
break;
}
}
}
}
-static int ZOOM_connection_exec_task(ZOOM_connection c);
-
void ZOOM_connection_remove_tasks(ZOOM_connection c)
{
while (c->tasks)
c->odr_in = odr_createmem(ODR_DECODE);
c->odr_out = odr_createmem(ODR_ENCODE);
+ c->odr_print = 0;
c->async = 0;
c->support_named_resultsets = 0;
c->m_queue_back = 0;
c->sru_version = 0;
+ c->no_redirects = 0;
return c;
}
set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
ZOOM_connection_remove_tasks(c);
+ if (c->odr_print)
+ {
+ odr_setprint(c->odr_print, 0); /* prevent destroy from fclose'ing */
+ odr_destroy(c->odr_print);
+ }
+ if (ZOOM_options_get_bool(c->options, "apdulog", 0))
+ {
+ c->odr_print = odr_createmem(ODR_PRINT);
+ odr_setprint(c->odr_print, yaz_log_file());
+ }
+ else
+ c->odr_print = 0;
+
if (c->cs)
{
yaz_log(log_details, "%p ZOOM_connection_connect reconnect ok", c);
static zoom_ret do_write(ZOOM_connection c);
+ZOOM_API(void) ZOOM_resultset_release(ZOOM_resultset r)
+{
+#if ZOOM_RESULT_LISTS
+#else
+ if (r->connection)
+ {
+ /* remove ourselves from the resultsets in connection */
+ ZOOM_resultset *rp = &r->connection->resultsets;
+ while (1)
+ {
+ assert(*rp); /* we must be in this list!! */
+ if (*rp == r)
+ { /* OK, we're here - take us out of it */
+ *rp = (*rp)->next;
+ break;
+ }
+ rp = &(*rp)->next;
+ }
+ r->connection = 0;
+ }
+#endif
+}
+
ZOOM_API(void)
ZOOM_connection_destroy(ZOOM_connection c)
{
+#if ZOOM_RESULT_LISTS
+ ZOOM_resultsets list;
+#else
ZOOM_resultset r;
+#endif
if (!c)
return;
yaz_log(log_api, "%p ZOOM_connection_destroy", c);
if (c->cs)
cs_close(c->cs);
+
+#if ZOOM_RESULT_LISTS
+ // Remove the connection's usage of resultsets
+ list = c->resultsets;
+ while (list) {
+ ZOOM_resultsets removed = list;
+ ZOOM_resultset_destroy(list->resultset);
+ list = list->next;
+ xfree(removed);
+ }
+#else
for (r = c->resultsets; r; r = r->next)
r->connection = 0;
+#endif
xfree(c->buf_in);
xfree(c->addinfo);
xfree(c->diagset);
odr_destroy(c->odr_in);
odr_destroy(c->odr_out);
+ if (c->odr_print)
+ {
+ odr_setprint(c->odr_print, 0); /* prevent destroy from fclose'ing */
+ odr_destroy(c->odr_print);
+ }
ZOOM_options_destroy(c->options);
ZOOM_connection_remove_tasks(c);
ZOOM_connection_remove_events(c);
{
if (r)
{
+ yaz_mutex_enter(r->mutex);
(r->refcount)++;
yaz_log(log_details, "%p ZOOM_resultset_addref count=%d",
r, r->refcount);
+ yaz_mutex_leave(r->mutex);
}
}
r->r_sort_spec = 0;
r->query = 0;
r->connection = 0;
- r->next = 0;
r->databaseNames = 0;
r->num_databaseNames = 0;
+ r->facets = 0;
+ r->num_facets = 0;
+ r->facets_names = 0;
+ r->mutex = 0;
+ yaz_mutex_create(&r->mutex);
+#if SHPTR
+ {
+ WRBUF w = wrbuf_alloc();
+ YAZ_SHPTR_INIT(r->record_wrbuf, w);
+ }
+#endif
return r;
}
const char *cp;
int start, count;
const char *syntax, *elementSetName;
+#if ZOOM_RESULT_LISTS
+ ZOOM_resultsets set;
+#endif
yaz_log(log_api, "%p ZOOM_connection_search set %p query %p", c, r, q);
r->r_sort_spec = q->sort_spec;
r->connection = c;
+#if ZOOM_RESULT_LISTS
+ yaz_log(log_details, "%p ZOOM_connection_search: Adding new resultset (%p) to resultsets (%p) ", c, r, c->resultsets);
+ set = xmalloc(sizeof(*set));
+ ZOOM_resultset_addref(r);
+ set->resultset = r;
+ set->next = c->resultsets;
+ c->resultsets = set;
+#else
r->next = c->resultsets;
c->resultsets = r;
-
-
-
+#endif
if (c->host_port && c->proto == PROTO_HTTP)
{
if (!c->cs)
task->u.search.resultset = r;
task->u.search.start = start;
task->u.search.count = count;
+ task->u.search.recv_search_fired = 0;
syntax = ZOOM_options_get(r->options, "preferredRecordSyntax");
task->u.search.syntax = syntax ? xstrdup(syntax) : 0;
return 0;
}
+static void ZOOM_record_release(ZOOM_record rec)
+{
+ if (!rec)
+ return;
+
+#if SHPTR
+ if (rec->record_wrbuf)
+ YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
+#else
+ if (rec->wrbuf)
+ wrbuf_destroy(rec->wrbuf);
+#endif
+
+ if (rec->odr)
+ odr_destroy(rec->odr);
+}
+
ZOOM_API(void)
ZOOM_resultset_cache_reset(ZOOM_resultset r)
{
ZOOM_record_cache rc;
for (rc = r->record_hash[i]; rc; rc = rc->next)
{
- if (rc->rec.wrbuf_marc)
- wrbuf_destroy(rc->rec.wrbuf_marc);
- if (rc->rec.wrbuf_iconv)
- wrbuf_destroy(rc->rec.wrbuf_iconv);
- if (rc->rec.wrbuf_opac)
- wrbuf_destroy(rc->rec.wrbuf_opac);
+ ZOOM_record_release(&rc->rec);
}
r->record_hash[i] = 0;
}
{
if (!r)
return;
+ yaz_mutex_enter(r->mutex);
(r->refcount)--;
yaz_log(log_details, "%p ZOOM_resultset_destroy r=%p count=%d",
r, r, r->refcount);
if (r->refcount == 0)
{
- ZOOM_resultset_cache_reset(r);
+ yaz_mutex_leave(r->mutex);
- if (r->connection)
- {
- /* remove ourselves from the resultsets in connection */
- ZOOM_resultset *rp = &r->connection->resultsets;
- while (1)
- {
- assert(*rp); /* we must be in this list!! */
- if (*rp == r)
- { /* OK, we're here - take us out of it */
- *rp = (*rp)->next;
- break;
- }
- rp = &(*rp)->next;
- }
- }
+ yaz_log(log_details, "%p ZOOM_connection resultset_destroy: Deleting resultset (%p) ", r->connection, r);
+ ZOOM_resultset_cache_reset(r);
+ ZOOM_resultset_release(r);
ZOOM_query_destroy(r->query);
ZOOM_options_destroy(r->options);
odr_destroy(r->odr);
xfree(r->setname);
xfree(r->schema);
+ yaz_mutex_destroy(&r->mutex);
+#if SHPTR
+ YAZ_SHPTR_DEC(r->record_wrbuf, wrbuf_destroy);
+#endif
xfree(r);
}
+ else
+ yaz_mutex_leave(r->mutex);
}
ZOOM_API(size_t)
ZOOM_resultset_size(ZOOM_resultset r)
{
- yaz_log(log_details, "ZOOM_resultset_size r=%p count=%d",
+ yaz_log(log_details, "ZOOM_resultset_size r=%p count=" ODR_INT_PRINTF,
r, r->size);
return r->size;
}
}
}
+ZOOM_API(size_t)
+ ZOOM_resultset_facets_size(ZOOM_resultset r) {
+ return r->num_facets;
+}
+
+ZOOM_API(ZOOM_facet_field)
+ ZOOM_resultset_get_facet_field(ZOOM_resultset r, const char *name) {
+ int num = r->num_facets;
+ ZOOM_facet_field *facets = r->facets;
+ int index;
+ for (index = 0; index < num; index++) {
+ if (!strcmp(facets[index]->facet_name, name)) {
+ return facets[index];
+ }
+ }
+ return 0;
+}
+
+
+ZOOM_API(ZOOM_facet_field *)
+ ZOOM_resultset_facets(ZOOM_resultset r)
+{
+ return r->facets;
+}
+
+ZOOM_API(const char**)
+ ZOOM_resultset_facet_names(ZOOM_resultset r)
+{
+ return (const char **) r->facets_names;
+}
+
+ZOOM_API(const char*)
+ ZOOM_facet_field_name(ZOOM_facet_field field)
+{
+ return field->facet_name;
+}
+
+ZOOM_API(size_t)
+ ZOOM_facet_field_term_count(ZOOM_facet_field field)
+{
+ return field->num_terms;
+}
+
+ZOOM_API(const char*)
+ ZOOM_facet_field_get_term(ZOOM_facet_field field, size_t idx, int *freq) {
+ *freq = field->facet_terms[idx].frequency;
+ return field->facet_terms[idx].term;
+}
+
+
static void get_cert(ZOOM_connection c)
{
char *cert_buf;
}
}
+static zoom_ret do_connect_host(ZOOM_connection c,
+ const char *effective_host,
+ const char *logical_url);
+
static zoom_ret do_connect(ZOOM_connection c)
{
- void *add;
const char *effective_host;
if (c->proxy)
effective_host = c->proxy;
else
effective_host = c->host_port;
+ return do_connect_host(c, effective_host, c->host_port);
+}
+
+static zoom_ret do_connect_host(ZOOM_connection c, const char *effective_host,
+ const char *logical_url)
+{
+ void *add;
yaz_log(log_details, "%p do_connect effective_host=%s", c, effective_host);
if (c->cs && c->cs->protocol == PROTO_HTTP)
{
#if YAZ_HAVE_XML2
- const char *path = 0;
-
- c->proto = PROTO_HTTP;
- cs_get_host_args(c->host_port, &path);
- xfree(c->path);
- c->path = (char*) xmalloc(strlen(path)+2);
- c->path[0] = '/';
- strcpy(c->path+1, path);
+ if (logical_url)
+ {
+ const char *db = 0;
+
+ c->proto = PROTO_HTTP;
+ cs_get_host_args(logical_url, &db);
+ xfree(c->path);
+
+ c->path = xmalloc(strlen(db) * 3 + 2);
+ yaz_encode_sru_dbpath_buf(c->path, db);
+ }
#else
set_ZOOM_error(c, ZOOM_ERROR_UNSUPPORTED_PROTOCOL, "SRW");
do_close(c);
}
}
c->state = STATE_IDLE;
- set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
+ set_ZOOM_error(c, ZOOM_ERROR_CONNECT, logical_url);
return zoom_complete;
}
odr_reset(out);
return -1;
}
+ if (c->odr_print)
+ z_APDU(c->odr_print, &a, 0, 0);
yaz_log(log_details, "%p encoding_APDU encoding OK", c);
return 0;
}
Z_InitRequest *ireq = apdu->u.initRequest;
Z_IdAuthentication *auth = (Z_IdAuthentication *)
odr_malloc(c->odr_out, sizeof(*auth));
- char *version;
ODR_MASK_SET(ireq->options, Z_Options_search);
ODR_MASK_SET(ireq->options, Z_Options_present);
ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2);
ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3);
- /* Index Data's Z39.50 Implementor Id is 81 */
ireq->implementationId =
odr_prepend(c->odr_out,
ZOOM_options_get(c->options, "implementationId"),
- odr_prepend(c->odr_out, "81", ireq->implementationId));
+ ireq->implementationId);
ireq->implementationName =
odr_prepend(c->odr_out,
odr_prepend(c->odr_out, "ZOOM-C",
ireq->implementationName));
- version = odr_strdup(c->odr_out, "$Revision: 1.151 $");
- if (strlen(version) > 10) /* check for unexpanded CVS strings */
- version[strlen(version)-2] = '\0';
ireq->implementationVersion =
odr_prepend(c->odr_out,
ZOOM_options_get(c->options, "implementationVersion"),
- odr_prepend(c->odr_out, &version[11],
- ireq->implementationVersion));
+ ireq->implementationVersion);
*ireq->maximumRecordSize = c->maximum_record_size;
*ireq->preferredMessageSize = c->preferred_message_size;
{
Z_GDU *gdu;
ZOOM_Event event;
-
- gdu = z_get_HTTP_Request_host_path(c->odr_out, c->host_port, c->path);
+ const char *database = ZOOM_options_get(c->options, "databaseName");
+ char *fdatabase = 0;
+
+ if (database)
+ fdatabase = yaz_encode_sru_dbpath_odr(c->odr_out, database);
+ gdu = z_get_HTTP_Request_host_path(c->odr_out, c->host_port,
+ fdatabase ? fdatabase : c->path);
if (c->sru_mode == zoom_sru_get)
{
}
if (!z_GDU(c->odr_out, &gdu, 0, 0))
return zoom_complete;
+ if (c->odr_print)
+ z_GDU(c->odr_print, &gdu, 0, 0);
c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
event = ZOOM_Event_create(ZOOM_EVENT_SEND_APDU);
}
#endif
-
-static Z_SRW_PDU *ZOOM_srw_get_pdu(ZOOM_connection c, int type) {
+#if YAZ_HAVE_XML2
+static Z_SRW_PDU *ZOOM_srw_get_pdu(ZOOM_connection c, int type)
+{
Z_SRW_PDU *sr = yaz_srw_get_pdu(c->odr_out, type, c->sru_version);
sr->username = c->user;
sr->password = c->password;
return sr;
}
-
+#endif
#if YAZ_HAVE_XML2
static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
{
case ZOOM_TASK_SEARCH:
resultset = c->tasks->u.search.resultset;
- resultset->setname = xstrdup("default");
+ if (!resultset->setname)
+ resultset->setname = xstrdup("default");
ZOOM_options_set(resultset->options, "setname", resultset->setname);
start = &c->tasks->u.search.start;
count = &c->tasks->u.search.count;
start = &c->tasks->u.retrieve.start;
count = &c->tasks->u.retrieve.count;
-
+
if (*start >= resultset->size)
return zoom_complete;
if (*start + *count > resultset->size)
}
sr->u.request->startRecord = odr_intdup(c->odr_out, *start + 1);
sr->u.request->maximumRecords = odr_intdup(
- c->odr_out, resultset->step>0 ? resultset->step : *count);
+ c->odr_out, (resultset->step > 0 && resultset->step < *count) ?
+ resultset->step : *count);
sr->u.request->recordSchema = resultset->schema;
option_val = ZOOM_resultset_option_get(resultset, "recordPacking");
sr->u.request->recordPacking = odr_strdup(c->odr_out, option_val);
option_val = ZOOM_resultset_option_get(resultset, "extraArgs");
- if (option_val)
- sr->extra_args = odr_strdup(c->odr_out, option_val);
+ yaz_encode_sru_extra(sr, c->odr_out, option_val);
return send_srw(c, sr);
}
#else
const char *elementSetName;
const char *smallSetElementSetName;
const char *mediumSetElementSetName;
+ const char *facets;
assert(c->tasks);
assert(c->tasks->which == ZOOM_TASK_SEARCH);
if (!mediumSetElementSetName)
mediumSetElementSetName = elementSetName;
+ facets = ZOOM_options_get(r->options, "facets");
+ if (facets) {
+ Z_FacetList *facet_list = yaz_pqf_parse_facet_list(c->odr_out, facets);
+ if (facet_list) {
+ Z_OtherInformation **oi;
+ yaz_oi_APDU(apdu, &oi);
+ if (facet_list) {
+ yaz_oi_set_facetlist_oid(oi, c->odr_out, yaz_oid_userinfo_facet_1, 1, facet_list);
+ }
+ }
+ }
+
assert(r);
assert(r->query);
yaz_iconv_t cd = yaz_iconv_open(cp, "UTF-8");
if (cd)
{
+ int r;
search_req->query = yaz_copy_Z_Query(search_req->query,
c->odr_out);
- yaz_query_charset_convert_rpnquery(search_req->query->u.type_1,
- c->odr_out, cd);
+ r = yaz_query_charset_convert_rpnquery_check(
+ search_req->query->u.type_1,
+ c->odr_out, cd);
yaz_iconv_close(cd);
+ if (r)
+ { /* query could not be char converted */
+ set_ZOOM_error(c, ZOOM_ERROR_INVALID_QUERY, 0);
+ return zoom_complete;
+ }
}
}
}
result sets on the server. */
for (ord = 1; ; ord++)
{
+#if ZOOM_RESULT_LISTS
+ ZOOM_resultsets rsp;
+ sprintf(setname, "%d", ord);
+ for (rsp = c->resultsets; rsp; rsp = rsp->next)
+ if (rsp->resultset->setname && !strcmp(rsp->resultset->setname, setname))
+ break;
+ if (!rsp)
+ break;
+#else
ZOOM_resultset rp;
sprintf(setname, "%d", ord);
for (rp = c->resultsets; rp; rp = rp->next)
break;
if (!rp)
break;
+#endif
+
}
r->setname = xstrdup(setname);
yaz_log(log_details, "%p ZOOM_connection_send_search: allocating "
buf = odr_getbuf(odr_enc, &size, 0);
nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
+ yaz_log(log_details, "ZOOM_record create");
nrec->odr = odr_createmem(ODR_DECODE);
- nrec->wrbuf_marc = 0;
- nrec->wrbuf_iconv = 0;
- nrec->wrbuf_opac = 0;
+#if SHPTR
+ nrec->record_wrbuf = 0;
+#else
+ nrec->wrbuf = 0;
+#endif
odr_setbuf(nrec->odr, buf, size, 0);
z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
ZOOM_API(void)
ZOOM_record_destroy(ZOOM_record rec)
{
- if (!rec)
- return;
- if (rec->wrbuf_marc)
- wrbuf_destroy(rec->wrbuf_marc);
- if (rec->wrbuf_iconv)
- wrbuf_destroy(rec->wrbuf_iconv);
- if (rec->wrbuf_opac)
- wrbuf_destroy(rec->wrbuf_opac);
- odr_destroy(rec->odr);
+ ZOOM_record_release(rec);
+ yaz_log(log_details, "ZOOM_record destroy");
xfree(rec);
}
-static const char *marc_iconv_return(ZOOM_record rec, int marc_type,
- int *len,
- const char *buf, int sz,
- const char *record_charset)
+
+static yaz_iconv_t iconv_create_charset(const char *record_charset)
{
char to[40];
char from[40];
yaz_iconv_t cd = 0;
- yaz_marc_t mt = yaz_marc_create();
*from = '\0';
strcpy(to, "UTF-8");
{
/* Use "from,to" or just "from" */
const char *cp = strchr(record_charset, ',');
- int clen = strlen(record_charset);
+ size_t clen = strlen(record_charset);
if (cp && cp[1])
{
strncpy( to, cp+1, sizeof(to)-1);
strncpy(from, record_charset, clen);
from[clen] = '\0';
}
-
if (*from && *to)
- {
cd = yaz_iconv_open(to, from);
- yaz_marc_iconv(mt, cd);
- }
+ return cd;
+}
+static const char *return_marc_record(WRBUF wrbuf,
+ int marc_type,
+ int *len,
+ const char *buf, int sz,
+ const char *record_charset)
+{
+ yaz_iconv_t cd = iconv_create_charset(record_charset);
+ yaz_marc_t mt = yaz_marc_create();
+ const char *ret_string = 0;
+
+ if (cd)
+ yaz_marc_iconv(mt, cd);
yaz_marc_xml(mt, marc_type);
- if (!rec->wrbuf_marc)
- rec->wrbuf_marc = wrbuf_alloc();
- wrbuf_rewind(rec->wrbuf_marc);
- if (yaz_marc_decode_wrbuf(mt, buf, sz, rec->wrbuf_marc) > 0)
- {
- yaz_marc_destroy(mt);
- if (cd)
- yaz_iconv_close(cd);
+ if (yaz_marc_decode_wrbuf(mt, buf, sz, wrbuf) > 0)
+ {
if (len)
- *len = wrbuf_len(rec->wrbuf_marc);
- return wrbuf_cstr(rec->wrbuf_marc);
+ *len = wrbuf_len(wrbuf);
+ ret_string = wrbuf_cstr(wrbuf);
}
yaz_marc_destroy(mt);
if (cd)
yaz_iconv_close(cd);
- return 0;
+ return ret_string;
}
-static const char *record_iconv_return(ZOOM_record rec, int *len,
- const char *buf, int sz,
- const char *record_charset)
+static const char *return_opac_record(WRBUF wrbuf,
+ int marc_type,
+ int *len,
+ Z_OPACRecord *opac_rec,
+ const char *record_charset)
{
- char to[40];
- char from[40];
- yaz_iconv_t cd = 0;
+ yaz_iconv_t cd = iconv_create_charset(record_charset);
+ yaz_marc_t mt = yaz_marc_create();
- *from = '\0';
- strcpy(to, "UTF-8");
+ if (cd)
+ yaz_marc_iconv(mt, cd);
+ yaz_marc_xml(mt, marc_type);
- if (record_charset && *record_charset)
- {
- /* Use "from,to" or just "from" */
- const char *cp = strchr(record_charset, ',');
- int clen = strlen(record_charset);
- if (cp && cp[1])
- {
- strncpy( to, cp+1, sizeof(to)-1);
- to[sizeof(to)-1] = '\0';
- clen = cp - record_charset;
- }
- if (clen > sizeof(from)-1)
- clen = sizeof(from)-1;
-
- if (clen)
- strncpy(from, record_charset, clen);
- from[clen] = '\0';
- }
+ yaz_opac_decode_wrbuf(mt, opac_rec, wrbuf);
+ yaz_marc_destroy(mt);
- if (*from && *to && (cd = yaz_iconv_open(to, from)))
- {
- if (!rec->wrbuf_iconv)
- rec->wrbuf_iconv = wrbuf_alloc();
+ if (cd)
+ yaz_iconv_close(cd);
+ if (len)
+ *len = wrbuf_len(wrbuf);
+ return wrbuf_cstr(wrbuf);
+}
- wrbuf_rewind(rec->wrbuf_iconv);
+static const char *return_string_record(WRBUF wrbuf,
+ int *len,
+ const char *buf, int sz,
+ const char *record_charset)
+{
+ yaz_iconv_t cd = iconv_create_charset(record_charset);
- wrbuf_iconv_write(rec->wrbuf_iconv, cd, buf, sz);
- wrbuf_iconv_reset(rec->wrbuf_iconv, cd);
+ if (cd)
+ {
+ wrbuf_iconv_write(wrbuf, cd, buf, sz);
+ wrbuf_iconv_reset(wrbuf, cd);
- buf = wrbuf_cstr(rec->wrbuf_iconv);
- sz = wrbuf_len(rec->wrbuf_iconv);
+ buf = wrbuf_cstr(wrbuf);
+ sz = wrbuf_len(wrbuf);
yaz_iconv_close(cd);
}
if (len)
return buf;
}
+static const char *return_record_wrbuf(WRBUF wrbuf, int *len,
+ Z_NamePlusRecord *npr,
+ int marctype, const char *charset)
+{
+ Z_External *r = (Z_External *) npr->u.databaseRecord;
+ const Odr_oid *oid = r->direct_reference;
+ wrbuf_rewind(wrbuf);
+ /* render bibliographic record .. */
+ if (r->which == Z_External_OPAC)
+ {
+ return return_opac_record(wrbuf, marctype, len,
+ r->u.opac, charset);
+ }
+ if (r->which == Z_External_sutrs)
+ return return_string_record(wrbuf, len,
+ (char*) r->u.sutrs->buf,
+ r->u.sutrs->len,
+ charset);
+ else if (r->which == Z_External_octet)
+ {
+ if (yaz_oid_is_iso2709(oid))
+ {
+ const char *ret_buf = return_marc_record(
+ wrbuf, marctype, len,
+ (const char *) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len,
+ charset);
+ if (ret_buf)
+ return ret_buf;
+ /* bad ISO2709. Return fail unless raw (ISO2709) is wanted */
+ if (marctype != YAZ_MARC_ISO2709)
+ return 0;
+ }
+ return return_string_record(wrbuf, len,
+ (const char *) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len,
+ charset);
+ }
+ else if (r->which == Z_External_grs1)
+ {
+ yaz_display_grs1(wrbuf, r->u.grs1, 0);
+ return return_string_record(wrbuf, len,
+ wrbuf_buf(wrbuf),
+ wrbuf_len(wrbuf),
+ charset);
+ }
+ return 0;
+}
+
ZOOM_API(int)
ZOOM_record_error(ZOOM_record rec, const char **cp,
const char **addinfo, const char **diagset)
return 0;
}
-ZOOM_API(const char *)
- ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
+static const char *get_record_format(WRBUF wrbuf, int *len,
+ Z_NamePlusRecord *npr,
+ int marctype, const char *charset,
+ const char *format)
{
+ const char *res = return_record_wrbuf(wrbuf, len, npr, marctype, charset);
+#if YAZ_HAVE_XML2
+ if (*format == '1' && len)
+ {
+ /* try to XML format res */
+ xmlDocPtr doc;
+ xmlKeepBlanksDefault(0); /* get get xmlDocFormatMemory to work! */
+ doc = xmlParseMemory(res, *len);
+ if (doc)
+ {
+ xmlChar *xml_mem;
+ int xml_size;
+ xmlDocDumpFormatMemory(doc, &xml_mem, &xml_size, 1);
+ wrbuf_rewind(wrbuf);
+ wrbuf_write(wrbuf, (const char *) xml_mem, xml_size);
+ xmlFree(xml_mem);
+ xmlFreeDoc(doc);
+ res = wrbuf_cstr(wrbuf);
+ *len = wrbuf_len(wrbuf);
+ }
+ }
+#endif
+ return res;
+}
+
+
+static const char *npr_format(Z_NamePlusRecord *npr, const char *schema,
+ WRBUF wrbuf,
+ const char *type_spec, int *len)
+{
+ size_t i;
char type[40];
char charset[40];
- char xpath[512];
- const char *cp;
- int i;
- Z_NamePlusRecord *npr;
-
- if (len)
- *len = 0; /* default return */
-
- if (!rec)
- return 0;
- npr = rec->npr;
- if (!npr)
- return 0;
+ char format[3];
+ const char *cp = type_spec;
- cp = type_spec;
- for (i = 0; cp[i] && i < sizeof(type)-1; i++)
- {
- if (cp[i] == ';' || cp[i] == ' ')
- break;
+ for (i = 0; cp[i] && cp[i] != ';' && cp[i] != ' ' && i < sizeof(type)-1;
+ i++)
type[i] = cp[i];
- }
type[i] = '\0';
charset[0] = '\0';
- while (type_spec[i] == ';')
+ format[0] = '\0';
+ while (1)
{
+ while (cp[i] == ' ')
+ i++;
+ if (cp[i] != ';')
+ break;
i++;
- while (type_spec[i] == ' ')
+ while (cp[i] == ' ')
i++;
- if (!strncmp(type_spec+i, "charset=", 8))
+ if (!strncmp(cp + i, "charset=", 8))
{
- int j = 0;
+ size_t j = 0;
i = i + 8; /* skip charset= */
- for (j = 0; type_spec[i] && j < sizeof(charset)-1; i++, j++)
+ for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
{
- if (type_spec[i] == ';' || type_spec[i] == ' ')
- break;
- charset[j] = cp[i];
+ if (j < sizeof(charset)-1)
+ charset[j++] = cp[i];
}
charset[j] = '\0';
}
- else if (!strncmp(type_spec+i, "xpath=", 6))
+ else if (!strncmp(cp + i, "format=", 7))
{
- int j = 0;
- i = i + 6;
- for (j = 0; type_spec[i] && j < sizeof(xpath)-1; i++, j++)
- xpath[j] = cp[i];
- xpath[j] = '\0';
+ size_t j = 0;
+ i = i + 7;
+ for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
+ {
+ if (j < sizeof(format)-1)
+ format[j++] = cp[i];
+ }
+ format[j] = '\0';
}
- while (type_spec[i] == ' ')
- i++;
}
if (!strcmp(type, "database"))
{
else if (!strcmp(type, "schema"))
{
if (len)
- *len = rec->schema ? strlen(rec->schema) : 0;
- return rec->schema;
+ *len = schema ? strlen(schema) : 0;
+ return schema;
}
else if (!strcmp(type, "syntax"))
{
/* from now on - we have a database record .. */
if (!strcmp(type, "render"))
{
- Z_External *r = (Z_External *) npr->u.databaseRecord;
- const Odr_oid *oid = r->direct_reference;
-
- /* render bibliographic record .. */
- if (r->which == Z_External_OPAC)
- {
- r = r->u.opac->bibliographicRecord;
- if (!r)
- return 0;
- oid = r->direct_reference;
- }
- if (r->which == Z_External_sutrs)
- return record_iconv_return(rec, len,
- (char*) r->u.sutrs->buf,
- r->u.sutrs->len,
- charset);
- else if (r->which == Z_External_octet)
- {
- if (yaz_oid_is_iso2709(oid))
- {
- const char *ret_buf = marc_iconv_return(
- rec, YAZ_MARC_LINE, len,
- (const char *) r->u.octet_aligned->buf,
- r->u.octet_aligned->len,
- charset);
- if (ret_buf)
- return ret_buf;
- }
- return record_iconv_return(rec, len,
- (const char *) r->u.octet_aligned->buf,
- r->u.octet_aligned->len,
- charset);
- }
- else if (r->which == Z_External_grs1)
- {
- if (!rec->wrbuf_marc)
- rec->wrbuf_marc = wrbuf_alloc();
- wrbuf_rewind(rec->wrbuf_marc);
- yaz_display_grs1(rec->wrbuf_marc, r->u.grs1, 0);
- return record_iconv_return(rec, len,
- wrbuf_buf(rec->wrbuf_marc),
- wrbuf_len(rec->wrbuf_marc),
- charset);
- }
- return 0;
+ return get_record_format(wrbuf, len, npr, YAZ_MARC_LINE, charset, format);
}
else if (!strcmp(type, "xml"))
{
- Z_External *r = (Z_External *) npr->u.databaseRecord;
- const Odr_oid *oid = r->direct_reference;
-
- /* render bibliographic record .. */
- if (r->which == Z_External_OPAC)
- {
- r = r->u.opac->bibliographicRecord;
- if (!r)
- return 0;
- oid = r->direct_reference;
- }
-
- if (r->which == Z_External_sutrs)
- return record_iconv_return(rec, len,
- (const char *) r->u.sutrs->buf,
- r->u.sutrs->len,
- charset);
- else if (r->which == Z_External_octet)
- {
- int marc_decode_type = YAZ_MARC_MARCXML;
- if (yaz_oid_is_iso2709(oid))
- {
- const char *ret_buf = marc_iconv_return(
- rec, marc_decode_type, len,
- (const char *) r->u.octet_aligned->buf,
- r->u.octet_aligned->len,
- charset);
- if (ret_buf)
- return ret_buf;
- }
- return record_iconv_return(rec, len,
- (const char *) r->u.octet_aligned->buf,
- r->u.octet_aligned->len,
- charset);
- }
- else if (r->which == Z_External_grs1)
- {
- if (len) *len = 5;
- return "GRS-1";
- }
- return 0;
+ return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
+ format);
+ }
+ else if (!strcmp(type, "txml"))
+ {
+ return get_record_format(wrbuf, len, npr, YAZ_MARC_TURBOMARC, charset,
+ format);
}
else if (!strcmp(type, "raw"))
{
- Z_External *r = (Z_External *) npr->u.databaseRecord;
-
- if (r->which == Z_External_sutrs)
- {
- if (len) *len = r->u.sutrs->len;
- return (const char *) r->u.sutrs->buf;
- }
- else if (r->which == Z_External_octet)
- {
- if (len) *len = r->u.octet_aligned->len;
- return (const char *) r->u.octet_aligned->buf;
- }
- else /* grs-1, explain, OPAC, ... */
- {
- if (len) *len = -1;
- return (const char *) npr->u.databaseRecord;
- }
- return 0;
+ return get_record_format(wrbuf, len, npr, YAZ_MARC_ISO2709, charset,
+ format);
}
- else if (!strcmp (type, "ext"))
+ else if (!strcmp(type, "ext"))
{
if (len) *len = -1;
return (const char *) npr->u.databaseRecord;
}
- else if (!strcmp (type, "opac"))
-
+ else if (!strcmp(type, "opac"))
{
- Z_External *r = (Z_External *) npr->u.databaseRecord;
- if (r->which == Z_External_OPAC)
- {
- if (!rec->wrbuf_opac)
- rec->wrbuf_opac = wrbuf_alloc();
- wrbuf_rewind(rec->wrbuf_opac);
- yaz_display_OPAC(rec->wrbuf_opac, r->u.opac, 0);
- return record_iconv_return(rec, len,
- wrbuf_buf(rec->wrbuf_opac),
- wrbuf_len(rec->wrbuf_opac),
- charset);
- }
+ if (npr->u.databaseRecord->which == Z_External_OPAC)
+ return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
+ format);
}
return 0;
}
+ZOOM_API(const char *)
+ ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
+{
+ WRBUF wrbuf;
+
+ if (len)
+ *len = 0; /* default return */
+
+ if (!rec || !rec->npr)
+ return 0;
+
+#if SHPTR
+ if (!rec->record_wrbuf)
+ {
+ WRBUF w = wrbuf_alloc();
+ YAZ_SHPTR_INIT(rec->record_wrbuf, w);
+ }
+ wrbuf = rec->record_wrbuf->ptr;
+#else
+ if (!rec->wrbuf)
+ rec->wrbuf = wrbuf_alloc();
+ wrbuf = rec->wrbuf;
+#endif
+ return npr_format(rec->npr, rec->schema, wrbuf, type_spec, len);
+}
+
static int strcmp_null(const char *v1, const char *v2)
{
if (!v1 && !v2)
{
rc = (ZOOM_record_cache) odr_malloc(r->odr, sizeof(*rc));
rc->rec.odr = 0;
- rc->rec.wrbuf_marc = 0;
- rc->rec.wrbuf_iconv = 0;
- rc->rec.wrbuf_opac = 0;
+#if SHPTR
+ YAZ_SHPTR_INC(r->record_wrbuf);
+ rc->rec.record_wrbuf = r->record_wrbuf;
+#else
+ rc->rec.wrbuf = 0;
+#endif
rc->elementSetName = odr_strdup_null(r->odr, elementSetName);
rc->syntax = odr_strdup_null(r->odr, syntax);
{
/* present response and we didn't get any records! */
Z_NamePlusRecord *myrec =
- zget_surrogateDiagRec(resultset->odr, 0, 14, 0);
+ zget_surrogateDiagRec(
+ resultset->odr, 0,
+ YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
+ "ZOOM C generated. Present phase and no records");
record_cache_add(resultset, myrec, *start,
syntax, elementSetName, 0, 0);
}
{
/* present response and we didn't get any records! */
Z_NamePlusRecord *myrec =
- zget_surrogateDiagRec(resultset->odr, 0, 14, 0);
+ zget_surrogateDiagRec(
+ resultset->odr, 0,
+ YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS,
+ "ZOOM C generated: Present response and no records");
record_cache_add(resultset, myrec, *start, syntax, elementSetName,
0, 0);
}
}
}
-static void handle_searchResult(ZOOM_connection c, ZOOM_resultset resultset,
+static void handle_search_result(ZOOM_connection c, ZOOM_resultset resultset,
Z_OtherInformation *o)
{
int i;
}
}
+static char *get_term_cstr(ODR odr, Z_Term *term) {
+
+ switch (term->which) {
+ case Z_Term_general:
+ return odr_strdupn(odr, (const char *) term->u.general->buf, (size_t) term->u.general->len);
+ break;
+ case Z_Term_characterString:
+ return odr_strdup(odr, term->u.characterString);
+ }
+ return 0;
+}
+
+static ZOOM_facet_field get_zoom_facet_field(ODR odr, Z_FacetField *facet) {
+ int term_index;
+ struct yaz_facet_attr attr_values;
+ ZOOM_facet_field facet_field = odr_malloc(odr, sizeof(*facet_field));
+ yaz_facet_attr_init(&attr_values);
+ yaz_facet_attr_get_z_attributes(facet->attributes, &attr_values);
+ facet_field->facet_name = odr_strdup(odr, attr_values.useattr);
+ facet_field->num_terms = facet->num_terms;
+ yaz_log(YLOG_DEBUG, "ZOOM_facet_field %s %d terms %d", attr_values.useattr, attr_values.limit, facet->num_terms);
+ facet_field->facet_terms = odr_malloc(odr, facet_field->num_terms * sizeof(*facet_field->facet_terms));
+ for (term_index = 0 ; term_index < facet->num_terms; term_index++) {
+ Z_FacetTerm *facetTerm = facet->terms[term_index];
+ facet_field->facet_terms[term_index].frequency = *facetTerm->count;
+ facet_field->facet_terms[term_index].term = get_term_cstr(odr, facetTerm->term);
+ yaz_log(YLOG_DEBUG, " term[%d] %s %d",
+ term_index, facet_field->facet_terms[term_index].term, facet_field->facet_terms[term_index].frequency);
+ }
+ return facet_field;
+}
+
+static void handle_facet_result(ZOOM_connection c, ZOOM_resultset r,
+ Z_OtherInformation *o)
+{
+ int i;
+ for (i = 0; o && i < o->num_elements; i++)
+ {
+ if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo)
+ {
+ Z_External *ext = o->list[i]->information.externallyDefinedInfo;
+ if (ext->which == Z_External_userFacets)
+ {
+ int j;
+ Z_FacetList *fl = ext->u.facetList;
+ r->num_facets = fl->num;
+ yaz_log(YLOG_DEBUG, "Facets found: %d", fl->num);
+ r->facets = odr_malloc(r->odr, r->num_facets * sizeof(*r->facets));
+ r->facets_names = odr_malloc(r->odr, r->num_facets * sizeof(*r->facets_names));
+ for (j = 0; j < fl->num; j++)
+ {
+ r->facets[j] = get_zoom_facet_field(r->odr, fl->elements[j]);
+ if (!r->facets[j])
+ yaz_log(YLOG_DEBUG, "Facet field missing on index %d !", j);
+ r->facets_names[j] = (char *) ZOOM_facet_field_name(r->facets[j]);
+ }
+ }
+ }
+ }
+}
+
+
static void handle_search_response(ZOOM_connection c, Z_SearchResponse *sr)
{
ZOOM_resultset resultset;
ZOOM_options_set_int(resultset->options, "presentStatus",
*sr->presentStatus);
}
- handle_searchResult(c, resultset, sr->additionalSearchInfo);
+ handle_search_result(c, resultset, sr->additionalSearchInfo);
+
+ handle_facet_result(c, resultset, sr->additionalSearchInfo);
resultset->size = *sr->resultCount;
handle_records(c, sr->records, 0);
yaz_log(log_details, "%p send_present skip=%d", c, i);
*req->resultSetStartPoint = *start + 1;
- *req->numberOfRecordsRequested = resultset->step>0 ?
- resultset->step : *count;
+
+ if (resultset->step > 0 && resultset->step < *count)
+ *req->numberOfRecordsRequested = resultset->step;
+ else
+ *req->numberOfRecordsRequested = *count;
+
if (*req->numberOfRecordsRequested + *start > resultset->size)
*req->numberOfRecordsRequested = resultset->size - *start;
assert(*req->numberOfRecordsRequested > 0);
}
*req->numberOfTermsRequested =
- ZOOM_options_get_int(scan->options, "number", 10);
+ ZOOM_options_get_int(scan->options, "number", 20);
req->preferredPositionInResponse =
odr_intdup(c->odr_out,
c->odr_out, ZOOM_options_get_int(scan->options, "position", 1));
option_val = ZOOM_options_get(scan->options, "extraArgs");
- if (option_val)
- sr->extra_args = odr_strdup(c->odr_out, option_val);
+ yaz_encode_sru_extra(sr, c->odr_out, option_val);
return send_srw(c, sr);
}
#else
}
static void ZOOM_scanset_term_x(ZOOM_scanset scan, size_t pos,
- int *occ,
+ size_t *occ,
const char **value_term, size_t *value_len,
const char **disp_term, size_t *disp_len)
{
*disp_len = 0;
*occ = 0;
- if (pos >= noent || pos < 0)
+ if (pos >= noent)
return;
if (scan->scan_response)
{
ZOOM_API(const char *)
ZOOM_scanset_term(ZOOM_scanset scan, size_t pos,
- int *occ, int *len)
+ size_t *occ, size_t *len)
{
const char *value_term = 0;
size_t value_len = 0;
ZOOM_API(const char *)
ZOOM_scanset_display_term(ZOOM_scanset scan, size_t pos,
- int *occ, int *len)
+ size_t *occ, size_t *len)
{
const char *value_term = 0;
size_t value_len = 0;
{
Z_ItemOrder *req = (Z_ItemOrder *) odr_malloc(p->odr_out, sizeof(*req));
const char *str;
+ int len;
req->which = Z_IOItemOrder_esRequest;
req->u.esRequest = (Z_IORequest *)
req->u.esRequest->notToKeep->resultSetItem->resultSetId =
odr_strdup(p->odr_out, str);
req->u.esRequest->notToKeep->resultSetItem->item =
- (int *) odr_malloc(p->odr_out, sizeof(int));
+ odr_intdup(p->odr_out, 0);
str = ZOOM_options_get(p->options, "itemorder-item");
*req->u.esRequest->notToKeep->resultSetItem->item =
(str ? atoi(str) : 1);
}
- str = ZOOM_options_get(p->options, "doc");
+ str = ZOOM_options_getl(p->options, "doc", &len);
if (str)
{
req->u.esRequest->notToKeep->itemRequest =
- z_ext_record_xml(p->odr_out, str, strlen(str));
+ z_ext_record_xml(p->odr_out, str, len);
}
else
req->u.esRequest->notToKeep->itemRequest = encode_ill_request(p);
Z_APDU *apdu = create_es_package(p, yaz_oid_extserv_xml_es);
Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
Z_External *ext = (Z_External *) odr_malloc(p->odr_out, sizeof(*ext));
- const char *doc = ZOOM_options_get(p->options, "doc");
+ int len;
+ const char *doc = ZOOM_options_getl(p->options, "doc", &len);
if (!doc)
+ {
doc = "";
+ len = 0;
+ }
req->taskSpecificParameters = ext;
ext->direct_reference = req->packageType;
ext->which = Z_External_octet;
ext->u.single_ASN1_type =
- odr_create_Odr_oct(p->odr_out, (const unsigned char *) doc,
- strlen(doc));
+ odr_create_Odr_oct(p->odr_out, (const unsigned char *) doc, len);
return apdu;
}
int num_db;
char **db = set_DatabaseNames(p->connection, p->options, &num_db, p->odr_out);
const char *action = ZOOM_options_get(p->options, "action");
- const char *recordIdOpaque = ZOOM_options_get(p->options, "recordIdOpaque");
+ int recordIdOpaque_len;
+ const char *recordIdOpaque = ZOOM_options_getl(p->options, "recordIdOpaque",
+ &recordIdOpaque_len);
const char *recordIdNumber = ZOOM_options_get(p->options, "recordIdNumber");
- const char *record_buf = ZOOM_options_get(p->options, "record");
+ int record_len;
+ const char *record_buf = ZOOM_options_getl(p->options, "record",
+ &record_len);
+ int recordOpaque_len;
+ const char *recordOpaque_buf = ZOOM_options_getl(p->options, "recordOpaque",
+ &recordOpaque_len);
const char *syntax_str = ZOOM_options_get(p->options, "syntax");
const char *version = ZOOM_options_get(p->options, "updateVersion");
version = "3";
if (!syntax_str)
syntax_str = "xml";
- if (!record_buf)
+ if (!record_buf && !recordOpaque_buf)
{
record_buf = "void";
+ record_len = 4;
syntax_str = "SUTRS";
}
notToKeep->elements[0]->u.opaque =
odr_create_Odr_oct(p->odr_out,
(const unsigned char *) recordIdOpaque,
- strlen(recordIdOpaque));
+ recordIdOpaque_len);
}
else if (recordIdNumber)
{
{
Z_IUCorrelationInfo *ci;
ci = notToKeep->elements[0]->correlationInfo =
- odr_malloc(p->odr_out, sizeof(*ci));
+ (Z_IUCorrelationInfo *) odr_malloc(p->odr_out, sizeof(*ci));
ci->note = odr_strdup_null(p->odr_out, correlationInfo_note);
ci->id = correlationInfo_id ?
odr_intdup(p->odr_out, atoi(correlationInfo_id)) : 0;
}
else
notToKeep->elements[0]->correlationInfo = 0;
- notToKeep->elements[0]->record =
- z_ext_record_oid(p->odr_out, syntax_oid,
- record_buf, strlen(record_buf));
+ if (recordOpaque_buf)
+ {
+ notToKeep->elements[0]->record =
+ z_ext_record_oid_any(p->odr_out, syntax_oid,
+ recordOpaque_buf, recordOpaque_len);
+ }
+ else
+ {
+ notToKeep->elements[0]->record =
+ z_ext_record_oid(p->odr_out, syntax_oid,
+ record_buf, record_len);
+ }
}
if (0 && apdu)
{
return ZOOM_options_get(p->options, key);
}
+ZOOM_API(const char *)
+ ZOOM_package_option_getl(ZOOM_package p, const char *key, int *lenp)
+{
+ return ZOOM_options_getl(p->options, key, lenp);
+}
ZOOM_API(void)
ZOOM_package_option_set(ZOOM_package p, const char *key,
ZOOM_options_set(p->options, key, val);
}
-static int ZOOM_connection_exec_task(ZOOM_connection c)
+ZOOM_API(void)
+ ZOOM_package_option_setl(ZOOM_package p, const char *key,
+ const char *val, int len)
+{
+ ZOOM_options_setl(p->options, key, val, len);
+}
+
+ZOOM_API(int)
+ ZOOM_connection_exec_task(ZOOM_connection c)
{
ZOOM_task task = c->tasks;
zoom_ret ret = zoom_complete;
return r;
}
+static int es_response_taskpackage_update(ZOOM_connection c,
+ Z_IUUpdateTaskPackage *utp)
+{
+ if (utp && utp->targetPart)
+ {
+ Z_IUTargetPart *targetPart = utp->targetPart;
+ switch ( *targetPart->updateStatus ) {
+ case Z_IUTargetPart_success:
+ ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "success");
+ break;
+ case Z_IUTargetPart_partial:
+ ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "partial");
+ break;
+ case Z_IUTargetPart_failure:
+ ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "failure");
+ if (targetPart->globalDiagnostics && targetPart->num_globalDiagnostics > 0)
+ response_diag(c, targetPart->globalDiagnostics[0]);
+ break;
+ }
+ // NOTE: Individual record status, surrogate diagnostics, and supplemental diagnostics ARE NOT REPORTED.
+ }
+ return 1;
+}
+
+static int es_response_taskpackage(ZOOM_connection c,
+ Z_TaskPackage *taskPackage)
+{
+ // targetReference
+ Odr_oct *id = taskPackage->targetReference;
+ if (id)
+ ZOOM_options_setl(c->tasks->u.package->options,
+ "targetReference", (char*) id->buf, id->len);
+
+ // taskStatus
+ switch ( *taskPackage->taskStatus ) {
+ case Z_TaskPackage_pending:
+ ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "pending");
+ break;
+ case Z_TaskPackage_active:
+ ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "active");
+ break;
+ case Z_TaskPackage_complete:
+ ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "complete");
+ break;
+ case Z_TaskPackage_aborted:
+ ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "aborted");
+ if ( taskPackage->num_packageDiagnostics && taskPackage->packageDiagnostics )
+ response_diag(c, taskPackage->packageDiagnostics[0]);
+ break;
+ }
+
+ // taskSpecificParameters
+ // NOTE: Only Update implemented, no others.
+ if ( taskPackage->taskSpecificParameters->which == Z_External_update ) {
+ Z_IUUpdateTaskPackage *utp = taskPackage->taskSpecificParameters->u.update->u.taskPackage;
+ es_response_taskpackage_update(c, utp);
+ }
+ return 1;
+}
+
+
static int es_response(ZOOM_connection c,
Z_ExtendedServicesResponse *res)
{
if (!c->tasks || c->tasks->which != ZOOM_TASK_PACKAGE)
return 0;
- if (res->diagnostics && res->num_diagnostics > 0)
- response_diag(c, res->diagnostics[0]);
+ switch (*res->operationStatus) {
+ case Z_ExtendedServicesResponse_done:
+ ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "done");
+ break;
+ case Z_ExtendedServicesResponse_accepted:
+ ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "accepted");
+ break;
+ case Z_ExtendedServicesResponse_failure:
+ ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "failure");
+ if (res->diagnostics && res->num_diagnostics > 0)
+ response_diag(c, res->diagnostics[0]);
+ break;
+ }
if (res->taskPackage &&
res->taskPackage->which == Z_External_extendedService)
{
Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
- Odr_oct *id = taskPackage->targetReference;
-
- if (id)
- ZOOM_options_setl(c->tasks->u.package->options,
- "targetReference", (char*) id->buf, id->len);
+ es_response_taskpackage(c, taskPackage);
}
if (res->taskPackage &&
res->taskPackage->which == Z_External_octet)
}
#if YAZ_HAVE_XML2
-static void handle_srw_response(ZOOM_connection c,
- Z_SRW_searchRetrieveResponse *res)
+static zoom_ret handle_srw_response(ZOOM_connection c,
+ Z_SRW_searchRetrieveResponse *res)
{
ZOOM_resultset resultset = 0;
int i;
NMEM nmem;
ZOOM_Event event;
- int *start;
+ int *start, *count;
const char *syntax, *elementSetName;
if (!c->tasks)
- return;
+ return zoom_complete;
switch(c->tasks->which)
{
case ZOOM_TASK_SEARCH:
resultset = c->tasks->u.search.resultset;
start = &c->tasks->u.search.start;
+ count = &c->tasks->u.search.count;
syntax = c->tasks->u.search.syntax;
elementSetName = c->tasks->u.search.elementSetName;
+
+ if (!c->tasks->u.search.recv_search_fired)
+ {
+ event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
+ ZOOM_connection_put_event(c, event);
+ c->tasks->u.search.recv_search_fired = 1;
+ }
break;
case ZOOM_TASK_RETRIEVE:
resultset = c->tasks->u.retrieve.resultset;
start = &c->tasks->u.retrieve.start;
+ count = &c->tasks->u.retrieve.count;
syntax = c->tasks->u.retrieve.syntax;
elementSetName = c->tasks->u.retrieve.elementSetName;
break;
default:
- return;
+ return zoom_complete;
}
- event = ZOOM_Event_create(ZOOM_EVENT_RECV_SEARCH);
- ZOOM_connection_put_event(c, event);
resultset->size = 0;
ZOOM_resultset_option_set(resultset, "resultSetId", res->resultSetId);
yaz_log(log_details, "%p handle_srw_response got SRW response OK", c);
-
- if (res->numberOfRecords)
- resultset->size = *res->numberOfRecords;
- for (i = 0; i<res->num_records; i++)
+ if (res->num_diagnostics > 0)
{
- int pos;
- Z_SRW_record *sru_rec;
- Z_SRW_diagnostic *diag = 0;
- int num_diag;
-
- Z_NamePlusRecord *npr = (Z_NamePlusRecord *)
- odr_malloc(c->odr_in, sizeof(Z_NamePlusRecord));
-
- if (res->records[i].recordPosition &&
- *res->records[i].recordPosition > 0)
- pos = *res->records[i].recordPosition - 1;
- else
- pos = *start + i;
-
- sru_rec = &res->records[i];
-
- npr->databaseName = 0;
- npr->which = Z_NamePlusRecord_databaseRecord;
- npr->u.databaseRecord = (Z_External *)
- odr_malloc(c->odr_in, sizeof(Z_External));
- npr->u.databaseRecord->descriptor = 0;
- npr->u.databaseRecord->direct_reference =
- odr_oiddup(c->odr_in, yaz_oid_recsyn_xml);
- npr->u.databaseRecord->which = Z_External_octet;
-
- npr->u.databaseRecord->u.octet_aligned = (Odr_oct *)
- odr_malloc(c->odr_in, sizeof(Odr_oct));
- npr->u.databaseRecord->u.octet_aligned->buf = (unsigned char*)
- sru_rec->recordData_buf;
- npr->u.databaseRecord->u.octet_aligned->len =
- npr->u.databaseRecord->u.octet_aligned->size =
- sru_rec->recordData_len;
-
- if (sru_rec->recordSchema
- && !strcmp(sru_rec->recordSchema,
- "info:srw/schema/1/diagnostics-v1.1"))
+ set_SRU_error(c, &res->diagnostics[0]);
+ }
+ else
+ {
+ if (res->numberOfRecords)
+ resultset->size = *res->numberOfRecords;
+ for (i = 0; i<res->num_records; i++)
{
- sru_decode_surrogate_diagnostics(sru_rec->recordData_buf,
- sru_rec->recordData_len,
- &diag, &num_diag,
- resultset->odr);
+ int pos;
+ Z_SRW_record *sru_rec;
+ Z_SRW_diagnostic *diag = 0;
+ int num_diag;
+
+ Z_NamePlusRecord *npr = (Z_NamePlusRecord *)
+ odr_malloc(c->odr_in, sizeof(Z_NamePlusRecord));
+
+ if (res->records[i].recordPosition &&
+ *res->records[i].recordPosition > 0)
+ pos = *res->records[i].recordPosition - 1;
+ else
+ pos = *start + i;
+
+ sru_rec = &res->records[i];
+
+ npr->databaseName = 0;
+ npr->which = Z_NamePlusRecord_databaseRecord;
+ npr->u.databaseRecord = (Z_External *)
+ odr_malloc(c->odr_in, sizeof(Z_External));
+ npr->u.databaseRecord->descriptor = 0;
+ npr->u.databaseRecord->direct_reference =
+ odr_oiddup(c->odr_in, yaz_oid_recsyn_xml);
+ npr->u.databaseRecord->which = Z_External_octet;
+
+ npr->u.databaseRecord->u.octet_aligned = (Odr_oct *)
+ odr_malloc(c->odr_in, sizeof(Odr_oct));
+ npr->u.databaseRecord->u.octet_aligned->buf = (unsigned char*)
+ sru_rec->recordData_buf;
+ npr->u.databaseRecord->u.octet_aligned->len =
+ npr->u.databaseRecord->u.octet_aligned->size =
+ sru_rec->recordData_len;
+
+ if (sru_rec->recordSchema
+ && !strcmp(sru_rec->recordSchema,
+ "info:srw/schema/1/diagnostics-v1.1"))
+ {
+ sru_decode_surrogate_diagnostics(sru_rec->recordData_buf,
+ sru_rec->recordData_len,
+ &diag, &num_diag,
+ resultset->odr);
+ }
+ record_cache_add(resultset, npr, pos, syntax, elementSetName,
+ sru_rec->recordSchema, diag);
}
- record_cache_add(resultset, npr, pos, syntax, elementSetName,
- sru_rec->recordSchema, diag);
+ *count -= i;
+ *start += i;
+ if (*count + *start > resultset->size)
+ *count = resultset->size - *start;
+ if (*count < 0)
+ *count = 0;
+
+ nmem = odr_extract_mem(c->odr_in);
+ nmem_transfer(odr_getmem(resultset->odr), nmem);
+ nmem_destroy(nmem);
+
+ if (*count > 0)
+ return ZOOM_connection_srw_send_search(c);
}
- if (res->num_diagnostics > 0)
- set_SRU_error(c, &res->diagnostics[0]);
- nmem = odr_extract_mem(c->odr_in);
- nmem_transfer(odr_getmem(resultset->odr), nmem);
- nmem_destroy(nmem);
+ return zoom_complete;
}
#endif
#endif
#if YAZ_HAVE_XML2
+static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url)
+{
+ Z_GDU *p = z_get_HTTP_Request(odr);
+ const char *host = url;
+ const char *cp0 = strstr(host, "://");
+ const char *cp1 = 0;
+ if (cp0)
+ cp0 = cp0+3;
+ else
+ cp0 = host;
+
+ cp1 = strchr(cp0, '/');
+ if (!cp1)
+ cp1 = cp0 + strlen(cp0);
+
+ if (cp0 && cp1)
+ {
+ char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
+ memcpy (h, cp0, cp1 - cp0);
+ h[cp1-cp0] = '\0';
+ z_HTTP_header_add(odr, &p->u.HTTP_Request->headers, "Host", h);
+ }
+ p->u.HTTP_Request->path = odr_strdup(odr, *cp1 ? cp1 : "/");
+ return p;
+}
+
+static zoom_ret send_SRW_redirect(ZOOM_connection c, const char *uri,
+ Z_HTTP_Response *cookie_hres)
+{
+ struct Z_HTTP_Header *h;
+ Z_GDU *gdu = get_HTTP_Request_url(c->odr_out, uri);
+ char *combined_cookies;
+ int combined_cookies_len = 0;
+
+ gdu->u.HTTP_Request->method = odr_strdup(c->odr_out, "GET");
+ z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers, "Accept",
+ "text/xml");
+
+ for (h = cookie_hres->headers; h; h = h->next)
+ {
+ if (!strcmp(h->name, "Set-Cookie"))
+ {
+ char *cp;
+
+ if (!(cp = strchr(h->value, ';')))
+ cp = h->value + strlen(h->value);
+ if (cp - h->value >= 1) {
+ combined_cookies = xrealloc(combined_cookies, combined_cookies_len + cp - h->value + 3);
+ memcpy(combined_cookies+combined_cookies_len, h->value, cp - h->value);
+ combined_cookies[combined_cookies_len + cp - h->value] = '\0';
+ strcat(combined_cookies,"; ");
+ combined_cookies_len = strlen(combined_cookies);
+ }
+ }
+ }
+
+ if (combined_cookies_len)
+ {
+ z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
+ "Cookie", combined_cookies);
+ xfree(combined_cookies);
+ }
+
+ if (c->user && c->password)
+ {
+ z_HTTP_header_add_basic_auth(c->odr_out, &gdu->u.HTTP_Request->headers,
+ c->user, c->password);
+ }
+ if (!z_GDU(c->odr_out, &gdu, 0, 0))
+ return zoom_complete;
+ if (c->odr_print)
+ z_GDU(c->odr_print, &gdu, 0, 0);
+ c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
+
+ odr_reset(c->odr_out);
+ return do_write(c);
+}
+
static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
{
+ zoom_ret cret = zoom_complete;
int ret = -1;
const char *addinfo = 0;
const char *connection_head = z_HTTP_header_lookup(hres->headers,
"Connection");
+ const char *location;
+
ZOOM_connection_set_mask(c, 0);
yaz_log(log_details, "%p handle_http", c);
- if (!yaz_srw_check_content_type(hres))
- addinfo = "content-type";
- else
+ if ((hres->code == 301 || hres->code == 302) && c->sru_mode == zoom_sru_get
+ && (location = z_HTTP_header_lookup(hres->headers, "Location")))
{
- Z_SOAP *soap_package = 0;
- ODR o = c->odr_in;
- Z_SOAP_Handler soap_handlers[2] = {
- {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
- {0, 0, 0}
- };
- ret = z_soap_codec(o, &soap_package,
- &hres->content_buf, &hres->content_len,
- soap_handlers);
- if (!ret && soap_package->which == Z_SOAP_generic &&
- soap_package->u.generic->no == 0)
+ c->no_redirects++;
+ if (c->no_redirects > 10)
{
- Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p;
-
- ZOOM_options_set(c->options, "sru_version", sr->srw_version);
- if (sr->which == Z_SRW_searchRetrieve_response)
- handle_srw_response(c, sr->u.response);
- else if (sr->which == Z_SRW_scan_response)
- handle_srw_scan_response(c, sr->u.scan_response);
- else
- ret = -1;
+ set_HTTP_error(c, hres->code, 0, 0);
+ c->no_redirects = 0;
+ do_close(c);
}
- else if (!ret && (soap_package->which == Z_SOAP_fault
- || soap_package->which == Z_SOAP_error))
+ else
{
- set_HTTP_error(c, hres->code,
- soap_package->u.fault->fault_code,
- soap_package->u.fault->fault_string);
+ /* since redirect may change host we just reconnect. A smarter
+ implementation might check whether it's the same server */
+ do_connect_host(c, location, 0);
+ send_SRW_redirect(c, location, hres);
+ /* we're OK for now. Operation is not really complete */
+ ret = 0;
+ cret = zoom_pending;
}
+ }
+ else
+ { /* not redirect (normal response) */
+ if (!yaz_srw_check_content_type(hres))
+ addinfo = "content-type";
else
- ret = -1;
+ {
+ Z_SOAP *soap_package = 0;
+ ODR o = c->odr_in;
+ Z_SOAP_Handler soap_handlers[2] = {
+ {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
+ {0, 0, 0}
+ };
+ ret = z_soap_codec(o, &soap_package,
+ &hres->content_buf, &hres->content_len,
+ soap_handlers);
+ if (!ret && soap_package->which == Z_SOAP_generic &&
+ soap_package->u.generic->no == 0)
+ {
+ Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p;
+
+ ZOOM_options_set(c->options, "sru_version", sr->srw_version);
+ ZOOM_options_setl(c->options, "sru_extra_response_data",
+ sr->extraResponseData_buf, sr->extraResponseData_len);
+ if (sr->which == Z_SRW_searchRetrieve_response)
+ cret = handle_srw_response(c, sr->u.response);
+ else if (sr->which == Z_SRW_scan_response)
+ handle_srw_scan_response(c, sr->u.scan_response);
+ else
+ ret = -1;
+ }
+ else if (!ret && (soap_package->which == Z_SOAP_fault
+ || soap_package->which == Z_SOAP_error))
+ {
+ set_HTTP_error(c, hres->code,
+ soap_package->u.fault->fault_code,
+ soap_package->u.fault->fault_string);
+ }
+ else
+ ret = -1;
+ }
+ if (ret == 0)
+ {
+ if (c->no_redirects) /* end of redirect. change hosts again */
+ do_close(c);
+ }
+ c->no_redirects = 0;
}
if (ret)
{
set_ZOOM_error(c, ZOOM_ERROR_DECODE, addinfo);
do_close(c);
}
- ZOOM_connection_remove_task(c);
- if (!strcmp(hres->version, "1.0"))
+ if (cret == zoom_complete)
{
- /* HTTP 1.0: only if Keep-Alive we stay alive.. */
- if (!connection_head || strcmp(connection_head, "Keep-Alive"))
- do_close(c);
+ yaz_log(YLOG_LOG, "removing tasks in handle_http");
+ ZOOM_connection_remove_task(c);
}
- else
{
- /* HTTP 1.1: only if no close we stay alive .. */
- if (connection_head && !strcmp(connection_head, "close"))
+ int must_close = 0;
+ if (!strcmp(hres->version, "1.0"))
+ {
+ /* HTTP 1.0: only if Keep-Alive we stay alive.. */
+ if (!connection_head || strcmp(connection_head, "Keep-Alive"))
+ must_close = 1;
+ }
+ else
+ {
+ /* HTTP 1.1: only if no close we stay alive.. */
+ if (connection_head && !strcmp(connection_head, "close"))
+ must_close = 1;
+ }
+ if (must_close)
+ {
do_close(c);
+ if (c->tasks)
+ {
+ c->tasks->running = 0;
+ ZOOM_connection_insert_task(c, ZOOM_TASK_CONNECT);
+ c->reconnect_ok = 0;
+ }
+ }
}
}
#endif
}
do_close(c);
}
- else if (gdu->which == Z_GDU_Z3950)
- recv_apdu(c, gdu->u.z3950);
- else if (gdu->which == Z_GDU_HTTP_Response)
+ else
{
+ if (c->odr_print)
+ z_GDU(c->odr_print, &gdu, 0, 0);
+ if (gdu->which == Z_GDU_Z3950)
+ recv_apdu(c, gdu->u.z3950);
+ else if (gdu->which == Z_GDU_HTTP_Response)
+ {
#if YAZ_HAVE_XML2
- handle_http(c, gdu->u.HTTP_Response);
+ handle_http(c, gdu->u.HTTP_Response);
#else
- set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
- do_close(c);
+ set_ZOOM_error(c, ZOOM_ERROR_DECODE, 0);
+ do_close(c);
#endif
+ }
}
c->reconnect_ok = 0;
}
return ZOOM_options_get_int(c->options, "timeout", 30);
}
+ZOOM_API(void) ZOOM_connection_close(ZOOM_connection c)
+{
+ do_close(c);
+}
+
/*
* Local variables:
* c-basic-offset: 4
+ * c-file-style: "Stroustrup"
* indent-tabs-mode: nil
* End:
* vim: shiftwidth=4 tabstop=8 expandtab