X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=client%2Fclient.c;h=5b7594d1f3346bcefca7d316cebf6e76b5ac0758;hp=d7a0ec1d97eac24f51cd36c82fabb8a1dea5f206;hb=3fa5c310994e3449aac2926385f742fe34fb5757;hpb=6158d7465f3e832a18554c3e1157c12faaa7828e diff --git a/client/client.c b/client/client.c index d7a0ec1..5b7594d 100644 --- a/client/client.c +++ b/client/client.c @@ -62,6 +62,7 @@ #include #include #include +#include #if HAVE_READLINE_READLINE_H #include @@ -104,6 +105,7 @@ static int smallSetUpperBound = 0; static int largeSetLowerBound = 1; static int mediumSetPresentNumber = 0; static Z_ElementSetNames *elementSetNames = 0; +static Z_FacetList *facet_list = 0; static Odr_int setno = 1; /* current set offset */ static enum oid_proto protocol = PROTO_Z3950; /* current app protocol */ #define RECORDSYNTAX_MAX 20 @@ -182,6 +184,7 @@ static void close_session(void); static void marc_file_write(const char *buf, size_t sz); static void wait_and_handle_response(int one_response_only); +static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url); ODR getODROutputStream(void) { @@ -242,10 +245,14 @@ static void do_hex_dump(const char* buf, size_t len) void add_otherInfos(Z_APDU *a) { Z_OtherInformation **oi; - int i; + int i = 0; yaz_oi_APDU(a, &oi); - for(i=0; i 0) yaz_oi_set_string_oid(oi, out, extraOtherInfos[i].oid, @@ -665,11 +672,10 @@ static int cmd_base(const char *arg) return set_base(arg); } -int session_connect(const char *arg) +static int session_connect_base(const char *arg, const char **basep) { void *add; char type_and_host[101]; - const char *basep = 0; if (conn) { cs_close(conn); @@ -681,7 +687,7 @@ int session_connect(const char *arg) session_mem = NULL; session_initResponse = 0; } - cs_get_host_args(arg, &basep); + cs_get_host_args(arg, basep); strncpy(type_and_host, arg, sizeof(type_and_host)-1); type_and_host[sizeof(type_and_host)-1] = '\0'; @@ -717,11 +723,6 @@ int session_connect(const char *arg) } printf("OK.\n"); cs_print_session_info(conn); - if (basep && *basep) - set_base(basep); - else if (protocol == PROTO_Z3950) - set_base("Default"); - if (protocol == PROTO_Z3950) { send_initRequest(type_and_host); @@ -730,6 +731,19 @@ int session_connect(const char *arg) return 0; } +static int session_connect(const char *arg) +{ + int r; + const char *basep = 0; + + r = session_connect_base(arg, &basep); + if (basep && *basep) + set_base(basep); + else if (protocol == PROTO_Z3950) + set_base("Default"); + return r; +} + int cmd_open(const char *arg) { int r; @@ -738,6 +752,9 @@ int cmd_open(const char *arg) strncpy(cur_host, arg, sizeof(cur_host)-1); cur_host[sizeof(cur_host)-1] = 0; } + /* TODO Make facet definition survive the open command without crashing */ + /* TODO Fix deallocation */ + facet_list = 0; set_base(""); r = session_connect(cur_host); @@ -1191,28 +1208,8 @@ static int send_deleteResultSetRequest(const char *arg) } #if YAZ_HAVE_XML2 -static int send_srw(Z_SRW_PDU *sr) +static int send_gdu(Z_GDU *gdu) { - const char *charset = negotiationCharset; - const char *host_port = cur_host; - Z_GDU *gdu; - char *path = yaz_encode_sru_dbpath_odr(out, databaseNames[0]); - - gdu = z_get_HTTP_Request_host_path(out, host_port, path); - - if (!yaz_matchstr(sru_method, "get")) - { - yaz_sru_get_encode(gdu->u.HTTP_Request, sr, out, charset); - } - else if (!yaz_matchstr(sru_method, "post")) - { - yaz_sru_post_encode(gdu->u.HTTP_Request, sr, out, charset); - } - else if (!yaz_matchstr(sru_method, "soap")) - { - yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, out, charset); - } - if (z_GDU(out, &gdu, 0, 0)) { /* encode OK */ @@ -1238,6 +1235,117 @@ static int send_srw(Z_SRW_PDU *sr) } return 0; } + +static int send_srw_host_path(Z_SRW_PDU *sr, const char *host_port, + char *path) +{ + const char *charset = negotiationCharset; + Z_GDU *gdu; + + gdu = z_get_HTTP_Request_host_path(out, host_port, path); + + if (auth) + { + if (auth->which == Z_IdAuthentication_open) + { + char **darray; + int num; + nmem_strsplit(out->mem, "/", auth->u.open, &darray, &num); + if (num >= 1) + sr->username = darray[0]; + if (num >= 2) + sr->password = darray[1]; + } + else if (auth->which == Z_IdAuthentication_idPass) + { + sr->username = auth->u.idPass->userId; + sr->password = auth->u.idPass->password; + } + } + + if (!yaz_matchstr(sru_method, "get")) + { + yaz_sru_get_encode(gdu->u.HTTP_Request, sr, out, charset); + } + else if (!yaz_matchstr(sru_method, "post")) + { + yaz_sru_post_encode(gdu->u.HTTP_Request, sr, out, charset); + } + else if (!yaz_matchstr(sru_method, "soap")) + { + yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, out, charset); + } + return send_gdu(gdu); +} + +static int send_srw(Z_SRW_PDU *sr) +{ + char *path = yaz_encode_sru_dbpath_odr(out, databaseNames[0]); + return send_srw_host_path(sr, cur_host, path); +} + +static int send_SRW_redirect(const char *uri, Z_HTTP_Response *cookie_hres) +{ + const char *username = 0; + const char *password = 0; + struct Z_HTTP_Header *h; + char *combined_cookies; + int combined_cookies_len = 0; + Z_GDU *gdu = get_HTTP_Request_url(out, uri); + + gdu->u.HTTP_Request->method = odr_strdup(out, "GET"); + z_HTTP_header_add(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(out, &gdu->u.HTTP_Request->headers, "Cookie", combined_cookies); + xfree(combined_cookies); + } + + if (auth) + { + if (auth->which == Z_IdAuthentication_open) + { + char **darray; + int num; + nmem_strsplit(out->mem, "/", auth->u.open, &darray, &num); + if (num >= 1) + username = darray[0]; + if (num >= 2) + password = darray[1]; + } + else if (auth->which == Z_IdAuthentication_idPass) + { + username = auth->u.idPass->userId; + password = auth->u.idPass->password; + } + } + + if (username && password) + { + z_HTTP_header_add_basic_auth(out, &gdu->u.HTTP_Request->headers, + username, password); + } + + return send_gdu(gdu); +} #endif #if YAZ_HAVE_XML2 @@ -1504,6 +1612,24 @@ static int send_searchRequest(const char *arg) return 2; } +static void display_term(Z_Term *term) { + switch (term->which) + { + case Z_Term_general: + printf("%.*s", term->u.general->len, term->u.general->buf); + break; + case Z_Term_characterString: + printf("%s", term->u.characterString); + break; + case Z_Term_numeric: + printf(ODR_INT_PRINTF, *term->u.numeric); + break; + case Z_Term_null: + printf("null"); + break; + } +} + /* display Query Expression as part of searchResult-1 */ static void display_queryExpression(const char *lead, Z_QueryExpression *qe) { @@ -1515,25 +1641,74 @@ static void display_queryExpression(const char *lead, Z_QueryExpression *qe) if (qe->u.term->queryTerm) { Z_Term *term = qe->u.term->queryTerm; - switch (term->which) - { - case Z_Term_general: - printf("%.*s", term->u.general->len, term->u.general->buf); - break; - case Z_Term_characterString: - printf("%s", term->u.characterString); - break; - case Z_Term_numeric: - printf(ODR_INT_PRINTF, *term->u.numeric); - break; - case Z_Term_null: - printf("null"); - break; + display_term(term); + } + } +} + +static void display_facet(Z_FacetField *facet) { + if (facet->attributes) { + Z_AttributeList *al = facet->attributes; + struct attrvalues attr_values; + attr_values.errcode = 0; + attr_values.limit = -1; + attr_values.useattr = 0; + attr_values.relation = "default"; + + facetattrs(al, &attr_values); + if (!attr_values.errcode) { + int term_index; + printf("Facet: %s (%d): \n", attr_values.useattr, /* attr_values.relation, attr_values.limit, */ facet->num_terms); + for (term_index = 0 ; term_index < facet->num_terms; term_index++) { + Z_FacetTerm *facetTerm = facet->terms[term_index]; + display_term(facetTerm->term); + printf(" (" NMEM_INT_PRINTF ")\n", *facetTerm->count); } } + + } +} + +static void* display_facets(Z_FacetList *fl) +{ + int index; + printf("Facets (%d): \n", fl->num); + + for (index = 0; index < fl->num ; index++) { + if (index) + printf(","); + display_facet(fl->elements[index]); + } + return 0; +} + +void display_searchResult1(Z_SearchInfoReport *sr) +{ + int j; + printf("SearchResult-1:"); + for (j = 0; j < sr->num; j++) + { + if (j) + printf(","); + if (!sr->elements[j]->subqueryExpression) + printf("%d", j); + display_queryExpression("term", + sr->elements[j]->subqueryExpression); + display_queryExpression("interpretation", + sr->elements[j]->subqueryInterpretation); + display_queryExpression("recommendation", + sr->elements[j]->subqueryRecommendation); + if (sr->elements[j]->subqueryCount) + printf(" cnt=" ODR_INT_PRINTF, + *sr->elements[j]->subqueryCount); + if (sr->elements[j]->subqueryId) + printf(" id=%s ", sr->elements[j]->subqueryId); } + printf("\n"); } + + /* see if we can find USR:SearchResult-1 */ static void display_searchResult(Z_OtherInformation *o) { @@ -1547,30 +1722,9 @@ static void display_searchResult(Z_OtherInformation *o) Z_External *ext = o->list[i]->information.externallyDefinedInfo; if (ext->which == Z_External_searchResult1) - { - int j; - Z_SearchInfoReport *sr = ext->u.searchResult1; - printf("SearchResult-1:"); - for (j = 0; j < sr->num; j++) - { - if (j) - printf(","); - if (!sr->elements[j]->subqueryExpression) - printf("%d", j); - display_queryExpression("term", - sr->elements[j]->subqueryExpression); - display_queryExpression("interpretation", - sr->elements[j]->subqueryInterpretation); - display_queryExpression("recommendation", - sr->elements[j]->subqueryRecommendation); - if (sr->elements[j]->subqueryCount) - printf(" cnt=" ODR_INT_PRINTF, - *sr->elements[j]->subqueryCount); - if (sr->elements[j]->subqueryId) - printf(" id=%s ", sr->elements[j]->subqueryId); - } - printf("\n"); - } + display_searchResult1(ext->u.searchResult1); + else if (ext->which == Z_External_userFacets) + display_facets(ext->u.facetList); } } } @@ -2706,6 +2860,94 @@ static int cmd_find(const char *arg) return 2; } +static Z_FacetField* parse_facet(ODR odr, const char *facet, int length) +{ + YAZ_PQF_Parser pqf_parser = yaz_pqf_create(); + char buffer[length+1]; + Odr_oid *attributeSetId; + Z_FacetField *facet_field; + Z_AttributeList *attribute_list; + memcpy(buffer, facet, length); + buffer[length] = '\0'; + attribute_list = yaz_pqf_scan_attribute_list(pqf_parser, odr, &attributeSetId, buffer); + + if (!attribute_list) { + printf("Invalid facet definition: %s", facet); + return 0; + } + facet_field = odr_malloc(odr, sizeof(*facet_field)); + facet_field->attributes = attribute_list; + facet_field->num_terms = 0; + facet_field->terms = 0; + //debug_add_facet_term(odr, facet_field); + + return facet_field; +} + +#define FACET_DElIMITER ',' + +static int scan_facet_argument(const char *arg) { + int index; + int length = strlen(arg); + int count = 1; + for (index = 0; index < length; index++) { + if (arg[index] == FACET_DElIMITER) + count++; + } + return count; +} + +static int cmd_facets(const char *arg) +{ + int size = 0; + if (!*arg) + { + facet_list = 0; + printf("Facets cleared.\n"); + return 0; + } + size = strlen(arg); + if (only_z3950()) + { + printf("Currently only supported for Z39.50.\n"); + return 0; + } + else + { + int index = 0; + Z_FacetField **elements; + int num_elements ; + const char *facet = arg; + // parse facets list + ODR odr = odr_createmem(ODR_ENCODE); + num_elements = scan_facet_argument(arg); + facet_list = odr_malloc(odr, sizeof(*facet_list)); + elements = odr_malloc(odr, num_elements * sizeof(*elements)); + for (index = 0; index < num_elements;) { + const char *pos = strchr(facet, FACET_DElIMITER); + if (pos == 0) + pos = facet + strlen(facet); + elements[index] = parse_facet(odr, (const char *) facet, (pos - facet)); + if (elements[index]) { + index++; + } + else + num_elements--; + facet = pos + 1; + } + + if (!num_elements || !facet_list) { + printf("Invalid facet list: %s", arg); + return 0; + } + facet_list->elements = elements; + facet_list->num = index; + return 1; + } + return 2; +} + + static int cmd_delete(const char *arg) { if (only_z3950()) @@ -2764,36 +3006,54 @@ static int cmd_setnames(const char *arg) /* PRESENT SERVICE ----------------------------- */ -static void parse_show_args(const char *arg_c, char *setstring, - Odr_int *start, Odr_int *number) +static int parse_show_args(const char *arg_c, char *setstring, + Odr_int *start, Odr_int *number) { - char arg[40]; - char *p; + char *end_ptr; + Odr_int start_position; - strncpy(arg, arg_c, sizeof(arg)-1); - arg[sizeof(arg)-1] = '\0'; + if (setnumber >= 0) + sprintf(setstring, "%d", setnumber); + else + *setstring = '\0'; - if ((p = strchr(arg, '+'))) + if (!strcmp(arg_c, "all")) { - *number = odr_atoi(p + 1); - *p = '\0'; + *number = last_hit_count; + *start = 1; } - if (*arg) + start_position = odr_strtol(arg_c, &end_ptr, 10); + if (end_ptr == arg_c) + return 1; + *start = start_position; + if (*end_ptr == '\0') + return 1; + while (isspace(*(unsigned char *)end_ptr)) + end_ptr++; + if (*end_ptr != '+') { - if (!strcmp(arg, "all")) - { - *number = last_hit_count; - *start = 1; - } - else - *start = odr_atoi(arg); + printf("Bad show arg: expected +. Got %s\n", end_ptr); + return 0; } - if (p && (p=strchr(p+1, '+'))) - strcpy(setstring, p+1); - else if (setnumber >= 0) - sprintf(setstring, "%d", setnumber); - else - *setstring = '\0'; + end_ptr++; + arg_c = end_ptr; + *number = odr_strtol(arg_c, &end_ptr, 10); + if (end_ptr == arg_c) + { + printf("Bad show arg: expected number after +\n"); + return 0; + } + if (*end_ptr == '\0') + return 1; + while (isspace(*(unsigned char *)end_ptr)) + end_ptr++; + if (*end_ptr != '+') + { + printf("Bad show arg: + expected. Got %s\n", end_ptr); + return 0; + } + strcpy(setstring, end_ptr+1); + return 1; } static int send_presentRequest(const char *arg) @@ -2806,7 +3066,8 @@ static int send_presentRequest(const char *arg) req->referenceId = set_refid(out); - parse_show_args(arg, setstring, &setno, &nos); + if (!parse_show_args(arg, setstring, &setno, &nos)) + return 0; if (*setstring) req->resultSetId = setstring; @@ -2897,7 +3158,8 @@ static int send_SRW_presentRequest(const char *arg) if (!sr) return 0; - parse_show_args(arg, setstring, &setno, &nos); + if (!parse_show_args(arg, setstring, &setno, &nos)) + return 0; sr->u.request->startRecord = odr_intdup(out, setno); sr->u.request->maximumRecords = odr_intdup(out, nos); if (record_schema) @@ -3070,6 +3332,7 @@ int send_scanrequest(const char *set, const char *query, { YAZ_PQF_Parser pqf_parser = yaz_pqf_create(); + if (!(req->termListAndStartPoint = yaz_pqf_scan(pqf_parser, out, &req->attributeSet, query))) { @@ -3161,7 +3424,7 @@ int send_sortrequest(const char *arg, int newset) return 2; } -void display_term(Z_TermInfo *t) +void display_term_info(Z_TermInfo *t) { if (t->displayTerm) printf("%s", t->displayTerm); @@ -3203,7 +3466,7 @@ void process_scanResponse(Z_ScanResponse *res) if (entries[i]->which == Z_Entry_termInfo) { printf("%c ", i + 1 == pos_term ? '*' : ' '); - display_term(entries[i]->u.termInfo); + display_term_info(entries[i]->u.termInfo); } else display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1); @@ -4189,9 +4452,12 @@ static void http_response(Z_HTTP_Response *hres) } #endif +#define max_HTTP_redirects 2 + static void wait_and_handle_response(int one_response_only) { int reconnect_ok = 1; + int no_redirects = 0; int res; char *netbuffer= 0; int netbufferlen = 0; @@ -4320,7 +4586,26 @@ static void wait_and_handle_response(int one_response_only) #if YAZ_HAVE_XML2 else if (gdu->which == Z_GDU_HTTP_Response) { - http_response(gdu->u.HTTP_Response); + Z_HTTP_Response *hres = gdu->u.HTTP_Response; + int code = hres->code; + const char *location = 0; + if ((code == 301 || code == 302) + && no_redirects < max_HTTP_redirects + && !yaz_matchstr(sru_method, "get") + && (location = z_HTTP_header_lookup(hres->headers, "Location"))) + { + const char *base_tmp; + session_connect_base(location, &base_tmp); + no_redirects++; + if (conn) + { + if (send_SRW_redirect(location, hres) == 2) + continue; + } + printf("Redirect failed\n"); + } + else + http_response(gdu->u.HTTP_Response); } #endif if (one_response_only) @@ -4611,6 +4896,7 @@ static struct { {"open", cmd_open, "('tcp'|'ssl')':[':'][/]",NULL,0,NULL}, {"quit", cmd_quit, "",NULL,0,NULL}, {"find", cmd_find, "",NULL,0,NULL}, + {"facets", cmd_facets, "",NULL,0,NULL}, {"delete", cmd_delete, "",NULL,0,NULL}, {"base", cmd_base, "",NULL,0,NULL}, {"show", cmd_show, "['+'<#recs>['+']]",NULL,0,NULL}, @@ -4966,7 +5252,7 @@ static void client(void) line_in=readline(C_PROMPT); if (!line_in) { - putchar("\n"); + putchar('\n'); break; } #if HAVE_READLINE_HISTORY_H