X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fzoom-c.c;h=7131b41ab9dc4cfd76c263988bd7b34702c64531;hp=1c67d1d70fb52df9f81a19a3566710c00c48d1a3;hb=4d35e2e6ab9c8d544292cbd94a574dec6694cf9a;hpb=72009188eda06296bb8839ef16de1470ecc2d240 diff --git a/src/zoom-c.c b/src/zoom-c.c index 1c67d1d..7131b41 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -2,7 +2,7 @@ * Copyright (C) 1995-2005, Index Data ApS * See the file LICENSE for details. * - * $Id: zoom-c.c,v 1.53 2005-12-07 16:15:15 mike Exp $ + * $Id: zoom-c.c,v 1.58 2005-12-20 22:24:05 mike Exp $ */ /** * \file zoom-c.c @@ -11,6 +11,7 @@ #include #include +#include #include "zoom-p.h" #include @@ -23,6 +24,7 @@ #include #include #include +#include #if HAVE_SYS_TYPES_H #include @@ -50,6 +52,8 @@ typedef enum { static zoom_ret ZOOM_connection_send_init (ZOOM_connection c); static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out); +static char *cql2pqf(ZOOM_connection c, const char *cql); + static void initlog() { @@ -388,22 +392,35 @@ ZOOM_connection_connect(ZOOM_connection c, else c->host_port = xstrdup(host); - if ((val = strchr(c->host_port, '%')) != 0) { - /* We recognise :% for embedded - * authentication. This is slightly hacky syntax, but it's - * hard to get into the comstack code in a - * protocol-independent way. + { + /* + * If the ":" part of the host string is preceded by one + * or more comma-separated = pairs, these are taken + * to be options to be set on the connection object. Among other + * applications, this facility can be used to embed authentication + * in a host string: + * user=admin,password=secret,tcp:localhost:9999 */ - *(char*)val = '\0'; - char *remainder = xstrdup(val+1); - char *pass = strchr(c->host_port, ':'); - if (pass != 0) { - *pass++ = '\0'; - ZOOM_connection_option_set(c, "user", c->host_port); - ZOOM_connection_option_set(c, "password", pass); + char *remainder = c->host_port; + char *pcolon = strchr(remainder, ':'); + char *pcomma; + char *pequals; + while ((pcomma = strchr(remainder, ',')) != 0 && + (pcolon == 0 || pcomma < pcolon)) { + *pcomma = '\0'; + if ((pequals = strchr(remainder, '=')) != 0) { + *pequals = '\0'; + /*printf("# setting '%s'='%s'\n", remainder, pequals+1);*/ + ZOOM_connection_option_set(c, remainder, pequals+1); + } + remainder = pcomma+1; + } + + if (remainder != c->host_port) { + xfree(c->host_port); + c->host_port = xstrdup(remainder); + /*printf("# reset hp='%s'\n", remainder);*/ } - xfree(c->host_port); - c->host_port = remainder; } ZOOM_options_set(c->options, "host", c->host_port); @@ -941,7 +958,7 @@ static zoom_ret do_connect (ZOOM_connection c) } } c->state = STATE_IDLE; - set_ZOOM_error(c, ZOOM_ERROR_CONNECT, effective_host); + set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port); return zoom_complete; } @@ -1081,7 +1098,7 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c) ZOOM_options_get(c->options, "implementationName"), odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName)); - version = odr_strdup(c->odr_out, "$Revision: 1.53 $"); + version = odr_strdup(c->odr_out, "$Revision: 1.58 $"); if (strlen(version) > 10) /* check for unexpanded CVS strings */ version[strlen(version)-2] = '\0'; ireq->implementationVersion = odr_prepend(c->odr_out, @@ -2071,7 +2088,8 @@ static void handle_queryExpressionTerm(ZOOM_options opt, const char *name, { case Z_Term_general: ZOOM_options_setl(opt, name, - term->u.general->buf, term->u.general->len); + (const char *)(term->u.general->buf), + term->u.general->len); break; case Z_Term_characterString: ZOOM_options_set(opt, name, term->u.characterString); @@ -2384,7 +2402,23 @@ static zoom_ret send_present(ZOOM_connection c) ZOOM_API(ZOOM_scanset) ZOOM_connection_scan (ZOOM_connection c, const char *start) { + ZOOM_scanset s; + ZOOM_query q = ZOOM_query_create(); + + ZOOM_query_prefix (q, start); + + s = ZOOM_connection_scan1(c, q); + ZOOM_query_destroy (q); + return s; + +} + +ZOOM_API(ZOOM_scanset) +ZOOM_connection_scan1 (ZOOM_connection c, ZOOM_query q) +{ ZOOM_scanset scan = (ZOOM_scanset) xmalloc (sizeof(*scan)); + char *start; + char *freeme = 0; scan->connection = c; scan->odr = odr_createmem (ODR_DECODE); @@ -2392,9 +2426,34 @@ ZOOM_connection_scan (ZOOM_connection c, const char *start) scan->refcount = 1; scan->scan_response = 0; - if ((scan->termListAndStartPoint = - p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, - start))) + /* + * We need to check the query-type, so we can recognise CQL and + * compile it into a form that we can use here. The ZOOM_query + * structure has no explicit `type' member, but inspection of the + * ZOOM_query_prefix() and ZOOM_query_cql() functions shows how + * the structure is set up in each case. + */ + + if (q->z_query->which == Z_Query_type_1) { + yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p PQF '%s'", + c, q, q->query_string); + start = q->query_string; + } else if (q->z_query->which == Z_Query_type_104) { + yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p CQL '%s'", + c, q, q->query_string); + start = freeme = cql2pqf(c, q->query_string); + if (start == 0) + return 0; + } else { + yaz_log(YLOG_FATAL, "%p ZOOM_connection_scan1 q=%p unknown type '%s'", + c, q, q->query_string); + abort(); + } + + scan->termListAndStartPoint = + p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, start); + xfree (freeme); + if (scan->termListAndStartPoint != 0) { ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_SCAN); task->u.scan.scan = scan; @@ -3273,7 +3332,7 @@ static void recv_apdu (ZOOM_connection c, Z_APDU *apdu) } else { - set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port); do_close(c); } break; @@ -3453,7 +3512,7 @@ static int do_read (ZOOM_connection c) } else { - set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port); do_close (c); } } @@ -3516,9 +3575,9 @@ static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out) return zoom_pending; } if (c->state == STATE_CONNECTING) - set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port); else - set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port); do_close (c); return zoom_complete; } @@ -3646,6 +3705,10 @@ ZOOM_diag_str (int error) return "Unsupported query type"; case ZOOM_ERROR_INVALID_QUERY: return "Invalid query"; + case ZOOM_ERROR_CQL_PARSE: + return "CQL parsing error"; + case ZOOM_ERROR_CQL_TRANSFORM: + return "CQL transformation error"; default: return diagbib1_str (error); } @@ -3693,7 +3756,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask) if (r == CS_NONE) { event = ZOOM_Event_create (ZOOM_EVENT_CONNECT); - set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port); do_close (c); ZOOM_connection_put_event (c, event); } @@ -3732,7 +3795,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask) } else { - set_ZOOM_error(c, ZOOM_ERROR_CONNECT, 0); + set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port); do_close (c); ZOOM_connection_put_event (c, event); } @@ -3939,6 +4002,74 @@ ZOOM_event (int no, ZOOM_connection *cs) } return 0; } + + +/* + * Returns an xmalloc()d string containing RPN that corresponds to the + * CQL passed in. On error, sets the Connection object's error state + * and returns a null pointer. + * ### We could cache CQL parser and/or transformer in Connection. + */ +static char *cql2pqf(ZOOM_connection c, const char *cql) +{ + CQL_parser parser; + int error; + struct cql_node *node; + const char *cqlfile; + static cql_transform_t trans; + char pqfbuf[512]; + + parser = cql_parser_create(); + printf("*** got CQL parser %p\n", parser); + if ((error = cql_parser_string(parser, cql)) != 0) { + cql_parser_destroy(parser); + set_ZOOM_error(c, ZOOM_ERROR_CQL_PARSE, cql); + return 0; + } + + node = cql_parser_result(parser); + printf("*** got CQL node %p\n", node); + cql_parser_destroy(parser); + printf("*** destroyed parser\n"); + + cqlfile = ZOOM_connection_option_get(c, "cqlfile"); + printf("*** cqlfile is %p\n", cqlfile); + if (cqlfile == 0) { + printf("*** cqlfile is null\n"); + cql_node_destroy(node); + printf("*** destroyed node\n"); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, "no CQL transform file"); + printf("*** set ZOOM_error\n"); + return 0; + } + printf("*** got CQL file %s\n", cqlfile); + + if ((trans = cql_transform_open_fname(cqlfile)) == 0) { + char buf[512]; + cql_node_destroy(node); + sprintf(buf, "can't open CQL transform file '%.200s': %.200s", + cqlfile, strerror(errno)); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + return 0; + } + + error = cql_transform_buf(trans, node, pqfbuf, sizeof pqfbuf); + cql_node_destroy(node); + if (error != 0) { + char buf[512]; + const char *addinfo; + error = cql_transform_error(trans, &addinfo); + cql_transform_close(trans); + sprintf(buf, "%.200s (addinfo=%.200s)", cql_strerror(error), addinfo); + set_ZOOM_error(c, ZOOM_ERROR_CQL_TRANSFORM, buf); + return 0; + } + + cql_transform_close(trans); + return xstrdup(pqfbuf); +} + + /* * Local variables: * c-basic-offset: 4