X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=client%2Fclient.c;h=5edf45746e526876b7d29abc578a083c61d5f70d;hp=cabebb9e63f1f8d5c493f1b87e813996a0162553;hb=6c5cedfce30df58be034fd3555ae6935b3023882;hpb=fca985d5c2944fa01270d363190264e4ee36ec93 diff --git a/client/client.c b/client/client.c index cabebb9..5edf457 100644 --- a/client/client.c +++ b/client/client.c @@ -1,10 +1,95 @@ /* - * Copyright (c) 1995, Index Data. + * Copyright (c) 1995-1996, Index Data. * See the file LICENSE for details. * Sebastian Hammer, Adam Dickmeiss * * $Log: client.c,v $ - * Revision 1.15 1995-06-22 09:28:03 quinn + * Revision 1.43 1996-11-08 11:03:26 adam + * Client accepts multiple database names. + * + * Revision 1.42 1996/10/08 10:44:57 quinn + * Resolved conflicts. + * + * Revision 1.41 1996/10/07 15:29:03 quinn + * Work + * + * Revision 1.40 1996/08/29 14:19:34 quinn + * Fixed conflict (CVS) + * + * Revision 1.39 1996/08/27 10:43:22 quinn + * Made select() optional + * + * Revision 1.38 1996/08/12 14:09:11 adam + * Default prefix query attribute set defined by using p_query_attset. + * + * Revision 1.37 1996/07/06 19:58:29 quinn + * System headerfiles gathered in yconfig + * + * Revision 1.36 1996/06/10 08:53:47 quinn + * Added Summary + * + * Revision 1.35 1996/06/03 09:45:50 quinn + * Added display of OIDs in the GRS routine. + * + * Revision 1.34 1996/05/09 07:26:49 quinn + * *** empty log message *** + * + * Revision 1.33 1996/05/09 07:25:22 quinn + * Small + * + * Revision 1.32 1996/03/15 11:05:33 adam + * The user can set the preferred query type (prefix, ccl, ..) with the + * querytype command. + * + * Revision 1.31 1996/02/20 12:51:54 quinn + * Fixed problems with EXTERNAL. + * + * Revision 1.30 1996/02/12 18:18:09 quinn + * Fidgeting. + * + * Revision 1.29 1996/01/02 08:57:25 quinn + * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass + * + * Revision 1.28 1995/12/14 11:09:31 quinn + * Added Explain record syntax to the format command. + * + * Revision 1.27 1995/12/12 16:37:02 quinn + * Added destroy element to data1_node. + * + * Revision 1.26 1995/12/12 14:11:00 quinn + * Minimal. + * + * Revision 1.25 1995/11/13 09:27:22 quinn + * Fiddling with the variant stuff. + * + * Revision 1.24 1995/10/30 12:41:13 quinn + * Added hostname lookup for server. + * + * Revision 1.23 1995/10/18 16:12:30 quinn + * Better diagnostics. + * + * Revision 1.22 1995/10/11 14:49:12 quinn + * Smallish. + * + * Revision 1.21 1995/09/29 17:01:47 quinn + * More Windows work + * + * Revision 1.20 1995/08/29 14:24:13 quinn + * Added second half of close-handshake + * + * Revision 1.19 1995/08/29 11:17:28 quinn + * Added code to receive close + * + * Revision 1.18 1995/08/28 12:21:27 quinn + * Client can now ask for simple element set names. + * + * Revision 1.17 1995/08/17 12:45:02 quinn + * Fixed minor problems with GRS-1. Added support in c&s. + * + * Revision 1.16 1995/08/15 12:00:04 quinn + * Updated External + * + * Revision 1.15 1995/06/22 09:28:03 quinn * Fixed bug in SUTRS processing. * * Revision 1.14 1995/06/19 12:37:41 quinn @@ -57,13 +142,11 @@ * to illustrate the use of the YAZ service-level API. */ +#include #include #include -#include +#include #include -#ifdef _AIX -#include -#endif #include #include @@ -75,36 +158,46 @@ #include #include -#ifdef RPN_QUERY -#ifdef PREFIX_QUERY #include -#else + +#if CCL2RPN #include #endif -#endif #define C_PROMPT "Z> " static ODR out, in, print; /* encoding and decoding streams */ static COMSTACK conn = 0; /* our z-association */ static Z_IdAuthentication *auth = 0; /* our current auth definition */ -static char database[512] = "Default"; /* Database name */ +static char *databaseNames[128]; +static int num_databaseNames = 0; static int setnumber = 0; /* current result set number */ static int smallSetUpperBound = 0; static int largeSetLowerBound = 1; static int mediumSetPresentNumber = 0; +static Z_ElementSetNames *elementSetNames = 0; static int setno = 1; /* current set offset */ static int protocol = PROTO_Z3950; /* current app protocol */ static int recordsyntax = VAL_USMARC; -static ODR_MEM session_mem; /* memory handle for init-response */ -static Z_InitResponse *session = 0; /* session parameters */ +static int sent_close = 0; +static ODR_MEM session_mem; /* memory handle for init-response */ +static Z_InitResponse *session = 0; /* session parameters */ static char last_scan[512] = "0"; static char last_cmd[100] = "?"; -#ifdef RPN_QUERY -#ifndef PREFIX_QUERY +static FILE *marcdump = 0; +static char marcdump_file[512] = "marc.out"; + +typedef enum { + QueryType_Prefix, + QueryType_CCL, + QueryType_CCL2RPN +} QueryType; + +static QueryType queryType = QueryType_Prefix; + +#if CCL2RPN static CCL_bibset bibset; /* CCL bibset handle */ #endif -#endif static void send_apdu(Z_APDU *a) { @@ -113,15 +206,15 @@ static void send_apdu(Z_APDU *a) if (!z_APDU(out, &a, 0)) { - odr_perror(out, "Encoding APDU"); - exit(1); + odr_perror(out, "Encoding APDU"); + exit(1); } buf = odr_getbuf(out, &len, 0); - odr_reset(out); /* release the APDU */ + odr_reset(out); /* release the APDU structure */ if (cs_put(conn, buf, len) < 0) { - fprintf(stderr, "cs_put: %s", cs_errlist[cs_errno(conn)]); - exit(1); + fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn))); + exit(1); } } @@ -140,6 +233,9 @@ static void send_initRequest() ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1); ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2); + ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3); + + *req->maximumRecordSize = 1024*1024; req->idAuthentication = auth; @@ -154,29 +250,29 @@ static int process_initResponse(Z_InitResponse *res) session = res; if (!*res->result) - printf("Connection rejected by target.\n"); + printf("Connection rejected by target.\n"); else - printf("Connection accepted by target.\n"); + printf("Connection accepted by target.\n"); if (res->implementationId) - printf("ID : %s\n", res->implementationId); + printf("ID : %s\n", res->implementationId); if (res->implementationName) - printf("Name : %s\n", res->implementationName); + printf("Name : %s\n", res->implementationName); if (res->implementationVersion) - printf("Version: %s\n", res->implementationVersion); + printf("Version: %s\n", res->implementationVersion); if (res->userInformationField) { - printf("UserInformationfield:\n"); - if (!odr_external(print, (Odr_external**)&res-> userInformationField, - 0)) - { - odr_perror(print, "Printing userinfo\n"); - odr_reset(print); - } - if (res->userInformationField->which == ODR_EXTERNAL_octet) - { - printf("Guessing visiblestring:\n"); - printf("'%s'\n", res->userInformationField->u. octet_aligned->buf); - } + printf("UserInformationfield:\n"); + if (!z_External(print, (Z_External**)&res-> userInformationField, + 0)) + { + odr_perror(print, "Printing userinfo\n"); + odr_reset(print); + } + if (res->userInformationField->which == Z_External_octet) + { + printf("Guessing visiblestring:\n"); + printf("'%s'\n", res->userInformationField->u. octet_aligned->buf); + } } return 0; } @@ -189,55 +285,55 @@ int cmd_open(char *arg) if (conn) { - printf("Already connected.\n"); - return 0; + printf("Already connected.\n"); + return 0; } if (!*arg || sscanf(arg, "%[^:]:%s", type, addr) < 2) { - fprintf(stderr, "Usage: open (osi|tcp) ':' [tsel '/']host[':'port]\n"); - return 0; + fprintf(stderr, "Usage: open (osi|tcp) ':' [tsel '/']host[':'port]\n"); + return 0; } #ifdef USE_XTIMOSI if (!strcmp(type, "osi")) { - if (!(add = mosi_strtoaddr(addr))) - { - perror(arg); - return 0; - } - t = mosi_type; - protocol = PROTO_SR; + if (!(add = mosi_strtoaddr(addr))) + { + perror(arg); + return 0; + } + t = mosi_type; + protocol = PROTO_SR; } else #endif if (!strcmp(type, "tcp")) { - if (!(add = tcpip_strtoaddr(addr))) - { - perror(arg); - return 0; - } - t = tcpip_type; - protocol = PROTO_Z3950; + if (!(add = tcpip_strtoaddr(addr))) + { + perror(arg); + return 0; + } + t = tcpip_type; + protocol = PROTO_Z3950; } else { - fprintf(stderr, "Bad type: %s\n", type); - return 0; + fprintf(stderr, "Bad type: %s\n", type); + return 0; } if (!(conn = cs_create(t, 1, protocol))) { - perror("cs_create"); - return 0; + perror("cs_create"); + return 0; } printf("Connecting..."); fflush(stdout); if (cs_connect(conn, add) < 0) { - perror("connect"); - cs_close(conn); - conn = 0; - return 0; + perror("connect"); + cs_close(conn); + conn = 0; + return 0; } printf("Ok.\n"); send_initRequest(); @@ -251,9 +347,9 @@ int cmd_authentication(char *arg) if (!*arg) { - printf("Auth field set to null\n"); - auth = 0; - return 1; + printf("Auth field set to null\n"); + auth = 0; + return 1; } auth = &au; au.which = Z_IdAuthentication_open; @@ -264,51 +360,171 @@ int cmd_authentication(char *arg) /* SEARCH SERVICE ------------------------------ */ -void display_record(Z_DatabaseRecord *p) +static void display_variant(Z_Variant *v, int level) { - Odr_external *r = (Odr_external*) p; - oident *ent = oid_getentbyoid(r->direct_reference); + int i; - if (r->direct_reference) + for (i = 0; i < v->num_triples; i++) { - printf("Record type: "); - if (ent) - printf("%s\n", ent->desc); - else if (!odr_oid(print, &r->direct_reference, 0)) - { - odr_perror(print, "print oid"); - odr_reset(print); - } + printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->class, + *v->triples[i]->type); + if (v->triples[i]->which == Z_Triple_internationalString) + printf(",value=%s\n", v->triples[i]->value.internationalString); + else + printf("\n"); } - if (r->which == ODR_EXTERNAL_octet && p->u.octet_aligned->len) - marc_display ((char*)p->u.octet_aligned->buf, stdout); - else if (ent->value == VAL_SUTRS) +} + +static void display_grs1(Z_GenericRecord *r, int level) +{ + int i; + + if (!r) + return; + for (i = 0; i < r->num_elements; i++) { - Odr_oct *rc; + Z_TaggedElement *t; + + printf("%*s", level * 4, ""); + t = r->elements[i]; + printf("("); + if (t->tagType) + printf("%d,", *t->tagType); + else + printf("?,"); + if (t->tagValue->which == Z_StringOrNumeric_numeric) + printf("%d) ", *t->tagValue->u.numeric); + else + printf("%s) ", t->tagValue->u.string); + if (t->content->which == Z_ElementData_subtree) + { + printf("\n"); + display_grs1(t->content->u.subtree, level+1); + } + else if (t->content->which == Z_ElementData_string) + printf("%s\n", t->content->u.string); + else if (t->content->which == Z_ElementData_numeric) + printf("%d\n", *t->content->u.numeric); + else if (t->content->which == Z_ElementData_oid) + { + int *ip = t->content->u.oid; + oident *oent; - if (r->which != ODR_EXTERNAL_single) + if ((oent = oid_getentbyoid(t->content->u.oid))) + printf("OID: %s\n", oent->desc); + else + { + printf("{"); + while (ip && *ip >= 0) + printf(" %d", *(ip++)); + printf(" }\n"); + } + } + else if (t->content->which == Z_ElementData_noDataRequested) + printf("[No data requested]\n"); + else if (t->content->which == Z_ElementData_elementEmpty) + printf("[Element empty]\n"); + else if (t->content->which == Z_ElementData_elementNotThere) + printf("[Element not there]\n"); + else + printf("??????\n"); + if (t->appliedVariant) + display_variant(t->appliedVariant, level+1); + if (t->metaData && t->metaData->supportedVariants) { - printf("Expecting single ASN.1 type for SUTRS.\n"); - return; + int c; + + printf("%*s---- variant list\n", (level+1)*4, ""); + for (c = 0; c < t->metaData->num_supportedVariants; c++) + { + printf("%*svariant #%d\n", (level+1)*4, "", c); + display_variant(t->metaData->supportedVariants[c], level + 2); + } } - odr_setbuf(in, (char*)r->u.single_ASN1_type->buf, - r->u.single_ASN1_type->len, 0); - if (!z_SUTRS(in, &rc, 0)) + } +} + +static void display_record(Z_DatabaseRecord *p) +{ + Z_External *r = (Z_External*) p; + oident *ent = oid_getentbyoid(r->direct_reference); + + /* + * Tell the user what we got. + */ + if (r->direct_reference) + { + printf("Record type: "); + if (ent) + printf("%s\n", ent->desc); + else if (!odr_oid(print, &r->direct_reference, 0)) + { + odr_perror(print, "print oid"); + odr_reset(print); + } + } + + /* Check if this is a known, ASN.1 type tucked away in an octet string */ + if (ent && r->which == Z_External_octet) + { + Z_ext_typeent *type = z_ext_getentbyref(ent->value); + void *rr; + + if (type) { - odr_perror(in, "decoding SUTRS"); - odr_reset(in); + /* + * Call the given decoder to process the record. + */ + odr_setbuf(in, (char*)p->u.octet_aligned->buf, + p->u.octet_aligned->len, 0); + if (!(*type->fun)(in, &rr, 0)) + { + odr_perror(in, "Decoding constructed record."); + fprintf(stderr, "[Near %d]\n", odr_offset(in)); + fprintf(stderr, "Packet dump:\n---------\n"); + odr_dumpBER(stderr, (char*)p->u.octet_aligned->buf, + p->u.octet_aligned->len); + fprintf(stderr, "---------\n"); + exit(1); + } + /* + * Note: we throw away the original, BER-encoded record here. + * Do something else with it if you want to keep it. + */ + r->u.sutrs = rr; /* we don't actually check the type here. */ + r->which = type->what; } - else - printf("%.*s", rc->len, rc->buf); + } + if (ent->value == VAL_SOIF) + printf("%.*s", r->u.octet_aligned->len, r->u.octet_aligned->buf); + else if (r->which == Z_External_octet && p->u.octet_aligned->len) + marc_display ((char*)p->u.octet_aligned->buf, stdout); + else if (ent->value == VAL_SUTRS) + { + if (r->which != Z_External_sutrs) + { + printf("Expecting single SUTRS type for SUTRS.\n"); + return; + } + printf("%.*s", r->u.sutrs->len, r->u.sutrs->buf); + } + else if (ent->value == VAL_GRS1) + { + if (r->which != Z_External_grs1) + { + printf("Expecting single GRS type for GRS.\n"); + return; + } + display_grs1(r->u.grs1, 0); } else { - printf("Unknown record representation.\n"); - if (!odr_external(print, &r, 0)) - { - odr_perror(print, "Printing external"); - odr_reset(print); - } + printf("Unknown record representation.\n"); + if (!z_External(print, &r, 0)) + { + odr_perror(print, "Printing external"); + odr_reset(print); + } } } @@ -325,30 +541,30 @@ static void display_diagrec(Z_DiagRec *p) #ifdef Z_95 if (p->which != Z_DiagRec_defaultFormat) { - printf("Diagnostic record not in default format.\n"); - return; + printf("Diagnostic record not in default format.\n"); + return; } else - r = p->u.defaultFormat; + r = p->u.defaultFormat; #endif if (!(ent = oid_getentbyoid(r->diagnosticSetId)) || - ent->class != CLASS_DIAGSET || ent->value != VAL_BIB1) - printf("Missing or unknown diagset\n"); + ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1) + printf("Missing or unknown diagset\n"); printf(" [%d] %s", *r->condition, diagbib1_str(*r->condition)); if (r->addinfo && *r->addinfo) - printf(" -- %s\n", r->addinfo); + printf(" -- '%s'\n", r->addinfo); else - printf("\n"); + printf("\n"); } static void display_nameplusrecord(Z_NamePlusRecord *p) { if (p->databaseName) - printf("[%s]", p->databaseName); + printf("[%s]", p->databaseName); if (p->which == Z_NamePlusRecord_surrogateDiagnostic) - display_diagrec(p->u.surrogateDiagnostic); + display_diagrec(p->u.surrogateDiagnostic); else - display_record(p->u.databaseRecord); + display_record(p->u.databaseRecord); } static void display_records(Z_Records *p) @@ -356,12 +572,12 @@ static void display_records(Z_Records *p) int i; if (p->which == Z_Records_NSD) - display_diagrec(p->u.nonSurrogateDiagnostic); + display_diagrec(p->u.nonSurrogateDiagnostic); else { - printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records); - for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++) - display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]); + printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records); + for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++) + display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]); } } @@ -369,93 +585,99 @@ static int send_searchRequest(char *arg) { Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest); Z_SearchRequest *req = apdu->u.searchRequest; - char *databaseNames = database; Z_Query query; -#ifdef RPN_QUERY -#ifndef PREFIX_QUERY +#if CCL2RPN struct ccl_rpn_node *rpn; int error, pos; -#endif + oident bib1; #endif char setstring[100]; -#ifdef RPN_QUERY Z_RPNQuery *RPNquery; - oident bib1; -#else Odr_oct ccl_query; -#endif -#ifdef RPN_QUERY -#ifndef PREFIX_QUERY - rpn = ccl_find_str(bibset, arg, &error, &pos); - if (error) +#if CCL2RPN + if (queryType == QueryType_CCL2RPN) { - printf("CCL ERROR: %s\n", ccl_err_msg(error)); - return 0; + rpn = ccl_find_str(bibset, arg, &error, &pos); + if (error) + { + printf("CCL ERROR: %s\n", ccl_err_msg(error)); + return 0; + } } #endif -#endif if (!strcmp(arg, "@big")) /* strictly for troublemaking */ { - static unsigned char big[2100]; - static Odr_oct bigo; - - /* send a very big referenceid to test transport stack etc. */ - memset(big, 'A', 2100); - bigo.len = bigo.size = 2100; - bigo.buf = big; - req->referenceId = &bigo; + static unsigned char big[2100]; + static Odr_oct bigo; + + /* send a very big referenceid to test transport stack etc. */ + memset(big, 'A', 2100); + bigo.len = bigo.size = 2100; + bigo.buf = big; + req->referenceId = &bigo; } if (setnumber >= 0) { - sprintf(setstring, "%d", ++setnumber); - req->resultSetName = setstring; + sprintf(setstring, "%d", ++setnumber); + req->resultSetName = setstring; } *req->smallSetUpperBound = smallSetUpperBound; *req->largeSetLowerBound = largeSetLowerBound; *req->mediumSetPresentNumber = mediumSetPresentNumber; if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 && - mediumSetPresentNumber > 0)) + mediumSetPresentNumber > 0)) { - oident prefsyn; - - prefsyn.proto = protocol; - prefsyn.class = CLASS_RECSYN; - prefsyn.value = recordsyntax; - req->preferredRecordSyntax = odr_oiddup(out, oid_getoidbyent(&prefsyn)); + oident prefsyn; + + prefsyn.proto = protocol; + prefsyn.oclass = CLASS_RECSYN; + prefsyn.value = recordsyntax; + req->preferredRecordSyntax = + odr_oiddup(out, oid_getoidbyent(&prefsyn)); + req->smallSetElementSetNames = + req->mediumSetElementSetNames = elementSetNames; } - req->num_databaseNames = 1; - req->databaseNames = &databaseNames; + req->num_databaseNames = num_databaseNames; + req->databaseNames = databaseNames; req->query = &query; -#ifdef RPN_QUERY - query.which = Z_Query_type_1; - -#ifndef PREFIX_QUERY - assert((RPNquery = ccl_rpn_query(rpn))); -#else - RPNquery = p_query_rpn (out, arg); - if (!RPNquery) + switch (queryType) { - printf("Prefix query error\n"); + case QueryType_Prefix: + query.which = Z_Query_type_1; + RPNquery = p_query_rpn (out, protocol, arg); + if (!RPNquery) + { + printf("Prefix query error\n"); + return 0; + } + query.u.type_1 = RPNquery; + break; + case QueryType_CCL: + query.which = Z_Query_type_2; + query.u.type_2 = &ccl_query; + ccl_query.buf = (unsigned char*) arg; + ccl_query.len = strlen(arg); + break; +#if CCL2RPN + case QueryType_CCL2RPN: + query.which = Z_Query_type_1; + assert((RPNquery = ccl_rpn_query(rpn))); + bib1.proto = protocol; + bib1.oclass = CLASS_ATTSET; + bib1.value = VAL_BIB1; + RPNquery->attributeSetId = oid_getoidbyent(&bib1); + query.u.type_1 = RPNquery; + break; +#endif + default: + printf ("Unsupported query type\n"); return 0; } -#endif - bib1.proto = protocol; - bib1.class = CLASS_ATTSET; - bib1.value = VAL_BIB1; - RPNquery->attributeSetId = oid_getoidbyent(&bib1); - query.u.type_1 = RPNquery; -#else - query.which = Z_Query_type_2; - query.u.type_2 = &ccl_query; - ccl_query.buf = (unsigned char*) arg; - ccl_query.len = strlen(arg); -#endif - send_apdu(apdu); setno = 1; printf("Sent searchRequest.\n"); @@ -465,16 +687,16 @@ static int send_searchRequest(char *arg) static int process_searchResponse(Z_SearchResponse *res) { if (*res->searchStatus) - printf("Search was a success.\n"); + printf("Search was a success.\n"); else - printf("Search was a bloomin' failure.\n"); + printf("Search was a bloomin' failure.\n"); printf("Number of hits: %d, setno %d\n", - *res->resultCount, setnumber); + *res->resultCount, setnumber); printf("records returned: %d\n", - *res->numberOfRecordsReturned); + *res->numberOfRecordsReturned); setno += *res->numberOfRecordsReturned; if (res->records) - display_records(res->records); + display_records(res->records); return 0; } @@ -482,37 +704,37 @@ static int cmd_find(char *arg) { if (!*arg) { - printf("Find what?\n"); - return 0; + printf("Find what?\n"); + return 0; } if (!conn) { - printf("Not connected yet\n"); - return 0; + printf("Not connected yet\n"); + return 0; } if (!send_searchRequest(arg)) - return 0; + return 0; return 2; } static int cmd_ssub(char *arg) { if (!(smallSetUpperBound = atoi(arg))) - return 0; + return 0; return 1; } static int cmd_lslb(char *arg) { if (!(largeSetLowerBound = atoi(arg))) - return 0; + return 0; return 1; } static int cmd_mspn(char *arg) { if (!(mediumSetPresentNumber = atoi(arg))) - return 0; + return 0; return 1; } @@ -526,12 +748,30 @@ static int cmd_status(char *arg) static int cmd_base(char *arg) { + int i; + char *cp; + if (!*arg) { - printf("Usage: base \n"); - return 0; + printf("Usage: base ...\n"); + return 0; + } + for (i = 0; iu.presentRequest; + Z_RecordComposition compo; oident prefsyn; int nos = 1; char *p; @@ -563,32 +804,88 @@ static int send_presentRequest(char *arg) if ((p = strchr(arg, '+'))) { - nos = atoi(p + 1); - *p = 0; + nos = atoi(p + 1); + *p = 0; } if (*arg) - setno = atoi(arg); + setno = atoi(arg); if (setnumber >= 0) { - sprintf(setstring, "%d", setnumber); - req->resultSetId = setstring; + sprintf(setstring, "%d", setnumber); + req->resultSetId = setstring; } + + +#if 0 + if (1) + { + static Z_Range range; + static Z_Range *rangep = ⦥ + req->num_ranges = 1; +#endif + + + + + + + + + req->resultSetStartPoint = &setno; req->numberOfRecordsRequested = &nos; prefsyn.proto = protocol; - prefsyn.class = CLASS_RECSYN; + prefsyn.oclass = CLASS_RECSYN; prefsyn.value = recordsyntax; req->preferredRecordSyntax = oid_getoidbyent(&prefsyn); + if (elementSetNames) + { + req->recordComposition = &compo; + compo.which = Z_RecordComp_simple; + compo.u.simple = elementSetNames; + } send_apdu(apdu); printf("Sent presentRequest (%d+%d).\n", setno, nos); return 2; } +void process_close(Z_Close *req) +{ + Z_APDU *apdu = zget_APDU(out, Z_APDU_close); + Z_Close *res = apdu->u.close; + + static char *reasons[] = + { + "finished", + "shutdown", + "system problem", + "cost limit reached", + "resources", + "security violation", + "protocolError", + "lack of activity", + "peer abort", + "unspecified" + }; + + printf("Reason: %s, message: %s\n", reasons[*req->closeReason], + req->diagnosticInformation ? req->diagnosticInformation : "NULL"); + if (sent_close) + { + printf("Goodbye.\n"); + exit(0); + } + *res->closeReason = Z_Close_finished; + send_apdu(apdu); + printf("Sent response.\n"); + sent_close = 1; +} + static int cmd_show(char *arg) { if (!send_presentRequest(arg)) - return 0; + return 0; return 2; } @@ -602,18 +899,18 @@ int cmd_cancel(char *arg) { Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest); Z_TriggerResourceControlRequest *req = - apdu->u.triggerResourceControlRequest; + apdu->u.triggerResourceControlRequest; bool_t false = 0; if (!session) { - printf("Session not initialized yet\n"); - return 0; + printf("Session not initialized yet\n"); + return 0; } if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl)) { - printf("Target doesn't support cancel (trigger resource ctrl)\n"); - return 0; + printf("Target doesn't support cancel (trigger resource ctrl)\n"); + return 0; } *req->requestedAction = Z_TriggerResourceCtrl_cancel; req->resultSetWanted = &false; @@ -627,16 +924,11 @@ int send_scanrequest(char *string, int pp, int num) { Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest); Z_ScanRequest *req = apdu->u.scanRequest; - char *db = database; - oident attset; - - req->num_databaseNames = 1; - req->databaseNames = &db; - attset.proto = protocol; - attset.class = CLASS_ATTSET; - attset.value = VAL_BIB1; - req->attributeSet = oid_getoidbyent(&attset); - req->termListAndStartPoint = p_query_scan(out, string); + + req->num_databaseNames = num_databaseNames; + req->databaseNames = databaseNames; + req->termListAndStartPoint = p_query_scan(out, protocol, + &req->attributeSet, string); req->numberOfTermsRequested = # req->preferredPositionInResponse = &pp; send_apdu(apdu); @@ -647,13 +939,13 @@ void display_term(Z_TermInfo *t) { if (t->term->which == Z_Term_general) { - printf("%.*s (%d)\n", t->term->u.general->len, t->term->u.general->buf, - t->globalOccurrences ? *t->globalOccurrences : -1); - sprintf(last_scan, "%.*s", t->term->u.general->len, - t->term->u.general->buf); + printf("%.*s (%d)\n", t->term->u.general->len, t->term->u.general->buf, + t->globalOccurrences ? *t->globalOccurrences : -1); + sprintf(last_scan, "%.*s", t->term->u.general->len, + t->term->u.general->buf); } else - printf("Term type not general.\n"); + printf("Term type not general.\n"); } void process_scanResponse(Z_ScanResponse *res) @@ -661,48 +953,48 @@ void process_scanResponse(Z_ScanResponse *res) int i; printf("SCAN: %d entries, position=%d\n", *res->numberOfEntriesReturned, - *res->positionOfTerm); + *res->positionOfTerm); if (*res->scanStatus != Z_Scan_success) - printf("Scan returned code %d\n", *res->scanStatus); + printf("Scan returned code %d\n", *res->scanStatus); if (!res->entries) - return; + return; if (res->entries->which == Z_ListEntries_entries) { - Z_Entries *ent = res->entries->u.entries; - - for (i = 0; i < ent->num_entries; i++) - if (ent->entries[i]->which == Z_Entry_termInfo) - { - printf("%c ", i + 1 == *res->positionOfTerm ? '*' : ' '); - display_term(ent->entries[i]->u.termInfo); - } - else - display_diagrec(ent->entries[i]->u.surrogateDiagnostic); + Z_Entries *ent = res->entries->u.entries; + + for (i = 0; i < ent->num_entries; i++) + if (ent->entries[i]->which == Z_Entry_termInfo) + { + printf("%c ", i + 1 == *res->positionOfTerm ? '*' : ' '); + display_term(ent->entries[i]->u.termInfo); + } + else + display_diagrec(ent->entries[i]->u.surrogateDiagnostic); } else - display_diagrec(res->entries->u.nonSurrogateDiagnostics->diagRecs[0]); + display_diagrec(res->entries->u.nonSurrogateDiagnostics->diagRecs[0]); } int cmd_scan(char *arg) { if (!session) { - printf("Session not initialized yet\n"); - return 0; + printf("Session not initialized yet\n"); + return 0; } if (!ODR_MASK_GET(session->options, Z_Options_scan)) { - printf("Target doesn't support scan\n"); - return 0; + printf("Target doesn't support scan\n"); + return 0; } if (*arg) { - if (send_scanrequest(arg, 5, 20) < 0) - return 0; + if (send_scanrequest(arg, 5, 20) < 0) + return 0; } else - if (send_scanrequest(last_scan, 1, 20) < 0) - return 0; + if (send_scanrequest(last_scan, 1, 20) < 0) + return 0; return 2; } @@ -710,86 +1002,186 @@ int cmd_format(char *arg) { if (!arg || !*arg) { - printf("Usage: format \n"); - return 0; + printf("Usage: format \n"); + return 0; } if (!strcmp(arg, "sutrs")) { - printf("Preferred format is SUTRS.\n"); - recordsyntax = VAL_SUTRS; - return 1; + printf("Preferred format is SUTRS.\n"); + recordsyntax = VAL_SUTRS; + return 1; } else if (!strcmp(arg, "usmarc")) { - printf("Preferred format is USMARC\n"); - recordsyntax = VAL_USMARC; - return 1; + printf("Preferred format is USMARC\n"); + recordsyntax = VAL_USMARC; + return 1; } else if (!strcmp(arg, "danmarc")) { - printf("Preferred format is DANMARC\n"); - recordsyntax = VAL_DANMARC; - return 1; + printf("Preferred format is DANMARC\n"); + recordsyntax = VAL_DANMARC; + return 1; + } + else if (!strcmp(arg, "ukmarc")) + { + printf("Preferred format is UKMARC\n"); + recordsyntax = VAL_UKMARC; + return 1; + } + else if (!strcmp(arg, "grs1")) + { + printf("Preferred format is GRS1\n"); + recordsyntax = VAL_GRS1; + return 1; + } + else if (!strcmp(arg, "soif")) + { + printf("Preferred format is SOIF\n"); + recordsyntax = VAL_SOIF; + return 1; + } + else if (!strcmp(arg, "summary")) + { + printf("Preferred format is Summary\n"); + recordsyntax = VAL_SUMMARY; + return 1; + } + else if (!strcmp(arg, "explain")) + { + printf("Preferred format is Explain\n"); + recordsyntax = VAL_EXPLAIN; + return 1; } else { - printf("Specify one of {sutrs,usmarc,danmarc}.\n"); + printf("Specify one of {sutrs,usmarc,danmarc,ukmarc,grs1,summary,explain}.\n"); + return 0; + } +} + +int cmd_elements(char *arg) +{ + static Z_ElementSetNames esn; + static char what[100]; + + if (!arg || !*arg) + { + printf("Usage: elements \n"); + return 0; + } + strcpy(what, arg); + esn.which = Z_ElementSetNames_generic; + esn.u.generic = what; + elementSetNames = &esn; + return 1; +} + +int cmd_attributeset(char *arg) +{ + char what[100]; + + if (!arg || !*arg) + { + printf("Usage: attributeset \n"); return 0; } + sscanf(arg, "%s", what); + if (p_query_attset (what)) + { + printf("Unknown attribute set name\n"); + return 0; + } + return 1; +} + +int cmd_querytype (char *arg) +{ + if (!strcmp (arg, "ccl")) + queryType = QueryType_CCL; + else if (!strcmp (arg, "prefix")) + queryType = QueryType_Prefix; +#if CCL2RPN + else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn")) + queryType = QueryType_CCL2RPN; +#endif + else + { + printf ("Querytype must be one of:\n"); + printf (" prefix - Prefix query\n"); + printf (" ccl - CCL query\n"); +#if CCL2RPN + printf (" ccl2rpn - CCL query converted to RPN\n"); +#endif + return 0; + } + return 1; +} + +int cmd_close(char *arg) +{ + Z_APDU *apdu = zget_APDU(out, Z_APDU_close); + Z_Close *req = apdu->u.close; + + *req->closeReason = Z_Close_finished; + send_apdu(apdu); + printf("Sent close request.\n"); + sent_close = 1; + return 2; } static void initialize(void) { -#ifdef RPN_QUERY -#ifndef PREFIX_QUERY +#if CCL2RPN FILE *inf; #endif -#endif if (!(out = odr_createmem(ODR_ENCODE)) || - !(in = odr_createmem(ODR_DECODE)) || - !(print = odr_createmem(ODR_PRINT))) + !(in = odr_createmem(ODR_DECODE)) || + !(print = odr_createmem(ODR_PRINT))) { - fprintf(stderr, "failed to allocate ODR streams\n"); - exit(1); + fprintf(stderr, "failed to allocate ODR streams\n"); + exit(1); } setvbuf(stdout, 0, _IONBF, 0); -#ifdef RPN_QUERY -#ifndef PREFIX_QUERY +#if CCL2RPN bibset = ccl_qual_mk (); inf = fopen ("default.bib", "r"); if (inf) { - ccl_qual_file (bibset, inf); - fclose (inf); + ccl_qual_file (bibset, inf); + fclose (inf); } #endif -#endif } -static int client(void) +static int client(int wait) { static struct { - char *cmd; - int (*fun)(char *arg); - char *ad; + char *cmd; + int (*fun)(char *arg); + char *ad; } cmd[] = { - {"open", cmd_open, "('tcp'|'osi')':'['/'][':']"}, - {"quit", cmd_quit, ""}, - {"find", cmd_find, ""}, - {"base", cmd_base, ""}, - {"show", cmd_show, "['+'<#RECS>]"}, - {"scan", cmd_scan, ""}, - {"authentication", cmd_authentication, ""}, - {"lslb", cmd_lslb, ""}, - {"ssub", cmd_ssub, ""}, - {"mspn", cmd_mspn, ""}, - {"status", cmd_status, ""}, - {"setnames", cmd_setnames, ""}, - {"cancel", cmd_cancel, ""}, - {"format", cmd_format, ""}, - {0,0} + {"open", cmd_open, "('tcp'|'osi')':'['/'][':']"}, + {"quit", cmd_quit, ""}, + {"find", cmd_find, ""}, + {"base", cmd_base, ""}, + {"show", cmd_show, "['+'<#recs>]"}, + {"scan", cmd_scan, ""}, + {"authentication", cmd_authentication, ""}, + {"lslb", cmd_lslb, ""}, + {"ssub", cmd_ssub, ""}, + {"mspn", cmd_mspn, ""}, + {"status", cmd_status, ""}, + {"setnames", cmd_setnames, ""}, + {"cancel", cmd_cancel, ""}, + {"format", cmd_format, ""}, + {"elements", cmd_elements, ""}, + {"close", cmd_close, ""}, + {"attributeset", cmd_attributeset, ""}, + {"querytype", cmd_querytype, ""}, + {0,0} }; char *netbuffer= 0; int netbufferlen = 0; @@ -798,113 +1190,130 @@ static int client(void) while (1) { - int res; - fd_set input; - char line[1024], word[1024], arg[1024]; - - FD_ZERO(&input); - FD_SET(0, &input); - if (conn) - FD_SET(cs_fileno(conn), &input); - if ((res = select(20, &input, 0, 0, 0)) < 0) - { - perror("select"); - exit(1); - } - if (!res) - continue; - if (FD_ISSET(0, &input)) - { - /* quick & dirty way to get a command line. */ - if (!gets(line)) - break; - if ((res = sscanf(line, "%s %[^;]", word, arg)) <= 0) - { - strcpy(word, last_cmd); - *arg = '\0'; - } - else if (res == 1) - *arg = 0; - strcpy(last_cmd, word); - for (i = 0; cmd[i].cmd; i++) - if (!strncmp(cmd[i].cmd, word, strlen(word))) - { - res = (*cmd[i].fun)(arg); - break; - } - if (!cmd[i].cmd) /* dump our help-screen */ + int res; +#ifdef USE_SELECT + fd_set input; +#endif + char line[1024], word[1024], arg[1024]; + +#ifdef USE_SELECT + FD_ZERO(&input); + FD_SET(0, &input); + if (conn) + FD_SET(cs_fileno(conn), &input); + if ((res = select(20, &input, 0, 0, 0)) < 0) + { + perror("select"); + exit(1); + } + if (!res) + continue; + if (!wait && FD_ISSET(0, &input)) +#else + if (!wait) +#endif + { + /* quick & dirty way to get a command line. */ + if (!gets(line)) + break; + if ((res = sscanf(line, "%s %[^;]", word, arg)) <= 0) + { + strcpy(word, last_cmd); + *arg = '\0'; + } + else if (res == 1) + *arg = 0; + strcpy(last_cmd, word); + for (i = 0; cmd[i].cmd; i++) + if (!strncmp(cmd[i].cmd, word, strlen(word))) + { + res = (*cmd[i].fun)(arg); + break; + } + if (!cmd[i].cmd) /* dump our help-screen */ + { + printf("Unknown command: %s.\n", word); + printf("Currently recognized commands:\n"); + for (i = 0; cmd[i].cmd; i++) + printf(" %s %s\n", cmd[i].cmd, cmd[i].ad); + res = 1; + } + if (res < 2) { - printf("Unknown command: %s.\n", word); - printf("Currently recognized commands:\n"); - for (i = 0; cmd[i].cmd; i++) - printf(" %s %s\n", cmd[i].cmd, cmd[i].ad); - res = 1; + printf(C_PROMPT); + continue; } - if (res < 2) - printf(C_PROMPT); - } - if (conn && FD_ISSET(cs_fileno(conn), &input)) - { - do - { - if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) - { - perror("cs_get"); - exit(1); - } - if (!res) - { - printf("Target closed connection.\n"); - exit(1); - } - odr_reset(in); /* release APDU from last round */ - odr_setbuf(in, netbuffer, res, 0); - if (!z_APDU(in, &apdu, 0)) - { - odr_perror(in, "Decoding incoming APDU"); - fprintf(stderr, "Packet dump:\n---------\n"); - odr_dumpBER(stderr, netbuffer, res); - fprintf(stderr, "---------\n"); - exit(1); - } + } +#ifdef USE_SELECT + if (conn && FD_ISSET(cs_fileno(conn), &input)) +#endif + { + do + { + if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) + { + perror("cs_get"); + exit(1); + } + if (!res) + { + printf("Target closed connection.\n"); + exit(1); + } + odr_reset(in); /* release APDU from last round */ + odr_setbuf(in, netbuffer, res, 0); + if (!z_APDU(in, &apdu, 0)) + { + odr_perror(in, "Decoding incoming APDU"); + fprintf(stderr, "[Near %d]\n", odr_offset(in)); + fprintf(stderr, "Packet dump:\n---------\n"); + odr_dumpBER(stderr, netbuffer, res); + fprintf(stderr, "---------\n"); + exit(1); + } #if 0 - if (!z_APDU(print, &apdu, 0)) - { - odr_perror(print, "Failed to print incoming APDU"); - odr_reset(print); - continue; - } + if (!z_APDU(print, &apdu, 0)) + { + odr_perror(print, "Failed to print incoming APDU"); + odr_reset(print); + continue; + } #endif - switch(apdu->which) - { - case Z_APDU_initResponse: - process_initResponse(apdu->u.initResponse); - break; - case Z_APDU_searchResponse: - process_searchResponse(apdu->u.searchResponse); - break; - case Z_APDU_scanResponse: - process_scanResponse(apdu->u.scanResponse); - break; - case Z_APDU_presentResponse: - printf("Received presentResponse.\n"); - setno += - *apdu->u.presentResponse->numberOfRecordsReturned; - if (apdu->u.presentResponse->records) - display_records(apdu->u.presentResponse->records); - else - printf("No records.\n"); - break; - default: - printf("Received unknown APDU type (%d).\n", - apdu->which); - exit(1); - } - printf("Z> "); - fflush(stdout); - } - while (cs_more(conn)); - } + switch(apdu->which) + { + case Z_APDU_initResponse: + process_initResponse(apdu->u.initResponse); + break; + case Z_APDU_searchResponse: + process_searchResponse(apdu->u.searchResponse); + break; + case Z_APDU_scanResponse: + process_scanResponse(apdu->u.scanResponse); + break; + case Z_APDU_presentResponse: + printf("Received presentResponse.\n"); + setno += + *apdu->u.presentResponse->numberOfRecordsReturned; + if (apdu->u.presentResponse->records) + display_records(apdu->u.presentResponse->records); + else + printf("No records.\n"); + break; + case Z_APDU_close: + printf("Target has closed the association.\n"); + process_close(apdu->u.close); + break; + default: + printf("Received unknown APDU type (%d).\n", + apdu->which); + exit(1); + } + printf(C_PROMPT); + fflush(stdout); + } + while (cs_more(conn)); + } + wait = 0; } return 0; } @@ -912,9 +1321,15 @@ static int client(void) int main(int argc, char **argv) { initialize(); + cmd_base("Default"); if (argc > 1) - cmd_open(argv[1]); + cmd_open(argv[1]); else - printf(C_PROMPT); - return client(); + printf(C_PROMPT); + if (*marcdump_file && !(marcdump = fopen(marcdump_file, "a"))) + { + perror(marcdump_file); + exit(1); + } + return client((argc > 1)); }