root/trunk/gsdl/packages/yaz/client/yaz_zclient.c @ 1343

Revision 1343, 57.3 KB (checked in by johnmcp, 20 years ago)

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

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