source: trunk/gsdl/packages/yaz/client/yaz_zclient.c@ 1343

Last change on this file since 1343 was 1343, checked in by johnmcp, 24 years ago

Added the YAZ toolkit source to the packages directory (for z39.50 stuff)

  • Property svn:keywords set to Author Date Id Revision
File size: 57.3 KB
Line 
1/*
2 * Copyright (c) 1995-2000, Index Data
3 * See the file LICENSE for details.
4 * Sebastian Hammer, Adam Dickmeiss
5 *
6 * $Log$
7 * Revision 1.1 2000/08/03 03:10:01 johnmcp
8 * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
9 *
10 * Revision 1.1.2.1 2000/05/24 23:24:29 johnmcp
11 * added some of the YAZ toolkit code for z39.50 client.
12 *
13 * Revision 1.95 2000/02/28 11:20:05 adam
14 * Using autoconf. New definitions: YAZ_BEGIN_CDECL/YAZ_END_CDECL.
15 *
16 */
17
18/* Modified for the GreenStone Digital Library project - johnmcp */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <ctype.h> /* for isdigit() */
24#include <time.h>
25
26/* don't need functions from here, maybe only the other header files:
27function atoi_n needed by marc_display()
28#include <yaz/yconfig.h>
29#include <yaz/xmalloc.h>
30#include <yaz/log.h>
31#include <yaz/tpath.h>
32#include <yaz/options.h>
33#include <yaz/wrbuf.h>
34#include <yaz/nmem.h>
35#include <yaz/readconf.h>
36*/
37#include <yaz/yaz-util.h>
38
39#include <yaz/tcpip.h>
40
41#include <yaz/proto.h>
42
43/* only defines marc_display[_ex] (), which could be inline. May need
44 yaz/yconfig.h header file */
45#include <yaz/marcdisp.h>
46#include <yaz/diagbib1.h>
47
48#include <yaz/pquery.h>
49
50#ifdef ASN_COMPILED
51#include <yaz/ill.h>
52#endif
53
54#if HAVE_READLINE_READLINE_H
55#include <readline/readline.h>
56#endif
57#if HAVE_READLINE_HISTORY_H
58#include <readline/history.h>
59#endif
60
61#define C_PROMPT "Z> "
62
63static ODR out, in, print; /* encoding and decoding streams */
64static FILE *apdu_file = 0;
65static COMSTACK conn = 0; /* our z-association */
66static Z_IdAuthentication *auth = 0; /* our current auth definition */
67static char *databaseNames[128];
68static Z_External *record_last = 0;
69static int num_databaseNames = 0;
70static int setnumber = 0; /* current result set number */
71static int smallSetUpperBound = 0;
72static int largeSetLowerBound = 1;
73static int mediumSetPresentNumber = 0;
74static Z_ElementSetNames *elementSetNames = 0;
75static int setno = 1; /* current set offset */
76static enum oid_proto protocol = PROTO_Z3950; /* current app protocol */
77static enum oid_value recordsyntax = VAL_USMARC;
78static enum oid_value schema = VAL_NONE;
79static int sent_close = 0;
80static NMEM session_mem = NULL; /* memory handle for init-response */
81static Z_InitResponse *session = 0; /* session parameters */
82static char last_scan[512] = "0";
83static FILE *marcdump = 0;
84static char *refid = NULL;
85/*johnmcp*/
86Z_InitResponse *z_initresponse;
87typedef enum {
88 QueryType_Prefix,
89 QueryType_CCL,
90 QueryType_CCL2RPN
91} QueryType;
92
93static QueryType queryType = QueryType_Prefix;
94/*static QueryType queryType = QueryType_CCL;*/
95
96static void send_apdu(Z_APDU *a)
97{
98 char *buf;
99 int len;
100
101 if (!z_APDU(out, &a, 0, 0))
102 {
103 odr_perror(out, "Encoding APDU");
104 exit(1);
105 }
106 if (apdu_file)
107 {
108 z_APDU(print, &a, 0, 0);
109 odr_reset(print);
110 }
111 buf = odr_getbuf(out, &len, 0);
112 /* printf ("sending APDU of size %d\n", len); */
113 if (cs_put(conn, buf, len) < 0)
114 {
115 fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
116 exit(1);
117 }
118 odr_reset(out); /* release the APDU structure */
119}
120
121static void print_refid (Z_ReferenceId *id)
122{
123 if (id)
124 {
125 printf ("ReferenceId: '%.*s'\n", id->len, id->buf);
126 }
127}
128
129static Z_ReferenceId *set_refid (ODR out)
130{
131 Z_ReferenceId *id;
132 if (!refid)
133 return 0;
134 id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
135 id->size = id->len = strlen(refid);
136 id->buf = (unsigned char *) odr_malloc (out, id->len);
137 memcpy (id->buf, refid, id->len);
138 return id;
139}
140
141/* INIT SERVICE ------------------------------- */
142
143static void send_initRequest()
144{
145 Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
146 Z_InitRequest *req = apdu->u.initRequest;
147
148 ODR_MASK_SET(req->options, Z_Options_search);
149 ODR_MASK_SET(req->options, Z_Options_present);
150 ODR_MASK_SET(req->options, Z_Options_namedResultSets);
151 ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl);
152 ODR_MASK_SET(req->options, Z_Options_scan);
153 ODR_MASK_SET(req->options, Z_Options_sort);
154 ODR_MASK_SET(req->options, Z_Options_extendedServices);
155 ODR_MASK_SET(req->options, Z_Options_delSet);
156
157 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
158 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
159 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
160
161 *req->maximumRecordSize = 1024*1024;
162 *req->preferredMessageSize = 1024*1024;
163
164 req->idAuthentication = auth;
165
166 send_apdu(apdu);
167}
168
169char *z_get_initResponse()
170{
171 char *buffer;
172 size_t needed_length;
173 char *text_id="ID: ";
174 char *text_name="<br>\nName: ";
175 char *text_ver="<br>\nVersion: ";
176 int counter;
177
178 buffer=NULL;
179 /* save session parameters for later use */
180 /* session_mem = odr_extract_mem(in);
181 session = res; */
182 if (!*session->result)
183 return NULL;
184
185 /* work out total string length needed. Note strlen(NULL) is a bad thing
186 to do. */
187 needed_length=strlen(text_id)+strlen(text_name)+strlen(text_ver)+
188 (session->implementationId?strlen(session->implementationId):0) +
189 (session->implementationName?strlen(session->implementationName):0) +
190 (session->implementationVersion?strlen(session->implementationVersion)
191 :0) +
192 (session->userInformationField?
193 strlen(session->userInformationField->u.octet_aligned->buf):0) +
194 1 /* for null char */ ;
195 if ((buffer=malloc((sizeof(char *)) * needed_length))==NULL) {
196 fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
197 return (NULL);
198 }
199 /* can't pass NULL to sprintf as a (char *) */
200 sprintf(buffer,"%s%s%s%s%s%s",
201 session->implementationId?text_id:"",
202 session->implementationId?session->implementationId:"",
203 session->implementationName?text_name:"",
204 session->implementationName?session->implementationName:"",
205 session->implementationVersion?text_ver:"",
206 session->implementationVersion?session->implementationVersion:""
207 );
208
209 /* if version 3, also check the other-information parameter of the
210 response. (But check version is 3 first) */
211 if (session->otherInfo)
212 /**** From prt-proto.h *********** (comment added by johnmcp)
213 typedef struct Z_OtherInformationUnit
214 . { Z_InfoCategory *category; / * OPTIONAL * /
215 . int which;
216 #define Z_OtherInfo_characterInfo 0
217 #define Z_OtherInfo_binaryInfo 1
218 #define Z_OtherInfo_externallyDefinedInfo 2
219 #define Z_OtherInfo_oid 3
220 . union
221 . {
222 . char *characterInfo;
223 . Odr_oct *binaryInfo;
224 . Z_External *externallyDefinedInfo;
225 . Odr_oid *oid;
226 . } information;
227 . } Z_OtherInformationUnit;
228
229 typedef struct Z_OtherInformation
230 {
231 int num_elements;
232 Z_OtherInformationUnit **list;
233 } Z_OtherInformation;
234 ************/
235 for (counter=0;counter<session->otherInfo->num_elements;counter++)
236 if (session->otherInfo->list[counter]->which ==
237 Z_OtherInfo_characterInfo)
238 {
239 /* add this extra string to our buffer */
240 int where=strlen(buffer);
241 buffer=realloc(buffer,where+
242 strlen(session->otherInfo->list[counter]->
243 information.characterInfo));
244 strcpy(buffer+where,
245 session->otherInfo->list[counter]->
246 information.characterInfo);
247 }
248 return (buffer);
249}
250
251static int cmd_base(char *arg)
252{
253 int i;
254 char *cp;
255
256 if (!*arg)
257 {
258 printf("Usage: base <database> <database> ...\n");
259 return 0;
260 }
261 for (i = 0; i<num_databaseNames; i++)
262 xfree (databaseNames[i]);
263 num_databaseNames = 0;
264 while (1)
265 {
266 if (!(cp = strchr(arg, ' ')))
267 cp = arg + strlen(arg);
268 if (cp - arg < 1)
269 break;
270 databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
271 memcpy (databaseNames[num_databaseNames], arg, cp - arg);
272 databaseNames[num_databaseNames++][cp - arg] = '\0';
273 if (!*cp)
274 break;
275 arg = cp+1;
276 }
277 return 1;
278}
279
280
281int z_cmd_open(char *host_and_port, char *base)
282{
283 void *add;
284 CS_TYPE t;
285
286 if (conn)
287 {
288 printf("Already connected.\n");
289
290 cs_close (conn);
291 conn = NULL;
292 if (session_mem)
293 {
294 nmem_destroy (session_mem);
295 session_mem = NULL;
296 }
297 }
298
299 cmd_base (base);
300 t = tcpip_type;
301 protocol = PROTO_Z3950;
302
303 if (!(conn = cs_create(t, 1, protocol)))
304 {
305 perror("cs_create");
306 return 1;
307 }
308 if (!(add = cs_straddr(conn, host_and_port)))
309 {
310 perror(host_and_port);
311 return 1;
312 }
313
314 if (cs_connect(conn, add) < 0)
315 {
316 perror("connect");
317 cs_close(conn);
318 conn = 0;
319 return 1;
320 }
321 /* if here, we connected OK */
322 send_initRequest();
323 return 0;
324}
325
326int cmd_authentication(char *arg)
327{
328 static Z_IdAuthentication au;
329 static char open[256];
330
331 if (!*arg)
332 {
333 printf("Auth field set to null\n");
334 auth = 0;
335 return 1;
336 }
337 auth = &au;
338 au.which = Z_IdAuthentication_open;
339 au.u.open = open;
340 strcpy(open, arg);
341 return 1;
342}
343
344/* SEARCH SERVICE ------------------------------ */
345
346static void display_variant(Z_Variant *v, int level)
347{
348 int i;
349
350 for (i = 0; i < v->num_triples; i++)
351 {
352 printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass,
353 *v->triples[i]->type);
354 if (v->triples[i]->which == Z_Triple_internationalString)
355 printf(",value=%s\n", v->triples[i]->value.internationalString);
356 else
357 printf("\n");
358 }
359}
360
361static void display_grs1(Z_GenericRecord *r, int level)
362{
363 int i;
364
365 if (!r)
366 return;
367 for (i = 0; i < r->num_elements; i++)
368 {
369 Z_TaggedElement *t;
370
371 printf("%*s", level * 4, "");
372 t = r->elements[i];
373 printf("(");
374 if (t->tagType)
375 printf("%d,", *t->tagType);
376 else
377 printf("?,");
378 if (t->tagValue->which == Z_StringOrNumeric_numeric)
379 printf("%d) ", *t->tagValue->u.numeric);
380 else
381 printf("%s) ", t->tagValue->u.string);
382 if (t->content->which == Z_ElementData_subtree)
383 {
384 printf("\n");
385 display_grs1(t->content->u.subtree, level+1);
386 }
387 else if (t->content->which == Z_ElementData_string)
388 printf("%s\n", t->content->u.string);
389 else if (t->content->which == Z_ElementData_numeric)
390 printf("%d\n", *t->content->u.numeric);
391 else if (t->content->which == Z_ElementData_oid)
392 {
393 int *ip = t->content->u.oid;
394 oident *oent;
395
396 if ((oent = oid_getentbyoid(t->content->u.oid)))
397 printf("OID: %s\n", oent->desc);
398 else
399 {
400 printf("{");
401 while (ip && *ip >= 0)
402 printf(" %d", *(ip++));
403 printf(" }\n");
404 }
405 }
406 else if (t->content->which == Z_ElementData_noDataRequested)
407 printf("[No data requested]\n");
408 else if (t->content->which == Z_ElementData_elementEmpty)
409 printf("[Element empty]\n");
410 else if (t->content->which == Z_ElementData_elementNotThere)
411 printf("[Element not there]\n");
412 else
413 printf("??????\n");
414 if (t->appliedVariant)
415 display_variant(t->appliedVariant, level+1);
416 if (t->metaData && t->metaData->supportedVariants)
417 {
418 int c;
419
420 printf("%*s---- variant list\n", (level+1)*4, "");
421 for (c = 0; c < t->metaData->num_supportedVariants; c++)
422 {
423 printf("%*svariant #%d\n", (level+1)*4, "", c);
424 display_variant(t->metaData->supportedVariants[c], level + 2);
425 }
426 }
427 }
428}
429
430static void print_record(const unsigned char *buf, size_t len)
431{
432 size_t i;
433 for (i = 0; i<len; i++)
434 if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
435 fputc (buf[i], stdout);
436 else
437 printf ("\\X%02X", buf[i]);
438 /* add newline if not already added ... */
439 if (i <= 0 || buf[i-1] != '\n')
440 fputc ('\n', stdout);
441}
442
443static void display_record(Z_DatabaseRecord *p)
444{
445 Z_External *r = (Z_External*) p;
446 oident *ent = oid_getentbyoid(r->direct_reference);
447
448 record_last = r;
449 /*
450 * Tell the user what we got.
451 */
452 if (r->direct_reference)
453 {
454 printf("Record type: ");
455 if (ent)
456 printf("%s\n", ent->desc);
457 else if (!odr_oid(print, &r->direct_reference, 0, 0))
458 {
459 odr_perror(print, "print oid");
460 odr_reset(print);
461 }
462 }
463 /* Check if this is a known, ASN.1 type tucked away in an octet string */
464 if (ent && r->which == Z_External_octet)
465 {
466 Z_ext_typeent *type = z_ext_getentbyref(ent->value);
467 void *rr;
468
469 if (type)
470 {
471 /*
472 * Call the given decoder to process the record.
473 */
474 odr_setbuf(in, (char*)p->u.octet_aligned->buf,
475 p->u.octet_aligned->len, 0);
476 if (!(*type->fun)(in, (char **)&rr, 0, 0))
477 {
478 odr_perror(in, "Decoding constructed record.");
479 fprintf(stderr, "[Near %d]\n", odr_offset(in));
480 fprintf(stderr, "Packet dump:\n---------\n");
481 odr_dumpBER(stderr, (char*)p->u.octet_aligned->buf,
482 p->u.octet_aligned->len);
483 fprintf(stderr, "---------\n");
484 exit(1);
485 }
486 /*
487 * Note: we throw away the original, BER-encoded record here.
488 * Do something else with it if you want to keep it.
489 */
490 r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
491 r->which = type->what;
492 }
493 }
494 if (ent && ent->value == VAL_SOIF)
495 print_record((const unsigned char *) r->u.octet_aligned->buf, r->u.octet_aligned->len);
496 else if (r->which == Z_External_octet && p->u.octet_aligned->len)
497 {
498 /* johnmcp - this is called for USmarc for demo server, at least */
499 const char *octet_buf = (char*)p->u.octet_aligned->buf;
500 if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML ||
501 ent->value == VAL_HTML)
502 print_record((const unsigned char *) octet_buf,
503 p->u.octet_aligned->len);
504 else
505 {
506 /* johnmcp - here marc_display does the work */
507 if (marc_display (octet_buf, NULL) <= 0)
508 {
509 printf ("ISO2709 decoding failed, dumping record as is:\n");
510 print_record((const unsigned char*) octet_buf,
511 p->u.octet_aligned->len);
512 }
513 }
514 if (marcdump) /*here (false) */
515 fwrite (octet_buf, 1, p->u.octet_aligned->len, marcdump);
516 }
517 else if (ent && ent->value == VAL_SUTRS)
518 {
519 if (r->which != Z_External_sutrs)
520 {
521 printf("Expecting single SUTRS type for SUTRS.\n");
522 return;
523 }
524 print_record(r->u.sutrs->buf, r->u.sutrs->len);
525 }
526 else if (ent && ent->value == VAL_GRS1)
527 {
528 if (r->which != Z_External_grs1)
529 {
530 printf("Expecting single GRS type for GRS.\n");
531 return;
532 }
533 display_grs1(r->u.grs1, 0);
534 }
535 else
536 {
537 printf("Unknown record representation.\n");
538 if (!z_External(print, &r, 0, 0))
539 {
540 odr_perror(print, "Printing external");
541 odr_reset(print);
542 }
543 }
544}
545
546
547static void display_diagrecs(Z_DiagRec **pp, int num)
548{
549 int i;
550 oident *ent;
551 Z_DefaultDiagFormat *r;
552
553 printf("Diagnostic message(s) from database:\n");
554 for (i = 0; i<num; i++)
555 {
556 Z_DiagRec *p = pp[i];
557 if (p->which != Z_DiagRec_defaultFormat)
558 {
559 printf("Diagnostic record not in default format.\n");
560 return;
561 }
562 else
563 r = p->u.defaultFormat;
564 if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
565 ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
566 printf("Missing or unknown diagset\n");
567 printf(" [%d] %s", *r->condition, diagbib1_str(*r->condition));
568#ifdef ASN_COMPILED
569 switch (r->which)
570 {
571 case Z_DefaultDiagFormat_v2Addinfo:
572 printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
573 break;
574 case Z_DefaultDiagFormat_v3Addinfo:
575 printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
576 break;
577 }
578#else
579 if (r->addinfo && *r->addinfo)
580 printf(" -- '%s'\n", r->addinfo);
581 else
582 printf("\n");
583#endif
584 }
585}
586
587
588static void display_nameplusrecord(Z_NamePlusRecord *p)
589{
590 if (p->databaseName)
591 printf("[%s]", p->databaseName);
592 if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
593 display_diagrecs(&p->u.surrogateDiagnostic, 1);
594 else if (p->which == Z_NamePlusRecord_databaseRecord)
595 display_record(p->u.databaseRecord);
596}
597
598static void display_records(Z_Records *p)
599{
600 int i;
601
602 if (p->which == Z_Records_NSD)
603 {
604#ifdef ASN_COMPILED
605 Z_DiagRec dr, *dr_p = &dr;
606 dr.which = Z_DiagRec_defaultFormat;
607 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
608 display_diagrecs (&dr_p, 1);
609#else
610 display_diagrecs (&p->u.nonSurrogateDiagnostic, 1);
611#endif
612 }
613 else if (p->which == Z_Records_multipleNSD)
614 display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs,
615 p->u.multipleNonSurDiagnostics->num_diagRecs);
616 else
617 {
618 printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
619 for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
620 display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
621 }
622}
623
624
625static int send_searchRequest(char *arg)
626{
627 Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
628 Z_SearchRequest *req = apdu->u.searchRequest;
629 Z_Query query;
630 int oid[OID_SIZE];
631 char setstring[100];
632 Z_RPNQuery *RPNquery;
633 /* Odr_oct ccl_query; */
634
635 req->referenceId = set_refid (out);
636 if (!strcmp(arg, "@big")) /* strictly for troublemaking */
637 {
638 static unsigned char big[2100];
639 static Odr_oct bigo;
640
641 /* send a very big referenceid to test transport stack etc. */
642 memset(big, 'A', 2100);
643 bigo.len = bigo.size = 2100;
644 bigo.buf = big;
645 req->referenceId = &bigo;
646 }
647
648 if (setnumber >= 0)
649 {
650 sprintf(setstring, "%d", ++setnumber);
651 req->resultSetName = setstring;
652 }
653 *req->smallSetUpperBound = smallSetUpperBound;
654 *req->largeSetLowerBound = largeSetLowerBound;
655 *req->mediumSetPresentNumber = mediumSetPresentNumber;
656 if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
657 mediumSetPresentNumber > 0))
658 {
659 oident prefsyn;
660
661 prefsyn.proto = protocol;
662 prefsyn.oclass = CLASS_RECSYN;
663 prefsyn.value = recordsyntax;
664 req->preferredRecordSyntax =
665 odr_oiddup(out, oid_ent_to_oid(&prefsyn, oid));
666 req->smallSetElementSetNames =
667 req->mediumSetElementSetNames = elementSetNames;
668 }
669 req->num_databaseNames = num_databaseNames;
670 req->databaseNames = databaseNames;
671
672 req->query = &query;
673 /* johnmcp - this is where we choose our query format. either ccl or rpn */
674 /* switch (queryType)
675 {
676 case QueryType_Prefix: */
677 query.which = Z_Query_type_1;
678 RPNquery = p_query_rpn (out, protocol, arg);
679 if (!RPNquery)
680 {
681 printf("Prefix query error\n");
682 return (-1);
683 }
684 query.u.type_1 = RPNquery;
685 /* break;
686 case QueryType_CCL:
687 query.which = Z_Query_type_2;
688 query.u.type_2 = &ccl_query;
689 ccl_query.buf = (unsigned char*) arg;
690 ccl_query.len = strlen(arg);
691 break;
692 default:
693 printf ("Unsupported query type\n");
694 return 0;
695 }*/
696 send_apdu(apdu);
697 setno = 1;
698 /* printf("Sent searchRequest.\n"); */
699 return 0;
700}
701
702static int process_searchResponse(Z_SearchResponse *res)
703{
704 print_refid (res->referenceId);
705 if (!(*res->searchStatus)) {
706 /* this should return an error instead of 0 docs found... one day... */
707 return 0;
708 }
709 setno += *res->numberOfRecordsReturned;
710 if (res->records)
711 display_records(res->records);
712 return *res->resultCount;
713}
714
715static void print_level(int iLevel)
716{
717 int i;
718 for (i = 0; i < iLevel * 4; i++)
719 printf(" ");
720}
721
722static void print_int(int iLevel, const char *pTag, int *pInt)
723{
724 if (pInt != NULL)
725 {
726 print_level(iLevel);
727 printf("%s: %d\n", pTag, *pInt);
728 }
729}
730
731static void print_string(int iLevel, const char *pTag, const char *pString)
732{
733 if (pString != NULL)
734 {
735 print_level(iLevel);
736 printf("%s: %s\n", pTag, pString);
737 }
738}
739
740static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
741{
742 if (pOid != NULL)
743 {
744 int *pInt = pOid;
745
746 print_level(iLevel);
747 printf("%s:", pTag);
748 for (; *pInt != -1; pInt++)
749 printf(" %d", *pInt);
750 printf("\n");
751 }
752}
753
754static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
755{
756 if (referenceId != NULL)
757 {
758 int i;
759
760 print_level(iLevel);
761 printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
762 for (i = 0; i < referenceId->len; i++)
763 printf("%c", referenceId->buf[i]);
764 printf("\n");
765 }
766}
767
768static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
769{
770 if (pStringNumeric != NULL)
771 {
772 switch (pStringNumeric->which)
773 {
774 case Z_StringOrNumeric_string:
775 print_string(iLevel, pTag, pStringNumeric->u.string);
776 break;
777
778 case Z_StringOrNumeric_numeric:
779 print_int(iLevel, pTag, pStringNumeric->u.numeric);
780 break;
781
782 default:
783 print_level(iLevel);
784 printf("%s: valid type for Z_StringOrNumeric\n", pTag);
785 break;
786 }
787 }
788}
789
790static void print_universe_report_duplicate(int iLevel, Z_UniverseReportDuplicate *pUniverseReportDuplicate)
791{
792 if (pUniverseReportDuplicate != NULL)
793 {
794 print_level(iLevel);
795 printf("Universe Report Duplicate: \n");
796 iLevel++;
797 print_string_or_numeric(iLevel, "Hit No", pUniverseReportDuplicate->hitno);
798 }
799}
800
801static void print_universe_report_hits(int iLevel, Z_UniverseReportHits *pUniverseReportHits)
802{
803 if (pUniverseReportHits != NULL)
804 {
805 print_level(iLevel);
806 printf("Universe Report Hits: \n");
807 iLevel++;
808 print_string_or_numeric(iLevel, "Database", pUniverseReportHits->database);
809 print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
810 }
811}
812
813static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
814{
815 if (pUniverseReport != NULL)
816 {
817 print_level(iLevel);
818 printf("Universe Report: \n");
819 iLevel++;
820 print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
821 switch (pUniverseReport->which)
822 {
823 case Z_UniverseReport_databaseHits:
824 print_universe_report_hits(iLevel, pUniverseReport->u.databaseHits);
825 break;
826
827 case Z_UniverseReport_duplicate:
828 print_universe_report_duplicate(iLevel, pUniverseReport->u.duplicate);
829 break;
830
831 default:
832 print_level(iLevel);
833 printf("Type: %d\n", pUniverseReport->which);
834 break;
835 }
836 }
837}
838
839static void print_external(int iLevel, Z_External *pExternal)
840{
841 if (pExternal != NULL)
842 {
843 print_level(iLevel);
844 printf("External: \n");
845 iLevel++;
846 print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
847 print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
848 print_string(iLevel, "Descriptor", pExternal->descriptor);
849 switch (pExternal->which)
850 {
851 case Z_External_universeReport:
852 print_universe_report(iLevel, pExternal->u.universeReport);
853 break;
854
855 default:
856 print_level(iLevel);
857 printf("Type: %d\n", pExternal->which);
858 break;
859 }
860 }
861}
862
863static int process_resourceControlRequest (Z_ResourceControlRequest *req)
864{
865 printf ("Received ResourceControlRequest.\n");
866 print_referenceId(1, req->referenceId);
867 print_int(1, "Suspended Flag", req->suspendedFlag);
868 print_int(1, "Partial Results Available", req->partialResultsAvailable);
869 print_int(1, "Response Required", req->responseRequired);
870 print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
871 print_external(1, req->resourceReport);
872 return 0;
873}
874
875void process_ESResponse(Z_ExtendedServicesResponse *res)
876{
877 printf("process_ESResponse status=");
878 switch (*res->operationStatus)
879 {
880 case Z_ExtendedServicesResponse_done:
881 printf ("done\n");
882 break;
883 case Z_ExtendedServicesResponse_accepted:
884 printf ("accepted\n");
885 break;
886 case Z_ExtendedServicesResponse_failure:
887 printf ("failure\n");
888 display_diagrecs(res->diagnostics, res->num_diagnostics);
889 break;
890 }
891}
892
893#ifdef ASN_COMPILED
894
895const char *get_ill_element (void *clientData, const char *element)
896{
897 if (!strcmp (element, "ill,transaction-id,transaction-group-qualifier"))
898 return "1";
899 if (!strcmp (element, "ill,transaction-id,transaction-qualifier"))
900 return "1";
901 return 0;
902}
903
904#endif
905
906
907/* PRESENT SERVICE ----------------------------- */
908static int z_send_getbriefrecords(int starting, int set, int howmany) {
909 Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
910 Z_PresentRequest *req = apdu->u.presentRequest;
911 Z_RecordComposition compo;
912 oident prefsyn;
913 int nos = 1;
914 int oid[OID_SIZE];
915 /* char *p;*/
916 char setstring[100];
917
918 req->referenceId = set_refid (out);
919 nos = howmany;
920
921 setno = starting;
922 setnumber=1;
923 sprintf(setstring, "%d", setnumber);
924 req->resultSetId = setstring;
925 req->resultSetStartPoint = &setno;
926 req->numberOfRecordsRequested = &nos;
927 prefsyn.proto = protocol;
928 prefsyn.oclass = CLASS_RECSYN;
929 prefsyn.value = recordsyntax;
930 req->preferredRecordSyntax =
931 odr_oiddup (out, oid_ent_to_oid(&prefsyn, oid));
932
933 if (schema != VAL_NONE)
934 {
935 oident prefschema;
936
937 prefschema.proto = protocol;
938 prefschema.oclass = CLASS_SCHEMA;
939 prefschema.value = schema;
940
941 req->recordComposition = &compo;
942 compo.which = Z_RecordComp_complex;
943 compo.u.complex = (Z_CompSpec *)
944 odr_malloc(out, sizeof(*compo.u.complex));
945 compo.u.complex->selectAlternativeSyntax = (bool_t *)
946 odr_malloc(out, sizeof(bool_t));
947 *compo.u.complex->selectAlternativeSyntax = 0;
948
949 compo.u.complex->generic = (Z_Specification *)
950 odr_malloc(out, sizeof(*compo.u.complex->generic));
951 compo.u.complex->generic->schema = (Odr_oid *)
952 odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
953 if (!compo.u.complex->generic->schema)
954 {
955 /* OID wasn't a schema! Try record syntax instead. */
956 prefschema.oclass = CLASS_RECSYN;
957 compo.u.complex->generic->schema = (Odr_oid *)
958 odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
959 }
960 if (!elementSetNames)
961 compo.u.complex->generic->elementSpec = 0;
962 else
963 {
964 compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
965 odr_malloc(out, sizeof(Z_ElementSpec));
966 compo.u.complex->generic->elementSpec->which =
967 Z_ElementSpec_elementSetName;
968 compo.u.complex->generic->elementSpec->u.elementSetName =
969 elementSetNames->u.generic;
970 }
971 compo.u.complex->num_dbSpecific = 0;
972 compo.u.complex->dbSpecific = 0;
973 compo.u.complex->num_recordSyntax = 0;
974 compo.u.complex->recordSyntax = 0;
975 }
976 else if (elementSetNames)
977 {
978 req->recordComposition = &compo;
979 compo.which = Z_RecordComp_simple;
980 compo.u.simple = elementSetNames;
981 }
982 send_apdu(apdu);
983 return 0;
984}
985
986void process_close(Z_Close *req)
987{
988 Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
989 Z_Close *res = apdu->u.close;
990
991 static char *reasons[] =
992 {
993 "finished",
994 "shutdown",
995 "system problem",
996 "cost limit reached",
997 "resources",
998 "security violation",
999 "protocolError",
1000 "lack of activity",
1001 "peer abort",
1002 "unspecified"
1003 };
1004
1005 printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
1006 req->diagnosticInformation ? req->diagnosticInformation : "NULL");
1007 if (sent_close)
1008 {
1009 cs_close (conn);
1010 conn = NULL;
1011 if (session_mem)
1012 {
1013 nmem_destroy (session_mem);
1014 session_mem = NULL;
1015 }
1016 sent_close = 0;
1017 }
1018 else
1019 {
1020 *res->closeReason = Z_Close_finished;
1021 send_apdu(apdu);
1022 printf("Sent response.\n");
1023 sent_close = 1;
1024 }
1025}
1026
1027
1028
1029int cmd_quit(char *arg)
1030{
1031 printf("See you later, alligator.\n");
1032 exit(0);
1033 return 0;
1034}
1035
1036int cmd_cancel(char *arg)
1037{
1038 Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
1039 Z_TriggerResourceControlRequest *req =
1040 apdu->u.triggerResourceControlRequest;
1041 bool_t rfalse = 0;
1042
1043 if (!conn)
1044 {
1045 printf("Session not initialized yet\n");
1046 return 0;
1047 }
1048 if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
1049 {
1050 printf("Target doesn't support cancel (trigger resource ctrl)\n");
1051 return 0;
1052 }
1053 *req->requestedAction = Z_TriggerResourceCtrl_cancel;
1054 req->resultSetWanted = &rfalse;
1055
1056 send_apdu(apdu);
1057 printf("Sent cancel request\n");
1058 return 2;
1059}
1060
1061int send_scanrequest(char *string, int pp, int num)
1062{
1063 Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
1064 Z_ScanRequest *req = apdu->u.scanRequest;
1065
1066 if (!(req->termListAndStartPoint =
1067 p_query_scan(out, protocol, &req->attributeSet, string)))
1068 {
1069 printf("Prefix query error\n");
1070 return -1;
1071 }
1072 req->referenceId = set_refid (out);
1073 req->num_databaseNames = num_databaseNames;
1074 req->databaseNames = databaseNames;
1075 req->numberOfTermsRequested = &num;
1076 req->preferredPositionInResponse = &pp;
1077 send_apdu(apdu);
1078 return 2;
1079}
1080
1081int send_sortrequest(char *arg, int newset)
1082{
1083 Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
1084 Z_SortRequest *req = apdu->u.sortRequest;
1085 Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
1086 odr_malloc (out, sizeof(*sksl));
1087 char setstring[32];
1088 char sort_string[32], sort_flags[32];
1089 int off;
1090 int oid[OID_SIZE];
1091 oident bib1;
1092
1093 if (setnumber >= 0)
1094 sprintf (setstring, "%d", setnumber);
1095 else
1096 sprintf (setstring, "default");
1097
1098 req->referenceId = set_refid (out);
1099
1100#ifdef ASN_COMPILED
1101 req->num_inputResultSetNames = 1;
1102 req->inputResultSetNames = (Z_InternationalString **)
1103 odr_malloc (out, sizeof(*req->inputResultSetNames));
1104 req->inputResultSetNames[0] = odr_strdup (out, setstring);
1105#else
1106 req->inputResultSetNames =
1107 (Z_StringList *)odr_malloc (out, sizeof(*req->inputResultSetNames));
1108 req->inputResultSetNames->num_strings = 1;
1109 req->inputResultSetNames->strings =
1110 (char **)odr_malloc (out, sizeof(*req->inputResultSetNames->strings));
1111 req->inputResultSetNames->strings[0] =
1112 odr_strdup (out, setstring);
1113#endif
1114
1115 if (newset && setnumber >= 0)
1116 sprintf (setstring, "%d", ++setnumber);
1117
1118 req->sortedResultSetName = odr_strdup (out, setstring);
1119
1120 req->sortSequence = sksl;
1121 sksl->num_specs = 0;
1122 sksl->specs = (Z_SortKeySpec **)odr_malloc (out, sizeof(sksl->specs) * 20);
1123
1124 bib1.proto = protocol;
1125 bib1.oclass = CLASS_ATTSET;
1126 bib1.value = VAL_BIB1;
1127 while ((sscanf (arg, "%31s %31s%n", sort_string, sort_flags, &off)) == 2
1128 && off > 1)
1129 {
1130 int i;
1131 char *sort_string_sep;
1132 Z_SortKeySpec *sks = (Z_SortKeySpec *)odr_malloc (out, sizeof(*sks));
1133 Z_SortKey *sk = (Z_SortKey *)odr_malloc (out, sizeof(*sk));
1134
1135 arg += off;
1136 sksl->specs[sksl->num_specs++] = sks;
1137 sks->sortElement = (Z_SortElement *)odr_malloc (out, sizeof(*sks->sortElement));
1138 sks->sortElement->which = Z_SortElement_generic;
1139 sks->sortElement->u.generic = sk;
1140
1141 if ((sort_string_sep = strchr (sort_string, '=')))
1142 {
1143 Z_AttributeElement *el = (Z_AttributeElement *)odr_malloc (out, sizeof(*el));
1144 sk->which = Z_SortKey_sortAttributes;
1145 sk->u.sortAttributes =
1146 (Z_SortAttributes *)odr_malloc (out, sizeof(*sk->u.sortAttributes));
1147 sk->u.sortAttributes->id = oid_ent_to_oid(&bib1, oid);
1148 sk->u.sortAttributes->list =
1149 (Z_AttributeList *)odr_malloc (out, sizeof(*sk->u.sortAttributes->list));
1150 sk->u.sortAttributes->list->num_attributes = 1;
1151 sk->u.sortAttributes->list->attributes =
1152 (Z_AttributeElement **)odr_malloc (out,
1153 sizeof(*sk->u.sortAttributes->list->attributes));
1154 sk->u.sortAttributes->list->attributes[0] = el;
1155 el->attributeSet = 0;
1156 el->attributeType = (int *)odr_malloc (out, sizeof(*el->attributeType));
1157 *el->attributeType = atoi (sort_string);
1158 el->which = Z_AttributeValue_numeric;
1159 el->value.numeric = (int *)odr_malloc (out, sizeof(*el->value.numeric));
1160 *el->value.numeric = atoi (sort_string_sep + 1);
1161 }
1162 else
1163 {
1164 sk->which = Z_SortKey_sortField;
1165 sk->u.sortField = odr_strdup (out, sort_string);
1166 }
1167 sks->sortRelation = (int *)odr_malloc (out, sizeof(*sks->sortRelation));
1168 *sks->sortRelation = Z_SortRelation_ascending;
1169 sks->caseSensitivity = (int *)odr_malloc (out, sizeof(*sks->caseSensitivity));
1170 *sks->caseSensitivity = Z_SortCase_caseSensitive;
1171
1172#ifdef ASN_COMPILED
1173 sks->which = Z_SortKeySpec_null;
1174 sks->u.null = odr_nullval ();
1175#else
1176 sks->missingValueAction = NULL;
1177#endif
1178
1179 for (i = 0; sort_flags[i]; i++)
1180 {
1181 switch (sort_flags[i])
1182 {
1183 case 'a':
1184 case 'A':
1185 case '>':
1186 *sks->sortRelation = Z_SortRelation_descending;
1187 break;
1188 case 'd':
1189 case 'D':
1190 case '<':
1191 *sks->sortRelation = Z_SortRelation_ascending;
1192 break;
1193 case 'i':
1194 case 'I':
1195 *sks->caseSensitivity = Z_SortCase_caseInsensitive;
1196 break;
1197 case 'S':
1198 case 's':
1199 *sks->caseSensitivity = Z_SortCase_caseSensitive;
1200 break;
1201 }
1202 }
1203 }
1204 if (!sksl->num_specs)
1205 {
1206 printf ("Missing sort specifications\n");
1207 return -1;
1208 }
1209 send_apdu(apdu);
1210 return 2;
1211}
1212
1213void display_term(Z_TermInfo *t)
1214{
1215 if (t->term->which == Z_Term_general)
1216 {
1217 printf("%.*s (%d)\n", t->term->u.general->len, t->term->u.general->buf,
1218 t->globalOccurrences ? *t->globalOccurrences : -1);
1219 sprintf(last_scan, "%.*s", t->term->u.general->len,
1220 t->term->u.general->buf);
1221 }
1222 else
1223 printf("Term type not general.\n");
1224}
1225
1226void process_scanResponse(Z_ScanResponse *res)
1227{
1228 int i;
1229 Z_Entry **entries = NULL;
1230 int num_entries = 0;
1231
1232 printf("Received ScanResponse\n");
1233 print_refid (res->referenceId);
1234 printf("%d entries", *res->numberOfEntriesReturned);
1235 if (res->positionOfTerm)
1236 printf (", position=%d", *res->positionOfTerm);
1237 printf ("\n");
1238 if (*res->scanStatus != Z_Scan_success)
1239 printf("Scan returned code %d\n", *res->scanStatus);
1240 if (!res->entries)
1241 return;
1242 if ((entries = res->entries->entries))
1243 num_entries = res->entries->num_entries;
1244 for (i = 0; i < num_entries; i++)
1245 {
1246 int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
1247 if (entries[i]->which == Z_Entry_termInfo)
1248 {
1249 printf("%c ", i + 1 == pos_term ? '*' : ' ');
1250 display_term(entries[i]->u.termInfo);
1251 }
1252 else
1253 display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
1254 }
1255 if (res->entries->nonsurrogateDiagnostics)
1256 display_diagrecs (res->entries->nonsurrogateDiagnostics,
1257 res->entries->num_nonsurrogateDiagnostics);
1258}
1259
1260void process_sortResponse(Z_SortResponse *res)
1261{
1262 printf("Received SortResponse: status=");
1263 switch (*res->sortStatus)
1264 {
1265 case Z_SortStatus_success:
1266 printf ("success"); break;
1267 case Z_SortStatus_partial_1:
1268 printf ("partial"); break;
1269 case Z_SortStatus_failure:
1270 printf ("failure"); break;
1271 default:
1272 printf ("unknown (%d)", *res->sortStatus);
1273 }
1274 printf ("\n");
1275 print_refid (res->referenceId);
1276#ifdef ASN_COMPILED
1277 if (res->diagnostics)
1278 display_diagrecs(res->diagnostics,
1279 res->num_diagnostics);
1280#else
1281 if (res->diagnostics)
1282 display_diagrecs(res->diagnostics->diagRecs,
1283 res->diagnostics->num_diagRecs);
1284#endif
1285}
1286
1287void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
1288{
1289 printf("Got deleteResultSetResponse status=%d\n",
1290 *res->deleteOperationStatus);
1291 if (res->deleteListStatuses)
1292 {
1293 int i;
1294 for (i = 0; i < res->deleteListStatuses->num; i++)
1295 {
1296 printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
1297 *res->deleteListStatuses->elements[i]->status);
1298 }
1299 }
1300}
1301
1302int cmd_sort_generic(char *arg, int newset)
1303{
1304 if (!conn)
1305 {
1306 printf("Session not initialized yet\n");
1307 return 0;
1308 }
1309 if (!ODR_MASK_GET(session->options, Z_Options_sort))
1310 {
1311 printf("Target doesn't support sort\n");
1312 return 0;
1313 }
1314 if (*arg)
1315 {
1316 if (send_sortrequest(arg, newset) < 0)
1317 return 0;
1318 return 2;
1319 }
1320 return 0;
1321}
1322
1323int cmd_sort(char *arg)
1324{
1325 return cmd_sort_generic (arg, 0);
1326}
1327
1328int cmd_sort_newset (char *arg)
1329{
1330 return cmd_sort_generic (arg, 1);
1331}
1332
1333int cmd_scan(char *arg)
1334{
1335 if (!conn)
1336 {
1337 printf("Session not initialized yet\n");
1338 return 0;
1339 }
1340 if (!ODR_MASK_GET(session->options, Z_Options_scan))
1341 {
1342 printf("Target doesn't support scan\n");
1343 return 0;
1344 }
1345 if (*arg)
1346 {
1347 if (send_scanrequest(arg, 1, 20) < 0)
1348 return 0;
1349 }
1350 else
1351 if (send_scanrequest(last_scan, 1, 20) < 0)
1352 return 0;
1353 return 2;
1354}
1355
1356int cmd_schema(char *arg)
1357{
1358 if (!arg || !*arg)
1359 {
1360 schema = VAL_NONE;
1361 return 1;
1362 }
1363 schema = oid_getvalbyname (arg);
1364 if (schema == VAL_NONE)
1365 {
1366 printf ("unknown schema\n");
1367 return 0;
1368 }
1369 return 1;
1370}
1371
1372int cmd_format(char *arg)
1373{
1374 if (!arg || !*arg)
1375 {
1376 printf("Usage: format <recordsyntax>\n");
1377 return 0;
1378 }
1379 recordsyntax = oid_getvalbyname (arg);
1380 if (recordsyntax == VAL_NONE)
1381 {
1382 printf ("unknown record syntax\n");
1383 return 0;
1384 }
1385 return 1;
1386}
1387
1388int cmd_elements(char *arg)
1389{
1390 static Z_ElementSetNames esn;
1391 static char what[100];
1392
1393 if (!arg || !*arg)
1394 {
1395 elementSetNames = 0;
1396 return 1;
1397 }
1398 strcpy(what, arg);
1399 esn.which = Z_ElementSetNames_generic;
1400 esn.u.generic = what;
1401 elementSetNames = &esn;
1402 return 1;
1403}
1404
1405int cmd_attributeset(char *arg)
1406{
1407 char what[100];
1408
1409 if (!arg || !*arg)
1410 {
1411 printf("Usage: attributeset <setname>\n");
1412 return 0;
1413 }
1414 sscanf(arg, "%s", what);
1415 if (p_query_attset (what))
1416 {
1417 printf("Unknown attribute set name\n");
1418 return 0;
1419 }
1420 return 1;
1421}
1422
1423int cmd_querytype (char *arg)
1424{
1425 if (!strcmp (arg, "ccl"))
1426 queryType = QueryType_CCL;
1427 else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
1428 queryType = QueryType_Prefix;
1429 else
1430 {
1431 printf ("Querytype must be one of:\n");
1432 printf (" prefix - Prefix query\n");
1433 printf (" ccl - CCL query\n");
1434 return 0;
1435 }
1436 return 1;
1437}
1438
1439int cmd_refid (char *arg)
1440{
1441 xfree (refid);
1442 refid = NULL;
1443 if (*arg)
1444 {
1445 refid = (char *) xmalloc (strlen(arg)+1);
1446 strcpy (refid, arg);
1447 }
1448 return 1;
1449}
1450
1451int z_cmd_close(char *arg)
1452{
1453 Z_APDU *apdu;
1454 Z_Close *req;
1455 if (!conn)
1456 return 1;
1457
1458 apdu = zget_APDU(out, Z_APDU_close);
1459 req = apdu->u.close;
1460 *req->closeReason = Z_Close_finished;
1461 send_apdu(apdu);
1462 sent_close = 1;
1463 return 0;
1464}
1465
1466void z_initialize(void)
1467{
1468 nmem_init();
1469 if (!(out = odr_createmem(ODR_ENCODE)) ||
1470 !(in = odr_createmem(ODR_DECODE)) ||
1471 !(print = odr_createmem(ODR_PRINT)))
1472 {
1473 fprintf(stderr, "failed to allocate ODR streams\n");
1474 exit(1);
1475 }
1476 setvbuf(stdout, 0, _IONBF, 0);
1477 if (apdu_file)
1478 odr_setprint(print, apdu_file);
1479
1480 cmd_base("Default");
1481}
1482
1483static int z_getAPDU (Z_APDU **ret_apdu) {
1484 int res;
1485
1486 char *netbuffer= 0;
1487 int netbufferlen = 0;
1488 Z_APDU *apdu;
1489
1490 if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) {
1491 perror("cs_get");
1492 exit(1);
1493 }
1494 if (!res) {
1495 printf("Target closed connection.\n");
1496 exit(1);
1497 }
1498 odr_reset(in); /* release APDU from last round */
1499 record_last = 0;
1500 odr_setbuf(in, netbuffer, res, 0);
1501 /* johnmcp */
1502 if (!z_APDU(in, &apdu, 0, 0))
1503 {
1504 odr_perror(in, "Decoding incoming APDU");
1505 fprintf(stderr, "[Near %d]\n", odr_offset(in));
1506 fprintf(stderr, "Packet dump:\n---------\n");
1507 odr_dumpBER(stderr, netbuffer, res);
1508 fprintf(stderr, "---------\n");
1509 if (apdu_file)
1510 z_APDU(print, &apdu, 0, 0);
1511 exit(1);
1512 }
1513 if (apdu_file && !z_APDU(print, &apdu, 0, 0))
1514 {
1515 odr_perror(print, "Failed to print incoming APDU");
1516 odr_reset(print);
1517 return -1; /* was continue */
1518 }
1519 (*ret_apdu)=apdu;
1520 return 0;
1521}
1522
1523
1524/* returns number found, arg is query string */
1525int z_cmd_dosearch(char *arg)
1526{
1527 Z_APDU *apdu;
1528 int matching;
1529 int ret_val;
1530 ret_val=send_searchRequest(arg);
1531 if (ret_val==-1) {
1532 /* prefix query error */
1533 return (-1);
1534 }
1535 z_getAPDU(&apdu);
1536 /* check return value??? */
1537 if (apdu->which != Z_APDU_searchResponse)
1538 {
1539 printf("sendsearchRequest() was not replied with a searchResponse!\n");
1540 return (-2);
1541 }
1542 /* let's keep going anyway... */
1543 matching=process_searchResponse(apdu->u.searchResponse);
1544 /* this assumes we want to take action on failure (-1) here rather than
1545 whereever we were called from */
1546 return (matching);
1547}
1548
1549/* src must be NULL-terminated */
1550static char *safeappendstr(char *dest, size_t *allocsize,
1551 size_t *offset, char *src) {
1552 /* allocsize is the amount of space currently allocated to dest,
1553 offset is how far into dest we want to append src */
1554 if (*offset + strlen(src) >= *allocsize) {
1555 *allocsize+=strlen(src)+64; /* add some extra space to save on reallocs */
1556 if ((dest=realloc(dest,*allocsize))==NULL) {
1557 fprintf(stderr, "malloc failed while decoding marc record.\n");
1558 return (NULL);
1559 }
1560 }
1561 strcpy(dest+(*offset), src);
1562 *offset+=strlen(src);
1563 return (dest);
1564}
1565
1566static char *getmarcfields(Z_DatabaseRecord *p, int titleonly) {
1567 /* this code is based on marc_display(), with a couple of lines taken from
1568 display_record() in the original client. */
1569 /* if titleonly is non-zero, we only get a (the?) title field, otherwise
1570 return the whole thing */
1571 const char *buf=(char *)p->u.octet_aligned->buf;
1572 char *title; /* our string to return */
1573 int title_maxlen=0; /* amount of space currently allocated */
1574 int title_curlen=0; /* amount of space actually used */
1575 int entry_p;
1576 int record_length;
1577 int indicator_length;
1578 int identifier_length;
1579 int base_address;
1580 int length_data_entry;
1581 int length_starting;
1582 int length_implementation;
1583 FILE *outf;
1584
1585 /* if (!outf) */
1586 outf = stdout;
1587
1588 /* initialise our title. Start with 64 chars */
1589 title_maxlen=64;
1590 if((title=malloc(title_maxlen))==NULL) {
1591 /* not quite sure where stderr will be going, but.... */
1592 fprintf(stderr,"Malloc failed while decoding marc record\n");
1593 return NULL;
1594 }
1595
1596 if (!titleonly) {
1597 strcpy(title,"<table border=1>\n");
1598 title_curlen=strlen(title);
1599 }
1600 else title_curlen=0;
1601
1602 record_length = atoi_n (buf, 5);
1603 if (record_length < 25)
1604 return (NULL); /* -1 */
1605 if (isdigit(buf[10]))
1606 indicator_length = atoi_n (buf+10, 1);
1607 else
1608 indicator_length = 2;
1609 if (isdigit(buf[11]))
1610 identifier_length = atoi_n (buf+11, 1);
1611 else
1612 identifier_length = 2;
1613 base_address = atoi_n (buf+12, 4);
1614
1615 length_data_entry = atoi_n (buf+20, 1);
1616 length_starting = atoi_n (buf+21, 1);
1617 length_implementation = atoi_n (buf+22, 1);
1618
1619 if (0) /* debug */
1620 {
1621 fprintf (outf, "Record length %5d\n", record_length);
1622 fprintf (outf, "Indicator length %5d\n", indicator_length);
1623 fprintf (outf, "Identifier length %5d\n", identifier_length);
1624 fprintf (outf, "Base address %5d\n", base_address);
1625 fprintf (outf, "Length data entry %5d\n", length_data_entry);
1626 fprintf (outf, "Length starting %5d\n", length_starting);
1627 fprintf (outf, "Length implementation %5d\n", length_implementation);
1628 }
1629 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
1630 {
1631 entry_p += 3+length_data_entry+length_starting;
1632 if (entry_p >= record_length)
1633 return (NULL); /* -1 */
1634 }
1635 base_address = entry_p+1;
1636 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
1637 {
1638 int data_length;
1639 int data_offset;
1640 int end_offset;
1641 int i /*, j*/ ;
1642 int startofstring;
1643 int whichtag;
1644 short int abbrtitle=0;
1645 char tag[4];
1646 memcpy (tag, buf+entry_p, 3);
1647 entry_p += 3;
1648 tag[3] = '\0';
1649 whichtag=atoi(tag);
1650 if (0) /* debug */
1651 fprintf (outf, "Tag: ");
1652 /* johnmcp
1653 Relevant tags (for "main entry") - assume only one of these is set,
1654 as we will only return the first one found.
1655 100=personal name
1656 110=corporate name
1657 111=meeting name
1658 130=uniform title
1659 subfields: $a=personal name, $c=title/other, $d=date
1660
1661 210=Abbreviated Title
1662 222=Key title
1663 240=uniform title
1664 243=collective uniform title
1665 245=title statement
1666 246=varying form of title
1667 247=former title or title variations
1668 subfields: $a=abbrev. title $b=qualifying info $2=source
1669 . $6=linkage $8=link field and sequence number.
1670 */
1671 /*fprintf (outf, "%s ", tag); */
1672 data_length = atoi_n (buf+entry_p, length_data_entry);
1673 entry_p += length_data_entry;
1674 data_offset = atoi_n (buf+entry_p, length_starting);
1675 entry_p += length_starting;
1676 i = data_offset + base_address;
1677 end_offset = i+data_length-1;
1678
1679 if (0) /* debug */
1680 fprintf (outf, " Ind: ");
1681
1682 /* memcmp (tag,"00",2) is true, then we DON'T have a control tag
1683 ie less than 10. */
1684 /*if (memcmp (tag, "00", 2) && indicator_length)
1685 {
1686 for (j = 0; j<indicator_length; j++)
1687 fprintf (outf, "%c", buf[i++]);
1688 }
1689 */
1690 if (whichtag>=10) i+=indicator_length;
1691 /* the control fields (<10) don't have leading chars. */
1692
1693
1694 if (0) /* debug */
1695 fprintf (outf, " Fields: ");
1696
1697 /* If we only want the title, then skip other fields */
1698 if (titleonly &&(whichtag<200||whichtag>249)) {
1699 /* skip this record */
1700 continue;
1701 i=end_offset;
1702 }
1703
1704 /* either titleonly is 0, or titleonly is 1 and whichtag is between
1705 200 and 249... */
1706 if (!titleonly) {
1707 /* print out what kind of tag this is */
1708 char *tagname;
1709 char *field_control1="<tr><td>Marc Control Number:</td><td>";
1710 char *field_control3="<tr><td>Marc Organisation Code:</td><td>";
1711 char *field_control5="<tr><td>Marc record Date Info.:</td><td>";
1712 char *field_control8="<tr><td>Control Field (Marc info):</td><td>";
1713 char *field_loc_nr="<tr><td>Lib. of Congress control #:</td><td>";
1714 char *field_issn="<tr><td>ISSN Number:</td><td>";
1715 char *field_catalog="<tr><td>Catalog agency:</td><td>";
1716 char *field_lang="<tr><td>3-letter language code(s):</td><td>";
1717 char *field_areacode="<tr><td>Geographic Area code:</td><td>";
1718 char *field_cn_loc="<tr><td>Lib. of Congress Call #:</td><td>";
1719 char *field_cn_dewdec="<tr><td>Dewey Decimal Call #:</td><td>";
1720 char *field_cn_other="<tr><td>Other Classification Info.:</td><td>";
1721 char *field_cn_gd="<tr><td>Govt. Document Call #:</td><td>";
1722 char *field_personalname="<tr><td>Personal Name:</td><td>";
1723 char *field_meetingname="<tr><td>Meeting Name:</td><td>";
1724 char *field_maintitle="<tr><td>Title:</td><td>";
1725 char *field_edition="<tr><td><Edition Information:</td><td>";
1726 char *field_publication="<tr><td>Publication Info.:</td><td>";
1727 char *field_physdesc="<tr><td>Physical Description:</td><td>";
1728 char *field_series_title="<tr><td>Series Title:</td><td>";
1729 char *field_series_statement="<tr><td>Series Statement:</td><td>";
1730 char *field_note_general="<tr><td>Note:</td><td>";
1731 char *field_note_bib="<tr><td>Bibliographic Note:</td><td>";
1732 char *field_note_summary="<tr><td>Summary Note:</td><td>";
1733 char *field_sub_note="<tr><td>Subject Notes:</td><td>";
1734 char *field_sub_topic="<tr><td>Subject - Topic:</td><td>";
1735 char *field_added_persname="<tr><td>Author Note - Name:</td><td>";
1736 char *field_added_corpname="<tr><td>Author - Organisation:</td><td>";
1737 char *field_uniform_title="<tr><td>Extra Title Information:</td><td>";
1738 char *field_host_item="<tr><td>In:</td><td>";
1739 char *field_series_corpname="<tr><td>Series - Organisation:</td><td>";
1740 /*char *field_other="<tr><td>(other field):</td><td>";*/
1741 char tag_num[100];
1742 switch (whichtag) {
1743 case (1): {tagname=field_control1;break;}
1744 case (3): {tagname=field_control3;break;}
1745 case (5): {tagname=field_control5;break;}
1746 case (8): {tagname=field_control8;break;}
1747 case (10): {tagname=field_loc_nr;break;}
1748 case (20): {tagname=field_issn;break;}
1749 case (40): {tagname=field_catalog;break;}
1750 case (41): {tagname=field_lang;break;}
1751 case (43): {tagname=field_areacode;break;}
1752 case (50): {tagname=field_cn_loc;break;}
1753 case (82): {tagname=field_cn_dewdec;break;}
1754 case (84): {tagname=field_cn_other;break;}
1755 case (86): {tagname=field_cn_gd;break;}
1756 case (100): {tagname=field_personalname;break;}
1757 case (111): {tagname=field_meetingname;break;}
1758 case (245): {tagname=field_maintitle;break;}
1759 case (250): {tagname=field_edition;break;}
1760 case (260): {tagname=field_publication;break;}
1761 case (300): {tagname=field_physdesc;break;}
1762 case (440): {tagname=field_series_title;break;}
1763 case (490): {tagname=field_series_statement;break;}
1764 case (500): {tagname=field_note_general;break;}
1765 case (504): {tagname=field_note_bib;break;}
1766 case (520): {tagname=field_note_summary;break;}
1767 case (630): {tagname=field_sub_note;break;}
1768 case (650): {tagname=field_sub_topic;break;}
1769 case (700): {tagname=field_added_persname;break;}
1770 case (710): {tagname=field_added_corpname;break;}
1771 case (730): {tagname=field_uniform_title;break;}
1772 case (773): {tagname=field_host_item;break;}
1773 case (810): {tagname=field_series_corpname;break;}
1774 default:
1775 if (whichtag>=90&&whichtag<=99)
1776 tagname="<tr><td>(obsolete field) Call #:</td><td>";
1777 else {
1778 /*tagname=field_other;*/
1779
1780 /*.*********** Following line "causes" (ie exposes) a seg fault
1781 in realloc(title,...). What is causing this????.
1782 ANSWER: The trailing '\0' needs to be explicit :-) */
1783 sprintf(tag_num,"<tr><td>(field %d)</td><td>\n\0",whichtag);
1784 tagname=tag_num;
1785 }
1786 }
1787
1788 /* add the field type */
1789 title=safeappendstr(title, &title_maxlen, &title_curlen, tagname);
1790 }
1791
1792 /* go through current field in current record */
1793 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
1794 {
1795 /* this loop goes through byte by byte, to find end-of-field or
1796 end-of-record separator tags */
1797
1798 /* if (memcmp (tag, "00", 2) && identifier_length)*/
1799 if ( ((titleonly==1&&whichtag==245)||(titleonly==0))
1800 && identifier_length)
1801 {
1802 if (buf[i]==ISO2709_IDFS) {
1803 /* this implies sub-fields for this field */
1804 /* skip sub-field tag, but wrap $a sub-field with <b> & </b>
1805 for HTML if titleonly==1 */
1806 if (buf[i+1]=='a' && titleonly) {
1807 abbrtitle=1;
1808 title=safeappendstr(title,&title_maxlen,&title_curlen,"<b>");
1809 }
1810 i+=identifier_length;
1811 }
1812 /* find end of this (sub-)field */
1813 startofstring=i;
1814 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
1815 buf[i] != ISO2709_FS && i < end_offset)
1816 i++;
1817 /*fprintf (outf, "%c", buf[i++]);*/
1818
1819 /* this only happens the first time around */
1820 if (i==startofstring) continue;
1821
1822 /* now put from $startofstring$ until $i$ into our
1823 string to return */
1824
1825 if (title_curlen+(i-startofstring)>=title_maxlen) {
1826 /* we need to make more room - add max(64,needed) bytes */
1827 if (title_curlen+(i-startofstring)-title_maxlen>63)
1828 title_maxlen+=(i-startofstring)+1;/*+1 for trailing \0 */
1829 else
1830 title_maxlen+=64;
1831 if ((title=realloc(title,title_maxlen))==NULL) {
1832 fprintf(stderr,"malloc failed decoding marc record\n");
1833 return (NULL);
1834 }
1835 }
1836
1837 strncpy(title+title_curlen,buf+startofstring,i-startofstring);
1838 title_curlen+=(i-startofstring);
1839 *(title+title_curlen)='\0';
1840 /* overwrite ISO2709_?S with \0 */
1841 /* *(title+title_curlen+i-startofstring)='\0';*/
1842 /*safeappendstr(title,&title_maxlen,
1843 &title_curlen,buf+startofstring);*/
1844
1845 /* if 'main' title, close HTML </B> tag */
1846 if (abbrtitle) {
1847 title=safeappendstr(title,&title_maxlen,&title_curlen,"</b>");
1848 abbrtitle=0;
1849 }
1850 /* end of this marc sub--field
1851 buf[i]==ISO2709_RS if end of record.
1852 buf[i]==ISO2709_FS if end of field,
1853 buf[i]==ISO2709_IDFS if end of sub-field. */
1854 if (titleonly==0) {
1855 if (buf[i]==ISO2709_IDFS) {
1856 /* there is a following sub-field, so only add whitespace */
1857 title=safeappendstr(title,&title_maxlen,&title_curlen," ");
1858 }
1859 else {
1860 /* end of record, so close HTML table row */
1861 title=safeappendstr(title, &title_maxlen, &title_curlen,
1862 "</td></tr>\n");
1863 }
1864 } /* end of if (titleonly==0) */
1865 } /* end of if ( ((titleonly==1&&....... */
1866 else { /* whichtag not matched (if titleonly) */
1867 /*fprintf (outf, "%c", buf[i++]);*/
1868 /* skip this char for now - should ideally skip whole field */
1869 i++;
1870 }
1871 } /* end of while loop - at end of field or record */
1872 /*fprintf (outf, "\n");*/
1873 /*if (i < end_offset)
1874 fprintf (outf, "-- separator but not at end of field\n");
1875 if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
1876 fprintf (outf, "-- no separator at end of field\n");
1877 */
1878 }
1879
1880 /* at end of whole record. */
1881 if (!titleonly)
1882 title=safeappendstr(title, &title_maxlen, &title_curlen, "</table>\n");
1883 return (title);
1884
1885}
1886static char *getrecordtitle(Z_DatabaseRecord *record) {
1887 return(getmarcfields(record,1));
1888}
1889
1890char *z_getfullRecord(int start) {
1891 Z_APDU *apdu;
1892 Z_DatabaseRecord *record;
1893 char *fullrecord;
1894
1895 fullrecord=NULL;
1896 z_send_getbriefrecords(start,1,1); /* for now, use getbriefrecords */
1897 z_getAPDU(&apdu);
1898
1899 if (apdu->which != Z_APDU_presentResponse) {
1900 /* out-of-order packets.... */
1901 fprintf(stderr,"Not a present response to present request\n");
1902 return NULL;
1903 }
1904
1905 /* just do some double checking */
1906 if (*apdu->u.presentResponse->numberOfRecordsReturned!=1 ||
1907 !apdu->u.presentResponse->records ||
1908 apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
1909 /* something bad has happened... johnmcp */
1910 fprintf (stderr,"Error occured in yaz while getting record (GSDL)\n");
1911 }
1912
1913 record=apdu->u.presentResponse->records->u.databaseOrSurDiagnostics->
1914 records[0]->u.databaseRecord;
1915
1916 return(getmarcfields(record,0));
1917}
1918
1919char **z_getrecordTitles(/*int resultset,*/ int starting, int howmany) {
1920 Z_APDU *apdu;
1921 char **titles;
1922 /* titles will be an array of strings. The first element will really
1923 be an int, saying how many strings follow. Ie 1st string in titles[1] */
1924 int count;
1925 int i;
1926
1927 titles=NULL;
1928
1929 /* WE SHOULD SET THE RECORD FORMAT SOMEWHERE..... USMARC (default)
1930 but may also want SUTRS support. */
1931
1932 /* sends a presentRequest - we need to know the set number - johnmcp */
1933 z_send_getbriefrecords(starting, 1, howmany);
1934 /* CHECK RETURN VALUE (currently only 0) */
1935
1936
1937 z_getAPDU(&apdu);
1938 if (apdu->which != Z_APDU_presentResponse) {
1939 /* we got out-of-sync.... */
1940 fprintf(stderr,"Not a present response to present request\n");
1941 return NULL;
1942 }
1943
1944 print_refid (apdu->u.presentResponse->referenceId);
1945 count=*apdu->u.presentResponse->numberOfRecordsReturned;
1946 setno += count;
1947 if (apdu->u.presentResponse->records) {
1948 /* extract the titles from each record, and return it as an array of
1949 strings */
1950 if (count==1 &&
1951 apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
1952 /* apdu->u.presentResponse->records->which gives a type:
1953 1=databaseOrSurDiagnostics | 2=nonSurrogateDiagnostic |
1954 3=multipleNonSurDiagnostics.
1955 Type 1 implies it is a database record. FROM z-core.h,
1956 NOT prt-proto.h!!!!! */
1957
1958 /* for type 2:
1959 apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which:
1960 1=v2Addinfo | 2=v3Addinfo, and u.v[23]Addinfo is a (char *).
1961
1962 */
1963 titles=malloc(sizeof(char *));
1964 titles[0]=(char *)0;
1965 /* could put error message and titles[1], and set titles[0] to -1. */
1966
1967
1968 }
1969 else /* more than 1 rec returned, so ?has? to be db records (dblcheck!!)*/
1970 {
1971 titles=malloc(sizeof(char *)*count + 1);
1972 /* check malloc succeeded... */
1973 titles[0]=(char *)count;
1974 for (i=1;i<=count;i++) {
1975 titles[i]=getrecordtitle(apdu->u.presentResponse->records->
1976 u.databaseOrSurDiagnostics->records[i-1]->
1977 u.databaseRecord);
1978 }
1979 }
1980 }
1981 else {
1982 titles=malloc(sizeof(char *));
1983 titles[0]=(char *)0;
1984 }
1985 /* printf ("nextResultSetPosition = %d\n",
1986 *apdu->u.presentResponse->nextResultSetPosition); */
1987 return (titles);
1988}
1989
1990
1991int z_getnextAPDU()
1992{
1993 Z_APDU *apdu;
1994 apdu=NULL;
1995
1996 z_getAPDU(&apdu);
1997
1998 switch(apdu->which)
1999 {
2000 case Z_APDU_initResponse:
2001 /* save session parameters for later use */
2002 session_mem = odr_extract_mem(in);
2003 session=apdu->u.initResponse;
2004 /*process_initResponse();*/
2005 break;
2006 case Z_APDU_searchResponse:
2007 process_searchResponse(apdu->u.searchResponse);
2008 break;
2009 case Z_APDU_scanResponse:
2010 process_scanResponse(apdu->u.scanResponse);
2011 break;
2012 case Z_APDU_presentResponse:
2013 print_refid (apdu->u.presentResponse->referenceId);
2014 setno +=
2015 *apdu->u.presentResponse->numberOfRecordsReturned;
2016 if (apdu->u.presentResponse->records)
2017 display_records(apdu->u.presentResponse->records);
2018 else
2019 printf("No records.\n");
2020 printf ("nextResultSetPosition = %d\n",
2021 *apdu->u.presentResponse->nextResultSetPosition);
2022 break;
2023 case Z_APDU_sortResponse:
2024 process_sortResponse(apdu->u.sortResponse);
2025 break;
2026 case Z_APDU_extendedServicesResponse:
2027 printf("Got extended services response\n");
2028 process_ESResponse(apdu->u.extendedServicesResponse);
2029 break;
2030 case Z_APDU_close:
2031 printf("Target has closed the association.\n");
2032 process_close(apdu->u.close);
2033 break;
2034 case Z_APDU_resourceControlRequest:
2035 process_resourceControlRequest
2036 (apdu->u.resourceControlRequest);
2037 break;
2038 case Z_APDU_deleteResultSetResponse:
2039 process_deleteResultSetResponse(apdu->u.
2040 deleteResultSetResponse);
2041 break;
2042 default:
2043 printf("Received unknown APDU type (%d).\n",
2044 apdu->which);
2045 exit(1);
2046 }
2047
2048 /*while (conn && cs_more(conn));*/
2049 return 0;
2050}
Note: See TracBrowser for help on using the repository browser.