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

Last change on this file since 1616 was 1616, checked in by jrm21, 24 years ago

Now makes hyperlinks for MARC field 856 (Electronic Access/Location),
so you too can point and click...

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