X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fzoom-c.c;h=b5241f303470af14bd7f4c2dee09547b40919c16;hp=6af917e464b3e293377165cfadc8970fd24dbc88;hb=8dc67a9430644549801c18ec7e3a725e5a4ef782;hpb=6e27325647596d80d9fcf1c9ad8f10be7004718a diff --git a/src/zoom-c.c b/src/zoom-c.c index 6af917e..b5241f3 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2003, Index Data + * Copyright (c) 2000-2004, Index Data * See the file LICENSE for details. * - * $Id: zoom-c.c,v 1.7 2003-11-25 23:18:08 adam Exp $ + * $Id: zoom-c.c,v 1.26 2004-04-06 17:47:24 adam Exp $ * * ZOOM layer for C, connections, result sets, queries. */ @@ -90,10 +90,18 @@ static void set_dset_error (ZOOM_connection c, int error, const char *dset, const char *addinfo, const char *addinfo2) { + char *cp; xfree (c->addinfo); c->addinfo = 0; c->error = error; - c->diagset = dset; + if (!c->diagset || strcmp(dset, c->diagset)) + { + xfree(c->diagset); + c->diagset = xstrdup(dset); + /* remove integer part from SRW diagset .. */ + if ((cp = strrchr(c->diagset, '/'))) + *cp = '\0'; + } if (addinfo && addinfo2) { c->addinfo = xmalloc(strlen(addinfo) + strlen(addinfo2) + 2); @@ -191,6 +199,10 @@ void ZOOM_connection_remove_task (ZOOM_connection c) case ZOOM_TASK_PACKAGE: ZOOM_package_destroy (task->u.package); break; + case ZOOM_TASK_SORT: + ZOOM_resultset_destroy (task->u.sort.resultset); + ZOOM_query_destroy(task->u.sort.q); + break; default: assert (0); } @@ -219,6 +231,7 @@ ZOOM_connection_create (ZOOM_options options) c->reconnect_ok = 0; c->state = STATE_IDLE; c->addinfo = 0; + c->diagset = 0; set_ZOOM_error(c, ZOOM_ERROR_NONE, 0); c->buf_in = 0; c->len_in = 0; @@ -422,7 +435,10 @@ ZOOM_query_prefix(ZOOM_query s, const char *str) s->z_query->which = Z_Query_type_1; s->z_query->u.type_1 = p_query_rpn(s->odr, PROTO_Z3950, str); if (!s->z_query->u.type_1) + { + s->z_query = 0; return -1; + } return 0; } @@ -471,6 +487,7 @@ ZOOM_connection_destroy(ZOOM_connection c) xfree (c->buf_in); xfree (c->addinfo); + xfree (c->diagset); odr_destroy (c->odr_in); odr_destroy (c->odr_out); ZOOM_options_destroy (c->options); @@ -495,6 +512,7 @@ void ZOOM_resultset_addref (ZOOM_resultset r) r, r->refcount); } } + ZOOM_resultset ZOOM_resultset_create () { ZOOM_resultset r = (ZOOM_resultset) xmalloc (sizeof(*r)); @@ -592,6 +610,62 @@ ZOOM_connection_search(ZOOM_connection c, ZOOM_query q) } ZOOM_API(void) + ZOOM_resultset_sort(ZOOM_resultset r, + const char *sort_type, const char *sort_spec) +{ + ZOOM_connection c = r->connection; + ZOOM_task task; + + if (!c) + return; + + if (c->host_port && c->proto == PROTO_HTTP) + { + if (!c->cs) + { + yaz_log(LOG_DEBUG, "NO COMSTACK"); + ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT); + } + else + { + yaz_log(LOG_DEBUG, "PREPARE FOR RECONNECT"); + c->reconnect_ok = 1; + } + } + + ZOOM_resultset_cache_reset(r); + task = ZOOM_connection_add_task (c, ZOOM_TASK_SORT); + task->u.sort.resultset = r; + task->u.sort.q = ZOOM_query_create(); + ZOOM_query_sortby(task->u.sort.q, sort_spec); + + ZOOM_resultset_addref (r); + + if (!c->async) + { + while (ZOOM_event (1, &c)) + ; + } +} + +ZOOM_API(void) + ZOOM_resultset_cache_reset(ZOOM_resultset r) +{ + ZOOM_record_cache rc; + + for (rc = r->record_cache; rc; rc = rc->next) + { + if (rc->rec.wrbuf_marc) + wrbuf_free (rc->rec.wrbuf_marc, 1); + if (rc->rec.wrbuf_iconv) + wrbuf_free (rc->rec.wrbuf_iconv, 1); + if (rc->rec.wrbuf_opac) + wrbuf_free (rc->rec.wrbuf_opac, 1); + } + r->record_cache = 0; +} + +ZOOM_API(void) ZOOM_resultset_destroy(ZOOM_resultset r) { if (!r) @@ -601,17 +675,8 @@ ZOOM_resultset_destroy(ZOOM_resultset r) r, r->refcount); if (r->refcount == 0) { - ZOOM_record_cache rc; + ZOOM_resultset_cache_reset(r); - for (rc = r->record_cache; rc; rc = rc->next) - { - if (rc->rec.wrbuf_marc) - wrbuf_free (rc->rec.wrbuf_marc, 1); - if (rc->rec.wrbuf_iconv) - wrbuf_free (rc->rec.wrbuf_iconv, 1); - if (rc->rec.wrbuf_opac) - wrbuf_free (rc->rec.wrbuf_opac, 1); - } if (r->connection) { /* remove ourselves from the resultsets in connection */ @@ -889,15 +954,19 @@ static zoom_ret send_APDU (ZOOM_connection c, Z_APDU *a) static zoom_ret ZOOM_connection_send_init (ZOOM_connection c) { - const char *impid, *impname, *impver; Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_initRequest); Z_InitRequest *ireq = apdu->u.initRequest; Z_IdAuthentication *auth = (Z_IdAuthentication *) odr_malloc(c->odr_out, sizeof(*auth)); const char *auth_groupId = ZOOM_options_get (c->options, "group"); const char *auth_userId = ZOOM_options_get (c->options, "user"); - const char *auth_password = ZOOM_options_get (c->options, "pass"); - + const char *auth_password = ZOOM_options_get (c->options, "password"); + char *version; + + /* support the pass for backwards compatibility */ + if (!auth_password) + auth_password = ZOOM_options_get (c->options, "pass"); + ODR_MASK_SET(ireq->options, Z_Options_search); ODR_MASK_SET(ireq->options, Z_Options_present); ODR_MASK_SET(ireq->options, Z_Options_scan); @@ -908,40 +977,22 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c) ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_1); ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2); ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3); - - impid = ZOOM_options_get (c->options, "implementationId"); - ireq->implementationId = - (char *) odr_malloc (c->odr_out, 15 + (impid ? strlen(impid) : 0)); - strcpy (ireq->implementationId, ""); - if (impid) - { - strcat (ireq->implementationId, impid); - strcat (ireq->implementationId, "/"); - } - strcat (ireq->implementationId, "81"); /* Index's implementor ID */ - - impname = ZOOM_options_get (c->options, "implementationName"); - ireq->implementationName = - (char *) odr_malloc (c->odr_out, 15 + (impname ? strlen(impname) : 0)); - strcpy (ireq->implementationName, ""); - if (impname) - { - strcat (ireq->implementationName, impname); - strcat (ireq->implementationName, "/"); - } - strcat (ireq->implementationName, "ZOOM-C/YAZ"); - - impver = ZOOM_options_get (c->options, "implementationVersion"); - ireq->implementationVersion = - (char *) odr_malloc (c->odr_out, strlen(YAZ_VERSION) + 2 + - (impver ? strlen(impver) : 0)); - strcpy (ireq->implementationVersion, ""); - if (impver) - { - strcat (ireq->implementationVersion, impver); - strcat (ireq->implementationVersion, "/"); - } - strcat (ireq->implementationVersion, YAZ_VERSION); + + /* 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->implementationName = odr_prepend(c->odr_out, + ZOOM_options_get(c->options, "implementationName"), + odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName)); + + version = odr_strdup(c->odr_out, "$Revision: 1.26 $"); + 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->maximumRecordSize = ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024); @@ -1022,7 +1073,7 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr) { char ctype[50]; Z_SOAP_Handler h[2] = { - {"http://www.loc.gov/zing/srw/v1.0/", 0, (Z_SOAP_fun) yaz_srw_codec}, + {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec}, {0, 0, 0} }; ODR o = odr_createmem(ODR_ENCODE); @@ -1206,6 +1257,11 @@ static zoom_ret ZOOM_connection_send_search (ZOOM_connection c) /* prepare query for the search request */ search_req->query = r->query->z_query; + if (!search_req->query) + { + set_ZOOM_error(c, ZOOM_ERROR_INVALID_QUERY, 0); + return zoom_complete; + } search_req->databaseNames = set_DatabaseNames (c, r->options, &search_req->num_databaseNames); @@ -1377,6 +1433,62 @@ ZOOM_record_destroy (ZOOM_record rec) 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) +{ + char to[40]; + char from[40]; + yaz_iconv_t cd = 0; + yaz_marc_t mt = yaz_marc_create(); + + *from = '\0'; + strcpy(to, "UTF-8"); + 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'; + } + + if (*from && *to) + { + cd = yaz_iconv_open(to, from); + 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 (len) + *len = wrbuf_len(rec->wrbuf_marc); + return wrbuf_buf(rec->wrbuf_marc); + } + yaz_marc_destroy(mt); + if (cd) + yaz_iconv_close(cd); + return 0; +} + static const char *record_iconv_return(ZOOM_record rec, int *len, const char *buf, int sz, const char *record_charset) @@ -1447,6 +1559,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) { char type[40]; char charset[40]; + char xpath[512]; const char *cp; int i; Z_NamePlusRecord *npr; @@ -1469,24 +1582,34 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) } type[i] = '\0'; charset[0] = '\0'; - if (type_spec[i] == ';') + while (type_spec[i] == ';') { i++; while (type_spec[i] == ' ') i++; if (!strncmp(type_spec+i, "charset=", 8)) { - cp = type_spec+i+8; - for (i = 0; cp[i] && i < sizeof(charset)-1; i++) + int j = 0; + i = i + 8; /* skip charset= */ + for (j = 0; type_spec[i] && j < sizeof(charset)-1; i++, j++) { - if (cp[i] == ';' || cp[i] == ' ') + if (type_spec[i] == ';' || type_spec[i] == ' ') break; - charset[i] = cp[i]; + charset[j] = cp[i]; } - charset[i] = '\0'; + charset[j] = '\0'; } - } - + else if (!strncmp(type_spec+i, "xpath=", 6)) + { + 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'; + } + while (type_spec[i] == ' ') + i++; + } if (!strcmp (type, "database")) { if (len) @@ -1532,7 +1655,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) charset); else if (r->which == Z_External_octet) { - yaz_marc_t mt; + const char *ret_buf; switch (ent->value) { case VAL_SOIF: @@ -1543,23 +1666,13 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) case VAL_APPLICATION_XML: break; default: - if (!rec->wrbuf_marc) - rec->wrbuf_marc = wrbuf_alloc(); - - mt = yaz_marc_create(); - wrbuf_rewind (rec->wrbuf_marc); - if (yaz_marc_decode_wrbuf ( - mt, (const char *) r->u.octet_aligned->buf, - r->u.octet_aligned->len, - rec->wrbuf_marc) > 0) - { - yaz_marc_destroy(mt); - return record_iconv_return(rec, len, - wrbuf_buf(rec->wrbuf_marc), - wrbuf_len(rec->wrbuf_marc), - charset); - } - yaz_marc_destroy(mt); + 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, @@ -1600,7 +1713,7 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) charset); else if (r->which == Z_External_octet) { - yaz_marc_t mt; + const char *ret_buf; int marc_decode_type = YAZ_MARC_MARCXML; if (!strcmp(type, "oai")) @@ -1615,24 +1728,13 @@ ZOOM_record_get (ZOOM_record rec, const char *type_spec, int *len) case VAL_APPLICATION_XML: break; default: - if (!rec->wrbuf_marc) - rec->wrbuf_marc = wrbuf_alloc(); - wrbuf_rewind (rec->wrbuf_marc); - mt = yaz_marc_create(); - - yaz_marc_xml(mt, YAZ_MARC_MARCXML); - if (yaz_marc_decode_wrbuf ( - mt, (const char *) r->u.octet_aligned->buf, - r->u.octet_aligned->len, - rec->wrbuf_marc) > 0) - { - yaz_marc_destroy(mt); - return record_iconv_return(rec, len, - wrbuf_buf(rec->wrbuf_marc), - wrbuf_len(rec->wrbuf_marc), - charset); - } - yaz_marc_destroy(mt); + 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, @@ -1901,20 +2003,11 @@ static int scan_response (ZOOM_connection c, Z_ScanResponse *res) return 1; } -static zoom_ret send_sort (ZOOM_connection c) +static zoom_ret send_sort (ZOOM_connection c, + ZOOM_resultset resultset) { - ZOOM_resultset resultset; - - if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH) - return zoom_complete; - - resultset = c->tasks->u.search.resultset; - if (c->error) - { resultset->r_sort_spec = 0; - return zoom_complete; - } if (resultset->r_sort_spec) { Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_sortRequest); @@ -2194,7 +2287,7 @@ ZOOM_scanset_display_term (ZOOM_scanset scan, size_t pos, if (t->displayTerm) { - term = (const char *) t->term->u.general->buf; + term = t->displayTerm; *len = strlen(term); } else if (t->term->which == Z_Term_general) @@ -2423,7 +2516,8 @@ static Z_APDU *create_update_package(ZOOM_package p) int num_db; char **db = set_DatabaseNames(p->connection, p->options, &num_db); const char *action = ZOOM_options_get(p->options, "action"); - const char *recordId = ZOOM_options_get(p->options, "recordId"); + const char *recordIdOpaque = ZOOM_options_get(p->options, "recordIdOpaque"); + const char *recordIdNumber = ZOOM_options_get(p->options, "recordIdNumber"); const char *record_buf = ZOOM_options_get(p->options, "record"); const char *syntax_str = ZOOM_options_get(p->options, "syntax"); int syntax_oid = VAL_NONE; @@ -2499,14 +2593,21 @@ static Z_APDU *create_update_package(ZOOM_package p) notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *) odr_malloc(p->odr_out, sizeof(**notToKeep->elements)); notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque; - if (recordId) + if (recordIdOpaque) { notToKeep->elements[0]->u.opaque = (Odr_oct *) odr_malloc (p->odr_out, sizeof(Odr_oct)); - notToKeep->elements[0]->u.opaque->size = strlen(recordId); - notToKeep->elements[0]->u.opaque->len = strlen(recordId); + notToKeep->elements[0]->u.opaque->size = + notToKeep->elements[0]->u.opaque->len = strlen(recordIdOpaque); notToKeep->elements[0]->u.opaque->buf = - odr_strdup(p->odr_out, recordId); + odr_strdup(p->odr_out, recordIdOpaque); + } + else if (recordIdNumber) + { + notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_number; + + notToKeep->elements[0]->u.number = + odr_intdup(p->odr_out, atoi(recordIdNumber)); } else notToKeep->elements[0]->u.opaque = 0; @@ -2684,6 +2785,11 @@ static int ZOOM_connection_exec_task (ZOOM_connection c) break; case ZOOM_TASK_PACKAGE: ret = send_package(c); + break; + case ZOOM_TASK_SORT: + c->tasks->u.sort.resultset->r_sort_spec = + c->tasks->u.sort.q->sort_spec; + ret = send_sort(c, c->tasks->u.sort.resultset); break; } } @@ -2704,7 +2810,10 @@ static int ZOOM_connection_exec_task (ZOOM_connection c) static zoom_ret send_sort_present (ZOOM_connection c) { - zoom_ret r = send_sort (c); + zoom_ret r = zoom_complete; + + if (c->tasks && c->tasks->which == ZOOM_TASK_SEARCH) + r = send_sort (c, c->tasks->u.search.resultset); if (r == zoom_complete) r = send_present (c); return r; @@ -2911,8 +3020,16 @@ static void handle_srw_response(ZOOM_connection c, } if (res->num_diagnostics > 0) { - set_dset_error(c, *res->diagnostics[0].code, "SRW", - res->diagnostics[0].details, 0); + const char *uri = res->diagnostics[0].uri; + if (uri) + { + int code = 0; + const char *cp; + if ((cp = strrchr(uri, '/'))) + code = atoi(cp+1); + set_dset_error(c, code, uri, + res->diagnostics[0].details, 0); + } } nmem = odr_extract_mem(c->odr_in); nmem_transfer(resultset->odr->mem, nmem); @@ -2934,9 +3051,9 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres) if (content_type && !yaz_strcmp_del("text/xml", content_type, "; ")) { Z_SOAP *soap_package = 0; - ODR o = odr_createmem(ODR_DECODE); + ODR o = c->odr_in; Z_SOAP_Handler soap_handlers[2] = { - {"http://www.loc.gov/zing/srw/v1.0/", 0, + {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec}, {0, 0, 0} }; @@ -2961,7 +3078,6 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres) } else ret = -1; - odr_destroy(o); } if (ret) { @@ -3179,6 +3295,8 @@ ZOOM_diag_str (int error) return "Unsupported protocol"; case ZOOM_ERROR_UNSUPPORTED_QUERY: return "Unsupported query type"; + case ZOOM_ERROR_INVALID_QUERY: + return "Invalid query"; default: return diagbib1_str (error); } @@ -3197,7 +3315,7 @@ ZOOM_connection_error_x (ZOOM_connection c, const char **cp, *cp = z_HTTP_errmsg(c->error); else if (!strcmp(c->diagset, "Bib-1")) *cp = ZOOM_diag_str(error); - else if (!strcmp(c->diagset, "SRW")) + else if (!strcmp(c->diagset, "info:srw/diagnostic/1")) *cp = yaz_diag_srw_str(c->error); else *cp = "Unknown error and diagnostic set";