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

Last change on this file since 3082 was 3082, checked in by jrm21, 22 years ago

Removed cvs log from file.
Field 92 is not obsolete - changed to say "Local call number" instead.

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