/* * Copyright (c) 1995-2000, Index Data * See the file LICENSE for details. * Sebastian Hammer, Adam Dickmeiss * * $Log$ * Revision 1.1 2000/08/03 03:10:01 johnmcp * Added the YAZ toolkit source to the packages directory (for z39.50 stuff) * * Revision 1.1.2.1 2000/05/24 23:24:29 johnmcp * added some of the YAZ toolkit code for z39.50 client. * * Revision 1.95 2000/02/28 11:20:05 adam * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL. * */ /* Modified for the GreenStone Digital Library project - johnmcp */ #include #include #include #include /* for isdigit() */ #include /* don't need functions from here, maybe only the other header files: function atoi_n needed by marc_display() #include #include #include #include #include #include #include #include */ #include #include #include /* only defines marc_display[_ex] (), which could be inline. May need yaz/yconfig.h header file */ #include #include #include #ifdef ASN_COMPILED #include #endif #if HAVE_READLINE_READLINE_H #include #endif #if HAVE_READLINE_HISTORY_H #include #endif #define C_PROMPT "Z> " static ODR out, in, print; /* encoding and decoding streams */ static FILE *apdu_file = 0; static COMSTACK conn = 0; /* our z-association */ static Z_IdAuthentication *auth = 0; /* our current auth definition */ static char *databaseNames[128]; static Z_External *record_last = 0; 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 enum oid_proto protocol = PROTO_Z3950; /* current app protocol */ static enum oid_value recordsyntax = VAL_USMARC; static enum oid_value schema = VAL_NONE; static int sent_close = 0; static NMEM session_mem = NULL; /* memory handle for init-response */ static Z_InitResponse *session = 0; /* session parameters */ static char last_scan[512] = "0"; static FILE *marcdump = 0; static char *refid = NULL; /*johnmcp*/ Z_InitResponse *z_initresponse; typedef enum { QueryType_Prefix, QueryType_CCL, QueryType_CCL2RPN } QueryType; static QueryType queryType = QueryType_Prefix; /*static QueryType queryType = QueryType_CCL;*/ static void send_apdu(Z_APDU *a) { char *buf; int len; if (!z_APDU(out, &a, 0, 0)) { odr_perror(out, "Encoding APDU"); exit(1); } if (apdu_file) { z_APDU(print, &a, 0, 0); odr_reset(print); } buf = odr_getbuf(out, &len, 0); /* printf ("sending APDU of size %d\n", len); */ if (cs_put(conn, buf, len) < 0) { fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn))); exit(1); } odr_reset(out); /* release the APDU structure */ } static void print_refid (Z_ReferenceId *id) { if (id) { printf ("ReferenceId: '%.*s'\n", id->len, id->buf); } } static Z_ReferenceId *set_refid (ODR out) { Z_ReferenceId *id; if (!refid) return 0; id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id)); id->size = id->len = strlen(refid); id->buf = (unsigned char *) odr_malloc (out, id->len); memcpy (id->buf, refid, id->len); return id; } /* INIT SERVICE ------------------------------- */ static void send_initRequest() { Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest); Z_InitRequest *req = apdu->u.initRequest; ODR_MASK_SET(req->options, Z_Options_search); ODR_MASK_SET(req->options, Z_Options_present); ODR_MASK_SET(req->options, Z_Options_namedResultSets); ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl); ODR_MASK_SET(req->options, Z_Options_scan); ODR_MASK_SET(req->options, Z_Options_sort); ODR_MASK_SET(req->options, Z_Options_extendedServices); ODR_MASK_SET(req->options, Z_Options_delSet); 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->preferredMessageSize = 1024*1024; req->idAuthentication = auth; send_apdu(apdu); } char *z_get_initResponse() { char *buffer; size_t needed_length; char *text_id="ID: "; char *text_name="
\nName: "; char *text_ver="
\nVersion: "; int counter; buffer=NULL; /* save session parameters for later use */ /* session_mem = odr_extract_mem(in); session = res; */ if (!*session->result) return NULL; /* work out total string length needed. Note strlen(NULL) is a bad thing to do. */ needed_length=strlen(text_id)+strlen(text_name)+strlen(text_ver)+ (session->implementationId?strlen(session->implementationId):0) + (session->implementationName?strlen(session->implementationName):0) + (session->implementationVersion?strlen(session->implementationVersion) :0) + (session->userInformationField? strlen(session->userInformationField->u.octet_aligned->buf):0) + 1 /* for null char */ ; if ((buffer=malloc((sizeof(char *)) * needed_length))==NULL) { fprintf(stderr,"Malloc failed while initialising z39.50 server\n"); return (NULL); } /* can't pass NULL to sprintf as a (char *) */ sprintf(buffer,"%s%s%s%s%s%s", session->implementationId?text_id:"", session->implementationId?session->implementationId:"", session->implementationName?text_name:"", session->implementationName?session->implementationName:"", session->implementationVersion?text_ver:"", session->implementationVersion?session->implementationVersion:"" ); /* if version 3, also check the other-information parameter of the response. (But check version is 3 first) */ if (session->otherInfo) /**** From prt-proto.h *********** (comment added by johnmcp) typedef struct Z_OtherInformationUnit . { Z_InfoCategory *category; / * OPTIONAL * / . int which; #define Z_OtherInfo_characterInfo 0 #define Z_OtherInfo_binaryInfo 1 #define Z_OtherInfo_externallyDefinedInfo 2 #define Z_OtherInfo_oid 3 . union . { . char *characterInfo; . Odr_oct *binaryInfo; . Z_External *externallyDefinedInfo; . Odr_oid *oid; . } information; . } Z_OtherInformationUnit; typedef struct Z_OtherInformation { int num_elements; Z_OtherInformationUnit **list; } Z_OtherInformation; ************/ for (counter=0;counterotherInfo->num_elements;counter++) if (session->otherInfo->list[counter]->which == Z_OtherInfo_characterInfo) { /* add this extra string to our buffer */ int where=strlen(buffer); buffer=realloc(buffer,where+ strlen(session->otherInfo->list[counter]-> information.characterInfo)); strcpy(buffer+where, session->otherInfo->list[counter]-> information.characterInfo); } return (buffer); } static int cmd_base(char *arg) { int i; char *cp; if (!*arg) { printf("Usage: base ...\n"); return 0; } for (i = 0; inum_triples; i++) { printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass, *v->triples[i]->type); if (v->triples[i]->which == Z_Triple_internationalString) printf(",value=%s\n", v->triples[i]->value.internationalString); else printf("\n"); } } static void display_grs1(Z_GenericRecord *r, int level) { int i; if (!r) return; for (i = 0; i < r->num_elements; i++) { 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 ((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) { 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); } } } } static void print_record(const unsigned char *buf, size_t len) { size_t i; for (i = 0; i= 32) || strchr ("\n\r\t\f", buf[i])) fputc (buf[i], stdout); else printf ("\\X%02X", buf[i]); /* add newline if not already added ... */ if (i <= 0 || buf[i-1] != '\n') fputc ('\n', stdout); } static void display_record(Z_DatabaseRecord *p) { Z_External *r = (Z_External*) p; oident *ent = oid_getentbyoid(r->direct_reference); record_last = r; /* * 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, 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) { /* * 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, (char **)&rr, 0, 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 = (Z_SUTRS *) rr; /* we don't actually check the type here. */ r->which = type->what; } } if (ent && ent->value == VAL_SOIF) print_record((const unsigned char *) r->u.octet_aligned->buf, r->u.octet_aligned->len); else if (r->which == Z_External_octet && p->u.octet_aligned->len) { /* johnmcp - this is called for USmarc for demo server, at least */ const char *octet_buf = (char*)p->u.octet_aligned->buf; if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML || ent->value == VAL_HTML) print_record((const unsigned char *) octet_buf, p->u.octet_aligned->len); else { /* johnmcp - here marc_display does the work */ if (marc_display (octet_buf, NULL) <= 0) { printf ("ISO2709 decoding failed, dumping record as is:\n"); print_record((const unsigned char*) octet_buf, p->u.octet_aligned->len); } } if (marcdump) /*here (false) */ fwrite (octet_buf, 1, p->u.octet_aligned->len, marcdump); } else if (ent && ent->value == VAL_SUTRS) { if (r->which != Z_External_sutrs) { printf("Expecting single SUTRS type for SUTRS.\n"); return; } print_record(r->u.sutrs->buf, r->u.sutrs->len); } else if (ent && 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 (!z_External(print, &r, 0, 0)) { odr_perror(print, "Printing external"); odr_reset(print); } } } static void display_diagrecs(Z_DiagRec **pp, int num) { int i; oident *ent; Z_DefaultDiagFormat *r; printf("Diagnostic message(s) from database:\n"); for (i = 0; iwhich != Z_DiagRec_defaultFormat) { printf("Diagnostic record not in default format.\n"); return; } else r = p->u.defaultFormat; if (!(ent = oid_getentbyoid(r->diagnosticSetId)) || ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1) printf("Missing or unknown diagset\n"); printf(" [%d] %s", *r->condition, diagbib1_str(*r->condition)); #ifdef ASN_COMPILED switch (r->which) { case Z_DefaultDiagFormat_v2Addinfo: printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo); break; case Z_DefaultDiagFormat_v3Addinfo: printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo); break; } #else if (r->addinfo && *r->addinfo) printf(" -- '%s'\n", r->addinfo); else printf("\n"); #endif } } static void display_nameplusrecord(Z_NamePlusRecord *p) { if (p->databaseName) printf("[%s]", p->databaseName); if (p->which == Z_NamePlusRecord_surrogateDiagnostic) display_diagrecs(&p->u.surrogateDiagnostic, 1); else if (p->which == Z_NamePlusRecord_databaseRecord) display_record(p->u.databaseRecord); } static void display_records(Z_Records *p) { int i; if (p->which == Z_Records_NSD) { #ifdef ASN_COMPILED Z_DiagRec dr, *dr_p = &dr; dr.which = Z_DiagRec_defaultFormat; dr.u.defaultFormat = p->u.nonSurrogateDiagnostic; display_diagrecs (&dr_p, 1); #else display_diagrecs (&p->u.nonSurrogateDiagnostic, 1); #endif } else if (p->which == Z_Records_multipleNSD) display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs, p->u.multipleNonSurDiagnostics->num_diagRecs); 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]); } } static int send_searchRequest(char *arg) { Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest); Z_SearchRequest *req = apdu->u.searchRequest; Z_Query query; int oid[OID_SIZE]; char setstring[100]; Z_RPNQuery *RPNquery; /* Odr_oct ccl_query; */ req->referenceId = set_refid (out); 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; } if (setnumber >= 0) { sprintf(setstring, "%d", ++setnumber); req->resultSetName = setstring; } *req->smallSetUpperBound = smallSetUpperBound; *req->largeSetLowerBound = largeSetLowerBound; *req->mediumSetPresentNumber = mediumSetPresentNumber; if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 && mediumSetPresentNumber > 0)) { oident prefsyn; prefsyn.proto = protocol; prefsyn.oclass = CLASS_RECSYN; prefsyn.value = recordsyntax; req->preferredRecordSyntax = odr_oiddup(out, oid_ent_to_oid(&prefsyn, oid)); req->smallSetElementSetNames = req->mediumSetElementSetNames = elementSetNames; } req->num_databaseNames = num_databaseNames; req->databaseNames = databaseNames; req->query = &query; /* johnmcp - this is where we choose our query format. either ccl or rpn */ /* switch (queryType) { case QueryType_Prefix: */ query.which = Z_Query_type_1; RPNquery = p_query_rpn (out, protocol, arg); if (!RPNquery) { printf("Prefix query error\n"); return (-1); } 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; default: printf ("Unsupported query type\n"); return 0; }*/ send_apdu(apdu); setno = 1; /* printf("Sent searchRequest.\n"); */ return 0; } static int process_searchResponse(Z_SearchResponse *res) { print_refid (res->referenceId); if (!(*res->searchStatus)) { /* this should return an error instead of 0 docs found... one day... */ return 0; } setno += *res->numberOfRecordsReturned; if (res->records) display_records(res->records); return *res->resultCount; } static void print_level(int iLevel) { int i; for (i = 0; i < iLevel * 4; i++) printf(" "); } static void print_int(int iLevel, const char *pTag, int *pInt) { if (pInt != NULL) { print_level(iLevel); printf("%s: %d\n", pTag, *pInt); } } static void print_string(int iLevel, const char *pTag, const char *pString) { if (pString != NULL) { print_level(iLevel); printf("%s: %s\n", pTag, pString); } } static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid) { if (pOid != NULL) { int *pInt = pOid; print_level(iLevel); printf("%s:", pTag); for (; *pInt != -1; pInt++) printf(" %d", *pInt); printf("\n"); } } static void print_referenceId(int iLevel, Z_ReferenceId *referenceId) { if (referenceId != NULL) { int i; print_level(iLevel); printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size); for (i = 0; i < referenceId->len; i++) printf("%c", referenceId->buf[i]); printf("\n"); } } static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric) { if (pStringNumeric != NULL) { switch (pStringNumeric->which) { case Z_StringOrNumeric_string: print_string(iLevel, pTag, pStringNumeric->u.string); break; case Z_StringOrNumeric_numeric: print_int(iLevel, pTag, pStringNumeric->u.numeric); break; default: print_level(iLevel); printf("%s: valid type for Z_StringOrNumeric\n", pTag); break; } } } static void print_universe_report_duplicate(int iLevel, Z_UniverseReportDuplicate *pUniverseReportDuplicate) { if (pUniverseReportDuplicate != NULL) { print_level(iLevel); printf("Universe Report Duplicate: \n"); iLevel++; print_string_or_numeric(iLevel, "Hit No", pUniverseReportDuplicate->hitno); } } static void print_universe_report_hits(int iLevel, Z_UniverseReportHits *pUniverseReportHits) { if (pUniverseReportHits != NULL) { print_level(iLevel); printf("Universe Report Hits: \n"); iLevel++; print_string_or_numeric(iLevel, "Database", pUniverseReportHits->database); print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits); } } static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport) { if (pUniverseReport != NULL) { print_level(iLevel); printf("Universe Report: \n"); iLevel++; print_int(iLevel, "Total Hits", pUniverseReport->totalHits); switch (pUniverseReport->which) { case Z_UniverseReport_databaseHits: print_universe_report_hits(iLevel, pUniverseReport->u.databaseHits); break; case Z_UniverseReport_duplicate: print_universe_report_duplicate(iLevel, pUniverseReport->u.duplicate); break; default: print_level(iLevel); printf("Type: %d\n", pUniverseReport->which); break; } } } static void print_external(int iLevel, Z_External *pExternal) { if (pExternal != NULL) { print_level(iLevel); printf("External: \n"); iLevel++; print_oid(iLevel, "Direct Reference", pExternal->direct_reference); print_int(iLevel, "InDirect Reference", pExternal->indirect_reference); print_string(iLevel, "Descriptor", pExternal->descriptor); switch (pExternal->which) { case Z_External_universeReport: print_universe_report(iLevel, pExternal->u.universeReport); break; default: print_level(iLevel); printf("Type: %d\n", pExternal->which); break; } } } static int process_resourceControlRequest (Z_ResourceControlRequest *req) { printf ("Received ResourceControlRequest.\n"); print_referenceId(1, req->referenceId); print_int(1, "Suspended Flag", req->suspendedFlag); print_int(1, "Partial Results Available", req->partialResultsAvailable); print_int(1, "Response Required", req->responseRequired); print_int(1, "Triggered Request Flag", req->triggeredRequestFlag); print_external(1, req->resourceReport); return 0; } void process_ESResponse(Z_ExtendedServicesResponse *res) { printf("process_ESResponse status="); switch (*res->operationStatus) { case Z_ExtendedServicesResponse_done: printf ("done\n"); break; case Z_ExtendedServicesResponse_accepted: printf ("accepted\n"); break; case Z_ExtendedServicesResponse_failure: printf ("failure\n"); display_diagrecs(res->diagnostics, res->num_diagnostics); break; } } #ifdef ASN_COMPILED const char *get_ill_element (void *clientData, const char *element) { if (!strcmp (element, "ill,transaction-id,transaction-group-qualifier")) return "1"; if (!strcmp (element, "ill,transaction-id,transaction-qualifier")) return "1"; return 0; } #endif /* PRESENT SERVICE ----------------------------- */ static int z_send_getbriefrecords(int starting, int set, int howmany) { Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest); Z_PresentRequest *req = apdu->u.presentRequest; Z_RecordComposition compo; oident prefsyn; int nos = 1; int oid[OID_SIZE]; /* char *p;*/ char setstring[100]; req->referenceId = set_refid (out); nos = howmany; setno = starting; setnumber=1; sprintf(setstring, "%d", setnumber); req->resultSetId = setstring; req->resultSetStartPoint = &setno; req->numberOfRecordsRequested = &nos; prefsyn.proto = protocol; prefsyn.oclass = CLASS_RECSYN; prefsyn.value = recordsyntax; req->preferredRecordSyntax = odr_oiddup (out, oid_ent_to_oid(&prefsyn, oid)); if (schema != VAL_NONE) { oident prefschema; prefschema.proto = protocol; prefschema.oclass = CLASS_SCHEMA; prefschema.value = schema; req->recordComposition = &compo; compo.which = Z_RecordComp_complex; compo.u.complex = (Z_CompSpec *) odr_malloc(out, sizeof(*compo.u.complex)); compo.u.complex->selectAlternativeSyntax = (bool_t *) odr_malloc(out, sizeof(bool_t)); *compo.u.complex->selectAlternativeSyntax = 0; compo.u.complex->generic = (Z_Specification *) odr_malloc(out, sizeof(*compo.u.complex->generic)); compo.u.complex->generic->schema = (Odr_oid *) odr_oiddup(out, oid_ent_to_oid(&prefschema, oid)); if (!compo.u.complex->generic->schema) { /* OID wasn't a schema! Try record syntax instead. */ prefschema.oclass = CLASS_RECSYN; compo.u.complex->generic->schema = (Odr_oid *) odr_oiddup(out, oid_ent_to_oid(&prefschema, oid)); } if (!elementSetNames) compo.u.complex->generic->elementSpec = 0; else { compo.u.complex->generic->elementSpec = (Z_ElementSpec *) odr_malloc(out, sizeof(Z_ElementSpec)); compo.u.complex->generic->elementSpec->which = Z_ElementSpec_elementSetName; compo.u.complex->generic->elementSpec->u.elementSetName = elementSetNames->u.generic; } compo.u.complex->num_dbSpecific = 0; compo.u.complex->dbSpecific = 0; compo.u.complex->num_recordSyntax = 0; compo.u.complex->recordSyntax = 0; } else if (elementSetNames) { req->recordComposition = &compo; compo.which = Z_RecordComp_simple; compo.u.simple = elementSetNames; } send_apdu(apdu); return 0; } 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) { cs_close (conn); conn = NULL; if (session_mem) { nmem_destroy (session_mem); session_mem = NULL; } sent_close = 0; } else { *res->closeReason = Z_Close_finished; send_apdu(apdu); printf("Sent response.\n"); sent_close = 1; } } int cmd_quit(char *arg) { printf("See you later, alligator.\n"); exit(0); return 0; } int cmd_cancel(char *arg) { Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest); Z_TriggerResourceControlRequest *req = apdu->u.triggerResourceControlRequest; bool_t rfalse = 0; if (!conn) { 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; } *req->requestedAction = Z_TriggerResourceCtrl_cancel; req->resultSetWanted = &rfalse; send_apdu(apdu); printf("Sent cancel request\n"); return 2; } int send_scanrequest(char *string, int pp, int num) { Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest); Z_ScanRequest *req = apdu->u.scanRequest; if (!(req->termListAndStartPoint = p_query_scan(out, protocol, &req->attributeSet, string))) { printf("Prefix query error\n"); return -1; } req->referenceId = set_refid (out); req->num_databaseNames = num_databaseNames; req->databaseNames = databaseNames; req->numberOfTermsRequested = # req->preferredPositionInResponse = &pp; send_apdu(apdu); return 2; } int send_sortrequest(char *arg, int newset) { Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest); Z_SortRequest *req = apdu->u.sortRequest; Z_SortKeySpecList *sksl = (Z_SortKeySpecList *) odr_malloc (out, sizeof(*sksl)); char setstring[32]; char sort_string[32], sort_flags[32]; int off; int oid[OID_SIZE]; oident bib1; if (setnumber >= 0) sprintf (setstring, "%d", setnumber); else sprintf (setstring, "default"); req->referenceId = set_refid (out); #ifdef ASN_COMPILED req->num_inputResultSetNames = 1; req->inputResultSetNames = (Z_InternationalString **) odr_malloc (out, sizeof(*req->inputResultSetNames)); req->inputResultSetNames[0] = odr_strdup (out, setstring); #else req->inputResultSetNames = (Z_StringList *)odr_malloc (out, sizeof(*req->inputResultSetNames)); req->inputResultSetNames->num_strings = 1; req->inputResultSetNames->strings = (char **)odr_malloc (out, sizeof(*req->inputResultSetNames->strings)); req->inputResultSetNames->strings[0] = odr_strdup (out, setstring); #endif if (newset && setnumber >= 0) sprintf (setstring, "%d", ++setnumber); req->sortedResultSetName = odr_strdup (out, setstring); req->sortSequence = sksl; sksl->num_specs = 0; sksl->specs = (Z_SortKeySpec **)odr_malloc (out, sizeof(sksl->specs) * 20); bib1.proto = protocol; bib1.oclass = CLASS_ATTSET; bib1.value = VAL_BIB1; while ((sscanf (arg, "%31s %31s%n", sort_string, sort_flags, &off)) == 2 && off > 1) { int i; char *sort_string_sep; Z_SortKeySpec *sks = (Z_SortKeySpec *)odr_malloc (out, sizeof(*sks)); Z_SortKey *sk = (Z_SortKey *)odr_malloc (out, sizeof(*sk)); arg += off; sksl->specs[sksl->num_specs++] = sks; sks->sortElement = (Z_SortElement *)odr_malloc (out, sizeof(*sks->sortElement)); sks->sortElement->which = Z_SortElement_generic; sks->sortElement->u.generic = sk; if ((sort_string_sep = strchr (sort_string, '='))) { Z_AttributeElement *el = (Z_AttributeElement *)odr_malloc (out, sizeof(*el)); sk->which = Z_SortKey_sortAttributes; sk->u.sortAttributes = (Z_SortAttributes *)odr_malloc (out, sizeof(*sk->u.sortAttributes)); sk->u.sortAttributes->id = oid_ent_to_oid(&bib1, oid); sk->u.sortAttributes->list = (Z_AttributeList *)odr_malloc (out, sizeof(*sk->u.sortAttributes->list)); sk->u.sortAttributes->list->num_attributes = 1; sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)odr_malloc (out, sizeof(*sk->u.sortAttributes->list->attributes)); sk->u.sortAttributes->list->attributes[0] = el; el->attributeSet = 0; el->attributeType = (int *)odr_malloc (out, sizeof(*el->attributeType)); *el->attributeType = atoi (sort_string); el->which = Z_AttributeValue_numeric; el->value.numeric = (int *)odr_malloc (out, sizeof(*el->value.numeric)); *el->value.numeric = atoi (sort_string_sep + 1); } else { sk->which = Z_SortKey_sortField; sk->u.sortField = odr_strdup (out, sort_string); } sks->sortRelation = (int *)odr_malloc (out, sizeof(*sks->sortRelation)); *sks->sortRelation = Z_SortRelation_ascending; sks->caseSensitivity = (int *)odr_malloc (out, sizeof(*sks->caseSensitivity)); *sks->caseSensitivity = Z_SortCase_caseSensitive; #ifdef ASN_COMPILED sks->which = Z_SortKeySpec_null; sks->u.null = odr_nullval (); #else sks->missingValueAction = NULL; #endif for (i = 0; sort_flags[i]; i++) { switch (sort_flags[i]) { case 'a': case 'A': case '>': *sks->sortRelation = Z_SortRelation_descending; break; case 'd': case 'D': case '<': *sks->sortRelation = Z_SortRelation_ascending; break; case 'i': case 'I': *sks->caseSensitivity = Z_SortCase_caseInsensitive; break; case 'S': case 's': *sks->caseSensitivity = Z_SortCase_caseSensitive; break; } } } if (!sksl->num_specs) { printf ("Missing sort specifications\n"); return -1; } send_apdu(apdu); return 2; } 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); } else printf("Term type not general.\n"); } void process_scanResponse(Z_ScanResponse *res) { int i; Z_Entry **entries = NULL; int num_entries = 0; printf("Received ScanResponse\n"); print_refid (res->referenceId); printf("%d entries", *res->numberOfEntriesReturned); if (res->positionOfTerm) printf (", position=%d", *res->positionOfTerm); printf ("\n"); if (*res->scanStatus != Z_Scan_success) printf("Scan returned code %d\n", *res->scanStatus); if (!res->entries) return; if ((entries = res->entries->entries)) num_entries = res->entries->num_entries; for (i = 0; i < num_entries; i++) { int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1; if (entries[i]->which == Z_Entry_termInfo) { printf("%c ", i + 1 == pos_term ? '*' : ' '); display_term(entries[i]->u.termInfo); } else display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1); } if (res->entries->nonsurrogateDiagnostics) display_diagrecs (res->entries->nonsurrogateDiagnostics, res->entries->num_nonsurrogateDiagnostics); } void process_sortResponse(Z_SortResponse *res) { printf("Received SortResponse: status="); switch (*res->sortStatus) { case Z_SortStatus_success: printf ("success"); break; case Z_SortStatus_partial_1: printf ("partial"); break; case Z_SortStatus_failure: printf ("failure"); break; default: printf ("unknown (%d)", *res->sortStatus); } printf ("\n"); print_refid (res->referenceId); #ifdef ASN_COMPILED if (res->diagnostics) display_diagrecs(res->diagnostics, res->num_diagnostics); #else if (res->diagnostics) display_diagrecs(res->diagnostics->diagRecs, res->diagnostics->num_diagRecs); #endif } void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res) { printf("Got deleteResultSetResponse status=%d\n", *res->deleteOperationStatus); if (res->deleteListStatuses) { int i; for (i = 0; i < res->deleteListStatuses->num; i++) { printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id, *res->deleteListStatuses->elements[i]->status); } } } int cmd_sort_generic(char *arg, int newset) { if (!conn) { printf("Session not initialized yet\n"); return 0; } if (!ODR_MASK_GET(session->options, Z_Options_sort)) { printf("Target doesn't support sort\n"); return 0; } if (*arg) { if (send_sortrequest(arg, newset) < 0) return 0; return 2; } return 0; } int cmd_sort(char *arg) { return cmd_sort_generic (arg, 0); } int cmd_sort_newset (char *arg) { return cmd_sort_generic (arg, 1); } int cmd_scan(char *arg) { if (!conn) { 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; } if (*arg) { if (send_scanrequest(arg, 1, 20) < 0) return 0; } else if (send_scanrequest(last_scan, 1, 20) < 0) return 0; return 2; } int cmd_schema(char *arg) { if (!arg || !*arg) { schema = VAL_NONE; return 1; } schema = oid_getvalbyname (arg); if (schema == VAL_NONE) { printf ("unknown schema\n"); return 0; } return 1; } int cmd_format(char *arg) { if (!arg || !*arg) { printf("Usage: format \n"); return 0; } recordsyntax = oid_getvalbyname (arg); if (recordsyntax == VAL_NONE) { printf ("unknown record syntax\n"); return 0; } return 1; } int cmd_elements(char *arg) { static Z_ElementSetNames esn; static char what[100]; if (!arg || !*arg) { elementSetNames = 0; return 1; } 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") || !strcmp(arg, "rpn")) queryType = QueryType_Prefix; else { printf ("Querytype must be one of:\n"); printf (" prefix - Prefix query\n"); printf (" ccl - CCL query\n"); return 0; } return 1; } int cmd_refid (char *arg) { xfree (refid); refid = NULL; if (*arg) { refid = (char *) xmalloc (strlen(arg)+1); strcpy (refid, arg); } return 1; } int z_cmd_close(char *arg) { Z_APDU *apdu; Z_Close *req; if (!conn) return 1; apdu = zget_APDU(out, Z_APDU_close); req = apdu->u.close; *req->closeReason = Z_Close_finished; send_apdu(apdu); sent_close = 1; return 0; } void z_initialize(void) { nmem_init(); if (!(out = odr_createmem(ODR_ENCODE)) || !(in = odr_createmem(ODR_DECODE)) || !(print = odr_createmem(ODR_PRINT))) { fprintf(stderr, "failed to allocate ODR streams\n"); exit(1); } setvbuf(stdout, 0, _IONBF, 0); if (apdu_file) odr_setprint(print, apdu_file); cmd_base("Default"); } static int z_getAPDU (Z_APDU **ret_apdu) { int res; char *netbuffer= 0; int netbufferlen = 0; Z_APDU *apdu; 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 */ record_last = 0; odr_setbuf(in, netbuffer, res, 0); /* johnmcp */ if (!z_APDU(in, &apdu, 0, 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"); if (apdu_file) z_APDU(print, &apdu, 0, 0); exit(1); } if (apdu_file && !z_APDU(print, &apdu, 0, 0)) { odr_perror(print, "Failed to print incoming APDU"); odr_reset(print); return -1; /* was continue */ } (*ret_apdu)=apdu; return 0; } /* returns number found, arg is query string */ int z_cmd_dosearch(char *arg) { Z_APDU *apdu; int matching; int ret_val; ret_val=send_searchRequest(arg); if (ret_val==-1) { /* prefix query error */ return (-1); } z_getAPDU(&apdu); /* check return value??? */ if (apdu->which != Z_APDU_searchResponse) { printf("sendsearchRequest() was not replied with a searchResponse!\n"); return (-2); } /* let's keep going anyway... */ matching=process_searchResponse(apdu->u.searchResponse); /* this assumes we want to take action on failure (-1) here rather than whereever we were called from */ return (matching); } /* src must be NULL-terminated */ static char *safeappendstr(char *dest, size_t *allocsize, size_t *offset, char *src) { /* allocsize is the amount of space currently allocated to dest, offset is how far into dest we want to append src */ if (*offset + strlen(src) >= *allocsize) { *allocsize+=strlen(src)+64; /* add some extra space to save on reallocs */ if ((dest=realloc(dest,*allocsize))==NULL) { fprintf(stderr, "malloc failed while decoding marc record.\n"); return (NULL); } } strcpy(dest+(*offset), src); *offset+=strlen(src); return (dest); } static char *getmarcfields(Z_DatabaseRecord *p, int titleonly) { /* this code is based on marc_display(), with a couple of lines taken from display_record() in the original client. */ /* if titleonly is non-zero, we only get a (the?) title field, otherwise return the whole thing */ const char *buf=(char *)p->u.octet_aligned->buf; char *title; /* our string to return */ int title_maxlen=0; /* amount of space currently allocated */ int title_curlen=0; /* amount of space actually used */ int entry_p; int record_length; int indicator_length; int identifier_length; int base_address; int length_data_entry; int length_starting; int length_implementation; FILE *outf; /* if (!outf) */ outf = stdout; /* initialise our title. Start with 64 chars */ title_maxlen=64; if((title=malloc(title_maxlen))==NULL) { /* not quite sure where stderr will be going, but.... */ fprintf(stderr,"Malloc failed while decoding marc record\n"); return NULL; } if (!titleonly) { strcpy(title,"\n"); title_curlen=strlen(title); } else title_curlen=0; record_length = atoi_n (buf, 5); if (record_length < 25) return (NULL); /* -1 */ if (isdigit(buf[10])) indicator_length = atoi_n (buf+10, 1); else indicator_length = 2; if (isdigit(buf[11])) identifier_length = atoi_n (buf+11, 1); else identifier_length = 2; base_address = atoi_n (buf+12, 4); length_data_entry = atoi_n (buf+20, 1); length_starting = atoi_n (buf+21, 1); length_implementation = atoi_n (buf+22, 1); if (0) /* debug */ { fprintf (outf, "Record length %5d\n", record_length); fprintf (outf, "Indicator length %5d\n", indicator_length); fprintf (outf, "Identifier length %5d\n", identifier_length); fprintf (outf, "Base address %5d\n", base_address); fprintf (outf, "Length data entry %5d\n", length_data_entry); fprintf (outf, "Length starting %5d\n", length_starting); fprintf (outf, "Length implementation %5d\n", length_implementation); } for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) { entry_p += 3+length_data_entry+length_starting; if (entry_p >= record_length) return (NULL); /* -1 */ } base_address = entry_p+1; for (entry_p = 24; buf[entry_p] != ISO2709_FS; ) { int data_length; int data_offset; int end_offset; int i /*, j*/ ; int startofstring; int whichtag; short int abbrtitle=0; char tag[4]; memcpy (tag, buf+entry_p, 3); entry_p += 3; tag[3] = '\0'; whichtag=atoi(tag); if (0) /* debug */ fprintf (outf, "Tag: "); /* johnmcp Relevant tags (for "main entry") - assume only one of these is set, as we will only return the first one found. 100=personal name 110=corporate name 111=meeting name 130=uniform title subfields: $a=personal name, $c=title/other, $d=date 210=Abbreviated Title 222=Key title 240=uniform title 243=collective uniform title 245=title statement 246=varying form of title 247=former title or title variations subfields: $a=abbrev. title $b=qualifying info $2=source . $6=linkage $8=link field and sequence number. */ /*fprintf (outf, "%s ", tag); */ data_length = atoi_n (buf+entry_p, length_data_entry); entry_p += length_data_entry; data_offset = atoi_n (buf+entry_p, length_starting); entry_p += length_starting; i = data_offset + base_address; end_offset = i+data_length-1; if (0) /* debug */ fprintf (outf, " Ind: "); /* memcmp (tag,"00",2) is true, then we DON'T have a control tag ie less than 10. */ /*if (memcmp (tag, "00", 2) && indicator_length) { for (j = 0; j=10) i+=indicator_length; /* the control fields (<10) don't have leading chars. */ if (0) /* debug */ fprintf (outf, " Fields: "); /* If we only want the title, then skip other fields */ if (titleonly &&(whichtag<200||whichtag>249)) { /* skip this record */ continue; i=end_offset; } /* either titleonly is 0, or titleonly is 1 and whichtag is between 200 and 249... */ if (!titleonly) { /* print out what kind of tag this is */ char *tagname; char *field_control1="\n"); } } /* end of if (titleonly==0) */ } /* end of if ( ((titleonly==1&&....... */ else { /* whichtag not matched (if titleonly) */ /*fprintf (outf, "%c", buf[i++]);*/ /* skip this char for now - should ideally skip whole field */ i++; } } /* end of while loop - at end of field or record */ /*fprintf (outf, "\n");*/ /*if (i < end_offset) fprintf (outf, "-- separator but not at end of field\n"); if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS) fprintf (outf, "-- no separator at end of field\n"); */ } /* at end of whole record. */ if (!titleonly) title=safeappendstr(title, &title_maxlen, &title_curlen, "
Marc Control Number:"; char *field_control3="
Marc Organisation Code:"; char *field_control5="
Marc record Date Info.:"; char *field_control8="
Control Field (Marc info):"; char *field_loc_nr="
Lib. of Congress control #:"; char *field_issn="
ISSN Number:"; char *field_catalog="
Catalog agency:"; char *field_lang="
3-letter language code(s):"; char *field_areacode="
Geographic Area code:"; char *field_cn_loc="
Lib. of Congress Call #:"; char *field_cn_dewdec="
Dewey Decimal Call #:"; char *field_cn_other="
Other Classification Info.:"; char *field_cn_gd="
Govt. Document Call #:"; char *field_personalname="
Personal Name:"; char *field_meetingname="
Meeting Name:"; char *field_maintitle="
Title:"; char *field_edition="
"; char *field_publication="
Publication Info.:"; char *field_physdesc="
Physical Description:"; char *field_series_title="
Series Title:"; char *field_series_statement="
Series Statement:"; char *field_note_general="
Note:"; char *field_note_bib="
Bibliographic Note:"; char *field_note_summary="
Summary Note:"; char *field_sub_note="
Subject Notes:"; char *field_sub_topic="
Subject - Topic:"; char *field_added_persname="
Author Note - Name:"; char *field_added_corpname="
Author - Organisation:"; char *field_uniform_title="
Extra Title Information:"; char *field_host_item="
In:"; char *field_series_corpname="
Series - Organisation:"; /*char *field_other="
(other field):";*/ char tag_num[100]; switch (whichtag) { case (1): {tagname=field_control1;break;} case (3): {tagname=field_control3;break;} case (5): {tagname=field_control5;break;} case (8): {tagname=field_control8;break;} case (10): {tagname=field_loc_nr;break;} case (20): {tagname=field_issn;break;} case (40): {tagname=field_catalog;break;} case (41): {tagname=field_lang;break;} case (43): {tagname=field_areacode;break;} case (50): {tagname=field_cn_loc;break;} case (82): {tagname=field_cn_dewdec;break;} case (84): {tagname=field_cn_other;break;} case (86): {tagname=field_cn_gd;break;} case (100): {tagname=field_personalname;break;} case (111): {tagname=field_meetingname;break;} case (245): {tagname=field_maintitle;break;} case (250): {tagname=field_edition;break;} case (260): {tagname=field_publication;break;} case (300): {tagname=field_physdesc;break;} case (440): {tagname=field_series_title;break;} case (490): {tagname=field_series_statement;break;} case (500): {tagname=field_note_general;break;} case (504): {tagname=field_note_bib;break;} case (520): {tagname=field_note_summary;break;} case (630): {tagname=field_sub_note;break;} case (650): {tagname=field_sub_topic;break;} case (700): {tagname=field_added_persname;break;} case (710): {tagname=field_added_corpname;break;} case (730): {tagname=field_uniform_title;break;} case (773): {tagname=field_host_item;break;} case (810): {tagname=field_series_corpname;break;} default: if (whichtag>=90&&whichtag<=99) tagname="
(obsolete field) Call #:"; else { /*tagname=field_other;*/ /*.*********** Following line "causes" (ie exposes) a seg fault in realloc(title,...). What is causing this????. ANSWER: The trailing '\0' needs to be explicit :-) */ sprintf(tag_num,"
(field %d)\n\0",whichtag); tagname=tag_num; } } /* add the field type */ title=safeappendstr(title, &title_maxlen, &title_curlen, tagname); } /* go through current field in current record */ while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset) { /* this loop goes through byte by byte, to find end-of-field or end-of-record separator tags */ /* if (memcmp (tag, "00", 2) && identifier_length)*/ if ( ((titleonly==1&&whichtag==245)||(titleonly==0)) && identifier_length) { if (buf[i]==ISO2709_IDFS) { /* this implies sub-fields for this field */ /* skip sub-field tag, but wrap $a sub-field with & for HTML if titleonly==1 */ if (buf[i+1]=='a' && titleonly) { abbrtitle=1; title=safeappendstr(title,&title_maxlen,&title_curlen,""); } i+=identifier_length; } /* find end of this (sub-)field */ startofstring=i; while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS && buf[i] != ISO2709_FS && i < end_offset) i++; /*fprintf (outf, "%c", buf[i++]);*/ /* this only happens the first time around */ if (i==startofstring) continue; /* now put from $startofstring$ until $i$ into our string to return */ if (title_curlen+(i-startofstring)>=title_maxlen) { /* we need to make more room - add max(64,needed) bytes */ if (title_curlen+(i-startofstring)-title_maxlen>63) title_maxlen+=(i-startofstring)+1;/*+1 for trailing \0 */ else title_maxlen+=64; if ((title=realloc(title,title_maxlen))==NULL) { fprintf(stderr,"malloc failed decoding marc record\n"); return (NULL); } } strncpy(title+title_curlen,buf+startofstring,i-startofstring); title_curlen+=(i-startofstring); *(title+title_curlen)='\0'; /* overwrite ISO2709_?S with \0 */ /* *(title+title_curlen+i-startofstring)='\0';*/ /*safeappendstr(title,&title_maxlen, &title_curlen,buf+startofstring);*/ /* if 'main' title, close HTML tag */ if (abbrtitle) { title=safeappendstr(title,&title_maxlen,&title_curlen,""); abbrtitle=0; } /* end of this marc sub--field buf[i]==ISO2709_RS if end of record. buf[i]==ISO2709_FS if end of field, buf[i]==ISO2709_IDFS if end of sub-field. */ if (titleonly==0) { if (buf[i]==ISO2709_IDFS) { /* there is a following sub-field, so only add whitespace */ title=safeappendstr(title,&title_maxlen,&title_curlen," "); } else { /* end of record, so close HTML table row */ title=safeappendstr(title, &title_maxlen, &title_curlen, "
\n"); return (title); } static char *getrecordtitle(Z_DatabaseRecord *record) { return(getmarcfields(record,1)); } char *z_getfullRecord(int start) { Z_APDU *apdu; Z_DatabaseRecord *record; char *fullrecord; fullrecord=NULL; z_send_getbriefrecords(start,1,1); /* for now, use getbriefrecords */ z_getAPDU(&apdu); if (apdu->which != Z_APDU_presentResponse) { /* out-of-order packets.... */ fprintf(stderr,"Not a present response to present request\n"); return NULL; } /* just do some double checking */ if (*apdu->u.presentResponse->numberOfRecordsReturned!=1 || !apdu->u.presentResponse->records || apdu->u.presentResponse->records->which!=Z_Records_DBOSD) { /* something bad has happened... johnmcp */ fprintf (stderr,"Error occured in yaz while getting record (GSDL)\n"); } record=apdu->u.presentResponse->records->u.databaseOrSurDiagnostics-> records[0]->u.databaseRecord; return(getmarcfields(record,0)); } char **z_getrecordTitles(/*int resultset,*/ int starting, int howmany) { Z_APDU *apdu; char **titles; /* titles will be an array of strings. The first element will really be an int, saying how many strings follow. Ie 1st string in titles[1] */ int count; int i; titles=NULL; /* WE SHOULD SET THE RECORD FORMAT SOMEWHERE..... USMARC (default) but may also want SUTRS support. */ /* sends a presentRequest - we need to know the set number - johnmcp */ z_send_getbriefrecords(starting, 1, howmany); /* CHECK RETURN VALUE (currently only 0) */ z_getAPDU(&apdu); if (apdu->which != Z_APDU_presentResponse) { /* we got out-of-sync.... */ fprintf(stderr,"Not a present response to present request\n"); return NULL; } print_refid (apdu->u.presentResponse->referenceId); count=*apdu->u.presentResponse->numberOfRecordsReturned; setno += count; if (apdu->u.presentResponse->records) { /* extract the titles from each record, and return it as an array of strings */ if (count==1 && apdu->u.presentResponse->records->which!=Z_Records_DBOSD) { /* apdu->u.presentResponse->records->which gives a type: 1=databaseOrSurDiagnostics | 2=nonSurrogateDiagnostic | 3=multipleNonSurDiagnostics. Type 1 implies it is a database record. FROM z-core.h, NOT prt-proto.h!!!!! */ /* for type 2: apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which: 1=v2Addinfo | 2=v3Addinfo, and u.v[23]Addinfo is a (char *). */ titles=malloc(sizeof(char *)); titles[0]=(char *)0; /* could put error message and titles[1], and set titles[0] to -1. */ } else /* more than 1 rec returned, so ?has? to be db records (dblcheck!!)*/ { titles=malloc(sizeof(char *)*count + 1); /* check malloc succeeded... */ titles[0]=(char *)count; for (i=1;i<=count;i++) { titles[i]=getrecordtitle(apdu->u.presentResponse->records-> u.databaseOrSurDiagnostics->records[i-1]-> u.databaseRecord); } } } else { titles=malloc(sizeof(char *)); titles[0]=(char *)0; } /* printf ("nextResultSetPosition = %d\n", *apdu->u.presentResponse->nextResultSetPosition); */ return (titles); } int z_getnextAPDU() { Z_APDU *apdu; apdu=NULL; z_getAPDU(&apdu); switch(apdu->which) { case Z_APDU_initResponse: /* save session parameters for later use */ session_mem = odr_extract_mem(in); session=apdu->u.initResponse; /*process_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: print_refid (apdu->u.presentResponse->referenceId); setno += *apdu->u.presentResponse->numberOfRecordsReturned; if (apdu->u.presentResponse->records) display_records(apdu->u.presentResponse->records); else printf("No records.\n"); printf ("nextResultSetPosition = %d\n", *apdu->u.presentResponse->nextResultSetPosition); break; case Z_APDU_sortResponse: process_sortResponse(apdu->u.sortResponse); break; case Z_APDU_extendedServicesResponse: printf("Got extended services response\n"); process_ESResponse(apdu->u.extendedServicesResponse); break; case Z_APDU_close: printf("Target has closed the association.\n"); process_close(apdu->u.close); break; case Z_APDU_resourceControlRequest: process_resourceControlRequest (apdu->u.resourceControlRequest); break; case Z_APDU_deleteResultSetResponse: process_deleteResultSetResponse(apdu->u. deleteResultSetResponse); break; default: printf("Received unknown APDU type (%d).\n", apdu->which); exit(1); } /*while (conn && cs_more(conn));*/ return 0; }