Implemented utility yaz_sort_spec.
[yaz-moved-to-github.git] / client / client.c
1 /*
2  * Copyright (c) 1995-2001, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: client.c,v 1.127 2001-08-08 19:35:06 adam Exp $
6  *
7  */
8
9 /*
10  * This is the obligatory little toy client, whose primary purpose is
11  * to illustrate the use of the YAZ service-level API.
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <time.h>
17
18 #include <yaz/yaz-util.h>
19
20 #include <yaz/tcpip.h>
21 #ifdef USE_XTIMOSI
22 #include <yaz/xmosi.h>
23 #endif
24
25 #include <yaz/proto.h>
26 #include <yaz/marcdisp.h>
27 #include <yaz/diagbib1.h>
28 #include <yaz/otherinfo.h>
29
30 #include <yaz/pquery.h>
31 #include <yaz/sortspec.h>
32
33 #if YAZ_MODULE_ill
34 #include <yaz/ill.h>
35 #endif
36
37 #if YAZ_MODULE_ccl
38 #include <yaz/yaz-ccl.h>
39 #endif
40
41 #if HAVE_READLINE_READLINE_H
42 #include <readline/readline.h>
43 #endif
44 #if HAVE_READLINE_HISTORY_H
45 #include <readline/history.h>
46 #endif
47
48 #include "admin.h"
49
50 #define C_PROMPT "Z> "
51
52 static ODR out, in, print;              /* encoding and decoding streams */
53 static FILE *apdu_file = 0;
54 static COMSTACK conn = 0;               /* our z-association */
55 static Z_IdAuthentication *auth = 0;    /* our current auth definition */
56 char *databaseNames[128];
57 int num_databaseNames = 0;
58 static Z_External *record_last = 0;
59 static int setnumber = 0;               /* current result set number */
60 static int smallSetUpperBound = 0;
61 static int largeSetLowerBound = 1;
62 static int mediumSetPresentNumber = 0;
63 static Z_ElementSetNames *elementSetNames = 0; 
64 static int setno = 1;                   /* current set offset */
65 static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
66 static enum oid_value recordsyntax = VAL_USMARC;
67 static enum oid_value schema = VAL_NONE;
68 static int sent_close = 0;
69 static NMEM session_mem = NULL;      /* memory handle for init-response */
70 static Z_InitResponse *session = 0;     /* session parameters */
71 static char last_scan_line[512] = "0";
72 static char last_scan_query[512] = "0";
73 static char ccl_fields[512] = "default.bib";
74 static char* esPackageName = 0;
75 static char* yazProxy = 0;
76
77 static char last_cmd[32] = "?";
78 static FILE *marcdump = 0;
79 static char *refid = NULL;
80
81 typedef enum {
82     QueryType_Prefix,
83     QueryType_CCL,
84     QueryType_CCL2RPN
85 } QueryType;
86
87 static QueryType queryType = QueryType_Prefix;
88
89 #if YAZ_MODULE_ccl
90 static CCL_bibset bibset;               /* CCL bibset handle */
91 #endif
92
93 ODR getODROutputStream()
94 {
95     return out;
96 }
97
98 void send_apdu(Z_APDU *a)
99 {
100     char *buf;
101     int len;
102
103     if (apdu_file)
104     {
105         z_APDU(print, &a, 0, 0);
106         odr_reset(print);
107     }
108     if (!z_APDU(out, &a, 0, 0))
109     {
110         odr_perror(out, "Encoding APDU");
111         exit(1);
112     }
113     buf = odr_getbuf(out, &len, 0);
114     /* printf ("sending APDU of size %d\n", len); */
115     if (cs_put(conn, buf, len) < 0)
116     {
117         fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
118         exit(1);
119     }
120     odr_reset(out); /* release the APDU structure  */
121 }
122
123 static void print_refid (Z_ReferenceId *id)
124 {
125     if (id)
126     {
127         printf ("ReferenceId: '%.*s'\n", id->len, id->buf);
128     }
129 }
130
131 static Z_ReferenceId *set_refid (ODR out)
132 {
133     Z_ReferenceId *id;
134     if (!refid)
135         return 0;
136     id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
137     id->size = id->len = strlen(refid);
138     id->buf = (unsigned char *) odr_malloc (out, id->len);
139     memcpy (id->buf, refid, id->len);
140     return id;
141 }   
142
143 /* INIT SERVICE ------------------------------- */
144
145 static void send_initRequest(const char* type_and_host)
146 {
147     Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
148     Z_InitRequest *req = apdu->u.initRequest;
149
150     ODR_MASK_SET(req->options, Z_Options_search);
151     ODR_MASK_SET(req->options, Z_Options_present);
152     ODR_MASK_SET(req->options, Z_Options_namedResultSets);
153     ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl);
154     ODR_MASK_SET(req->options, Z_Options_scan);
155     ODR_MASK_SET(req->options, Z_Options_sort);
156     ODR_MASK_SET(req->options, Z_Options_extendedServices);
157     ODR_MASK_SET(req->options, Z_Options_delSet);
158
159     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
160     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
161     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
162
163     *req->maximumRecordSize = 1024*1024;
164     *req->preferredMessageSize = 1024*1024;
165
166     req->idAuthentication = auth;
167
168     req->referenceId = set_refid (out);
169
170     if (yazProxy) 
171         yaz_oi_set_string_oidval(&req->otherInfo, out, VAL_PROXY,
172         1, type_and_host);
173     
174     send_apdu(apdu);
175     printf("Sent initrequest.\n");
176 }
177
178 static int process_initResponse(Z_InitResponse *res)
179 {
180     /* save session parameters for later use */
181     session_mem = odr_extract_mem(in);
182     session = res;
183
184     if (!*res->result)
185         printf("Connection rejected by target.\n");
186     else
187         printf("Connection accepted by target.\n");
188     if (res->implementationId)
189         printf("ID     : %s\n", res->implementationId);
190     if (res->implementationName)
191         printf("Name   : %s\n", res->implementationName);
192     if (res->implementationVersion)
193         printf("Version: %s\n", res->implementationVersion);
194     if (res->userInformationField)
195     {
196         printf("UserInformationfield:\n");
197         if (!z_External(print, (Z_External**)&res-> userInformationField,
198             0, 0))
199         {
200             odr_perror(print, "Printing userinfo\n");
201             odr_reset(print);
202         }
203         if (res->userInformationField->which == Z_External_octet)
204         {
205             printf("Guessing visiblestring:\n");
206             printf("'%s'\n", res->userInformationField->u. octet_aligned->buf);
207         }
208         odr_reset (print);
209     }
210     printf ("Options:");
211     if (ODR_MASK_GET(res->options, Z_Options_search))
212         printf (" search");
213     if (ODR_MASK_GET(res->options, Z_Options_present))
214         printf (" present");
215     if (ODR_MASK_GET(res->options, Z_Options_delSet))
216         printf (" delSet");
217     if (ODR_MASK_GET(res->options, Z_Options_resourceReport))
218         printf (" resourceReport");
219     if (ODR_MASK_GET(res->options, Z_Options_resourceCtrl))
220         printf (" resourceCtrl");
221     if (ODR_MASK_GET(res->options, Z_Options_accessCtrl))
222         printf (" accessCtrl");
223     if (ODR_MASK_GET(res->options, Z_Options_scan))
224         printf (" scan");
225     if (ODR_MASK_GET(res->options, Z_Options_sort))
226         printf (" sort");
227     if (ODR_MASK_GET(res->options, Z_Options_extendedServices))
228         printf (" extendedServices");
229     if (ODR_MASK_GET(res->options, Z_Options_level_1Segmentation))
230         printf (" level1Segmentation");
231     if (ODR_MASK_GET(res->options, Z_Options_level_2Segmentation))
232         printf (" level2Segmentation");
233     if (ODR_MASK_GET(res->options, Z_Options_concurrentOperations))
234         printf (" concurrentOperations");
235     if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
236         printf (" namedResultSets");
237     printf ("\n");
238     fflush (stdout);
239     return 0;
240 }
241
242 static int cmd_base(char *arg)
243 {
244     int i;
245     char *cp;
246
247     if (!*arg)
248     {
249         printf("Usage: base <database> <database> ...\n");
250         return 0;
251     }
252     for (i = 0; i<num_databaseNames; i++)
253         xfree (databaseNames[i]);
254     num_databaseNames = 0;
255     while (1)
256     {
257         if (!(cp = strchr(arg, ' ')))
258             cp = arg + strlen(arg);
259         if (cp - arg < 1)
260             break;
261         databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
262         memcpy (databaseNames[num_databaseNames], arg, cp - arg);
263         databaseNames[num_databaseNames++][cp - arg] = '\0';
264         if (!*cp)
265             break;
266         arg = cp+1;
267     }
268     return 1;
269 }
270
271
272 int cmd_open(char *arg)
273 {
274     void *add;
275     char type_and_host[101], base[101];
276     CS_TYPE t;
277
278     if (conn)
279     {
280         printf("Already connected.\n");
281
282         cs_close (conn);
283         conn = NULL;
284         if (session_mem)
285         {
286             nmem_destroy (session_mem);
287             session_mem = NULL;
288         }
289     }
290     t = tcpip_type;
291     base[0] = '\0';
292     if (sscanf (arg, "%100[^/]/%100s", type_and_host, base) < 1)
293         return 0;
294
295     if(yazProxy) 
296     {
297         conn = cs_create_host(yazProxy, 1, &add);
298     } 
299     else 
300     { 
301         conn = cs_create_host(type_and_host, 1, &add);
302     }
303         
304     if (!conn)
305     {
306         printf ("Couldn't create comstack\n");
307         return 0;
308     }
309     printf("Connecting...");
310     fflush(stdout);
311     if (cs_connect(conn, add) < 0)
312     {
313         printf ("error = %s\n", cs_strerror(conn));
314         if (conn->cerrno == CSYSERR)
315             perror("system");
316         cs_close(conn);
317         conn = 0;
318         return 0;
319     }
320     printf("Ok.\n");
321
322     send_initRequest(type_and_host);
323     if (*base)
324         cmd_base (base);
325     return 2;
326 }
327
328 int cmd_authentication(char *arg)
329 {
330     static Z_IdAuthentication au;
331     static char open[256];
332
333     if (!*arg)
334     {
335         printf("Auth field set to null\n");
336         auth = 0;
337         return 1;
338     }
339     auth = &au;
340     au.which = Z_IdAuthentication_open;
341     au.u.open = open;
342     strcpy(open, arg);
343     return 1;
344 }
345
346 /* SEARCH SERVICE ------------------------------ */
347
348 static void display_variant(Z_Variant *v, int level)
349 {
350     int i;
351
352     for (i = 0; i < v->num_triples; i++)
353     {
354         printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass,
355             *v->triples[i]->type);
356         if (v->triples[i]->which == Z_Triple_internationalString)
357             printf(",value=%s\n", v->triples[i]->value.internationalString);
358         else
359             printf("\n");
360     }
361 }
362
363 static void display_grs1(Z_GenericRecord *r, int level)
364 {
365     int i;
366
367     if (!r)
368         return;
369     for (i = 0; i < r->num_elements; i++)
370     {
371         Z_TaggedElement *t;
372
373         printf("%*s", level * 4, "");
374         t = r->elements[i];
375         printf("(");
376         if (t->tagType)
377             printf("%d,", *t->tagType);
378         else
379             printf("?,");
380         if (t->tagValue->which == Z_StringOrNumeric_numeric)
381             printf("%d) ", *t->tagValue->u.numeric);
382         else
383             printf("%s) ", t->tagValue->u.string);
384         if (t->content->which == Z_ElementData_subtree)
385         {
386             printf("\n");
387             display_grs1(t->content->u.subtree, level+1);
388         }
389         else if (t->content->which == Z_ElementData_string)
390             printf("%s\n", t->content->u.string);
391         else if (t->content->which == Z_ElementData_numeric)
392             printf("%d\n", *t->content->u.numeric);
393         else if (t->content->which == Z_ElementData_oid)
394         {
395             int *ip = t->content->u.oid;
396             oident *oent;
397
398             if ((oent = oid_getentbyoid(t->content->u.oid)))
399                 printf("OID: %s\n", oent->desc);
400             else
401             {
402                 printf("{");
403                 while (ip && *ip >= 0)
404                     printf(" %d", *(ip++));
405                 printf(" }\n");
406             }
407         }
408         else if (t->content->which == Z_ElementData_noDataRequested)
409             printf("[No data requested]\n");
410         else if (t->content->which == Z_ElementData_elementEmpty)
411             printf("[Element empty]\n");
412         else if (t->content->which == Z_ElementData_elementNotThere)
413             printf("[Element not there]\n");
414         else
415             printf("??????\n");
416         if (t->appliedVariant)
417             display_variant(t->appliedVariant, level+1);
418         if (t->metaData && t->metaData->supportedVariants)
419         {
420             int c;
421
422             printf("%*s---- variant list\n", (level+1)*4, "");
423             for (c = 0; c < t->metaData->num_supportedVariants; c++)
424             {
425                 printf("%*svariant #%d\n", (level+1)*4, "", c);
426                 display_variant(t->metaData->supportedVariants[c], level + 2);
427             }
428         }
429     }
430 }
431
432 static void print_record(const unsigned char *buf, size_t len)
433 {
434    size_t i;
435    for (i = 0; i<len; i++)
436        if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
437            fputc (buf[i], stdout);
438        else
439            printf ("\\X%02X", buf[i]);
440    /* add newline if not already added ... */
441    if (i <= 0 || buf[i-1] != '\n')
442        fputc ('\n', stdout);
443 }
444
445 static void display_record(Z_DatabaseRecord *p)
446 {
447     Z_External *r = (Z_External*) p;
448     oident *ent = oid_getentbyoid(r->direct_reference);
449
450     record_last = r;
451     /*
452      * Tell the user what we got.
453      */
454     if (r->direct_reference)
455     {
456         printf("Record type: ");
457         if (ent)
458             printf("%s\n", ent->desc);
459         else if (!odr_oid(print, &r->direct_reference, 0, 0))
460         {
461             odr_perror(print, "print oid");
462             odr_reset(print);
463         }
464     }
465     /* Check if this is a known, ASN.1 type tucked away in an octet string */
466     if (ent && r->which == Z_External_octet)
467     {
468         Z_ext_typeent *type = z_ext_getentbyref(ent->value);
469         void *rr;
470
471         if (type)
472         {
473             /*
474              * Call the given decoder to process the record.
475              */
476             odr_setbuf(in, (char*)p->u.octet_aligned->buf,
477                 p->u.octet_aligned->len, 0);
478             if (!(*type->fun)(in, (char **)&rr, 0, 0))
479             {
480                 odr_perror(in, "Decoding constructed record.");
481                 fprintf(stderr, "[Near %d]\n", odr_offset(in));
482                 fprintf(stderr, "Packet dump:\n---------\n");
483                 odr_dumpBER(stderr, (char*)p->u.octet_aligned->buf,
484                     p->u.octet_aligned->len);
485                 fprintf(stderr, "---------\n");
486                 exit(1);
487             }
488             /*
489              * Note: we throw away the original, BER-encoded record here.
490              * Do something else with it if you want to keep it.
491              */
492             r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
493             r->which = type->what;
494         }
495     }
496     if (ent && ent->value == VAL_SOIF)
497         print_record((const unsigned char *) r->u.octet_aligned->buf, r->u.octet_aligned->len);
498     else if (r->which == Z_External_octet && p->u.octet_aligned->len)
499     {
500         const char *octet_buf = (char*)p->u.octet_aligned->buf;
501         if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML ||
502             ent->value == VAL_HTML)
503             print_record((const unsigned char *) octet_buf,
504                          p->u.octet_aligned->len);
505         else
506         {
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)
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
547 static 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
588 static 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
598 static 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 static int send_deleteResultSetRequest(char *arg)
625 {
626     char names[8][32];
627     int i;
628
629     Z_APDU *apdu = zget_APDU(out, Z_APDU_deleteResultSetRequest);
630     Z_DeleteResultSetRequest *req = apdu->u.deleteResultSetRequest;
631
632     req->referenceId = set_refid (out);
633
634     req->num_resultSetList =
635         sscanf (arg, "%30s %30s %30s %30s %30s %30s %30s %30s",
636                 names[0], names[1], names[2], names[3],
637                 names[4], names[5], names[6], names[7]);
638
639     req->deleteFunction = (int *)
640         odr_malloc (out, sizeof(*req->deleteFunction));
641     if (req->num_resultSetList > 0)
642     {
643         *req->deleteFunction = Z_DeleteRequest_list;
644         req->resultSetList = (char **)
645             odr_malloc (out, sizeof(*req->resultSetList)*
646                         req->num_resultSetList);
647         for (i = 0; i<req->num_resultSetList; i++)
648             req->resultSetList[i] = names[i];
649     }
650     else
651     {
652         *req->deleteFunction = Z_DeleteRequest_all;
653         req->resultSetList = 0;
654     }
655     
656     send_apdu(apdu);
657     printf("Sent deleteResultSetRequest.\n");
658     return 2;
659 }
660
661 static int send_searchRequest(char *arg)
662 {
663     Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
664     Z_SearchRequest *req = apdu->u.searchRequest;
665     Z_Query query;
666     int oid[OID_SIZE];
667 #if YAZ_MODULE_ccl
668     struct ccl_rpn_node *rpn = NULL;
669     int error, pos;
670 #endif
671     char setstring[100];
672     Z_RPNQuery *RPNquery;
673     Odr_oct ccl_query;
674
675 #if YAZ_MODULE_ccl
676     if (queryType == QueryType_CCL2RPN)
677     {
678         rpn = ccl_find_str(bibset, arg, &error, &pos);
679         if (error)
680         {
681             printf("CCL ERROR: %s\n", ccl_err_msg(error));
682             return 0;
683         }
684     }
685 #endif
686     req->referenceId = set_refid (out);
687     if (!strcmp(arg, "@big")) /* strictly for troublemaking */
688     {
689         static unsigned char big[2100];
690         static Odr_oct bigo;
691
692         /* send a very big referenceid to test transport stack etc. */
693         memset(big, 'A', 2100);
694         bigo.len = bigo.size = 2100;
695         bigo.buf = big;
696         req->referenceId = &bigo;
697     }
698     
699     if (setnumber >= 0)
700     {
701         sprintf(setstring, "%d", ++setnumber);
702         req->resultSetName = setstring;
703     }
704     *req->smallSetUpperBound = smallSetUpperBound;
705     *req->largeSetLowerBound = largeSetLowerBound;
706     *req->mediumSetPresentNumber = mediumSetPresentNumber;
707     if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
708         mediumSetPresentNumber > 0))
709     {
710         oident prefsyn;
711
712         prefsyn.proto = protocol;
713         prefsyn.oclass = CLASS_RECSYN;
714         prefsyn.value = recordsyntax;
715         req->preferredRecordSyntax =
716             odr_oiddup(out, oid_ent_to_oid(&prefsyn, oid));
717         req->smallSetElementSetNames =
718             req->mediumSetElementSetNames = elementSetNames;
719     }
720     req->num_databaseNames = num_databaseNames;
721     req->databaseNames = databaseNames;
722
723     req->query = &query;
724
725     switch (queryType)
726     {
727     case QueryType_Prefix:
728         query.which = Z_Query_type_1;
729         RPNquery = p_query_rpn (out, protocol, arg);
730         if (!RPNquery)
731         {
732             printf("Prefix query error\n");
733             return 0;
734         }
735         query.u.type_1 = RPNquery;
736         break;
737     case QueryType_CCL:
738         query.which = Z_Query_type_2;
739         query.u.type_2 = &ccl_query;
740         ccl_query.buf = (unsigned char*) arg;
741         ccl_query.len = strlen(arg);
742         break;
743 #if YAZ_MODULE_ccl
744     case QueryType_CCL2RPN:
745         query.which = Z_Query_type_1;
746         RPNquery = ccl_rpn_query(out, rpn);
747         if (!RPNquery)
748         {
749             printf ("Couldn't convert from CCL to RPN\n");
750             return 0;
751         }
752         query.u.type_1 = RPNquery;
753         ccl_rpn_delete (rpn);
754         break;
755 #endif
756     default:
757         printf ("Unsupported query type\n");
758         return 0;
759     }
760     send_apdu(apdu);
761     setno = 1;
762     printf("Sent searchRequest.\n");
763     return 2;
764 }
765
766 static int process_searchResponse(Z_SearchResponse *res)
767 {
768     printf ("Received SearchResponse.\n");
769     print_refid (res->referenceId);
770     if (*res->searchStatus)
771         printf("Search was a success.\n");
772     else
773         printf("Search was a bloomin' failure.\n");
774     printf("Number of hits: %d, setno %d\n",
775         *res->resultCount, setnumber);
776     printf("records returned: %d\n",
777         *res->numberOfRecordsReturned);
778     setno += *res->numberOfRecordsReturned;
779     if (res->records)
780         display_records(res->records);
781     return 0;
782 }
783
784 static void print_level(int iLevel)
785 {
786     int i;
787     for (i = 0; i < iLevel * 4; i++)
788         printf(" ");
789 }
790
791 static void print_int(int iLevel, const char *pTag, int *pInt)
792 {
793     if (pInt != NULL)
794     {
795         print_level(iLevel);
796         printf("%s: %d\n", pTag, *pInt);
797     }
798 }
799
800 static void print_string(int iLevel, const char *pTag, const char *pString)
801 {
802     if (pString != NULL)
803     {
804         print_level(iLevel);
805         printf("%s: %s\n", pTag, pString);
806     }
807 }
808
809 static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
810 {
811     if (pOid != NULL)
812     {
813         int *pInt = pOid;
814
815         print_level(iLevel);
816         printf("%s:", pTag);
817         for (; *pInt != -1; pInt++)
818             printf(" %d", *pInt);
819         printf("\n");
820     }
821 }
822
823 static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
824 {
825     if (referenceId != NULL)
826     {
827         int i;
828
829         print_level(iLevel);
830         printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
831         for (i = 0; i < referenceId->len; i++)
832             printf("%c", referenceId->buf[i]);
833         printf("\n");
834     }
835 }
836
837 static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
838 {
839     if (pStringNumeric != NULL)
840     {
841         switch (pStringNumeric->which)
842         {
843             case Z_StringOrNumeric_string:
844                 print_string(iLevel, pTag, pStringNumeric->u.string);
845                 break;
846
847             case Z_StringOrNumeric_numeric:
848                 print_int(iLevel, pTag, pStringNumeric->u.numeric);
849                 break;
850
851             default:
852                 print_level(iLevel);
853                 printf("%s: valid type for Z_StringOrNumeric\n", pTag);
854                 break;
855         }
856     }
857 }
858
859 static void print_universe_report_duplicate(int iLevel, Z_UniverseReportDuplicate *pUniverseReportDuplicate)
860 {
861     if (pUniverseReportDuplicate != NULL)
862     {
863         print_level(iLevel);
864         printf("Universe Report Duplicate: \n");
865         iLevel++;
866         print_string_or_numeric(iLevel, "Hit No", pUniverseReportDuplicate->hitno);
867     }
868 }
869
870 static void print_universe_report_hits(int iLevel, Z_UniverseReportHits *pUniverseReportHits)
871 {
872     if (pUniverseReportHits != NULL)
873     {
874         print_level(iLevel);
875         printf("Universe Report Hits: \n");
876         iLevel++;
877         print_string_or_numeric(iLevel, "Database", pUniverseReportHits->database);
878         print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
879     }
880 }
881
882 static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
883 {
884     if (pUniverseReport != NULL)
885     {
886         print_level(iLevel);
887         printf("Universe Report: \n");
888         iLevel++;
889         print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
890         switch (pUniverseReport->which)
891         {
892             case Z_UniverseReport_databaseHits:
893                 print_universe_report_hits(iLevel, pUniverseReport->u.databaseHits);
894                 break;
895
896             case Z_UniverseReport_duplicate:
897                 print_universe_report_duplicate(iLevel, pUniverseReport->u.duplicate);
898                 break;
899
900             default:
901                 print_level(iLevel);
902                 printf("Type: %d\n", pUniverseReport->which);
903                 break;
904         }
905     }
906 }
907
908 static void print_external(int iLevel, Z_External *pExternal)
909 {
910     if (pExternal != NULL)
911     {
912         print_level(iLevel);
913         printf("External: \n");
914         iLevel++;
915         print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
916         print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
917         print_string(iLevel, "Descriptor", pExternal->descriptor);
918         switch (pExternal->which)
919         {
920             case Z_External_universeReport:
921                 print_universe_report(iLevel, pExternal->u.universeReport);
922                 break;
923
924             default:
925                 print_level(iLevel);
926                 printf("Type: %d\n", pExternal->which);
927                 break;
928         }
929     }
930 }
931
932 static int process_resourceControlRequest (Z_ResourceControlRequest *req)
933 {
934     printf ("Received ResourceControlRequest.\n");
935     print_referenceId(1, req->referenceId);
936     print_int(1, "Suspended Flag", req->suspendedFlag);
937     print_int(1, "Partial Results Available", req->partialResultsAvailable);
938     print_int(1, "Response Required", req->responseRequired);
939     print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
940     print_external(1, req->resourceReport);
941     return 0;
942 }
943
944 void process_ESResponse(Z_ExtendedServicesResponse *res)
945 {
946     printf("process_ESResponse status=");
947     switch (*res->operationStatus)
948     {
949     case Z_ExtendedServicesResponse_done:
950         printf ("done\n");
951         break;
952     case Z_ExtendedServicesResponse_accepted:
953         printf ("accepted\n");
954         break;
955     case Z_ExtendedServicesResponse_failure:
956         printf ("failure\n");
957         display_diagrecs(res->diagnostics, res->num_diagnostics);
958         break;
959     }
960     if ( (*res->operationStatus != Z_ExtendedServicesResponse_failure) &&
961         (res->num_diagnostics != 0) ) {
962         display_diagrecs(res->diagnostics, res->num_diagnostics);
963     }
964
965 }
966
967 #if YAZ_MODULE_ill
968
969 const char *get_ill_element (void *clientData, const char *element)
970 {
971     printf ("%s\n", element);
972     return 0;
973 }
974
975 static Z_External *create_external_itemRequest()
976 {
977     struct ill_get_ctl ctl;
978     ILL_ItemRequest *req;
979     Z_External *r = 0;
980     int item_request_size = 0;
981     char *item_request_buf = 0;
982
983     ctl.odr = out;
984     ctl.clientData = 0;
985     ctl.f = get_ill_element;
986
987     req = ill_get_ItemRequest(&ctl, "ill", 0);
988     if (!req)
989         printf ("ill_get_ItemRequest failed\n");
990         
991     if (!ill_ItemRequest (out, &req, 0, 0))
992     {
993         if (apdu_file)
994         {
995             ill_ItemRequest(print, &req, 0, 0);
996             odr_reset(print);
997         }
998         item_request_buf = odr_getbuf (out, &item_request_size, 0);
999         if (item_request_buf)
1000             odr_setbuf (out, item_request_buf, item_request_size, 1);
1001         printf ("Couldn't encode ItemRequest, size %d\n", item_request_size);
1002         return 0;
1003     }
1004     else
1005     {
1006         oident oid;
1007         
1008         item_request_buf = odr_getbuf (out, &item_request_size, 0);
1009         oid.proto = PROTO_GENERAL;
1010         oid.oclass = CLASS_GENERAL;
1011         oid.value = VAL_ISO_ILL_1;
1012         
1013         r = (Z_External *) odr_malloc (out, sizeof(*r));
1014         r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
1015         r->indirect_reference = 0;
1016         r->descriptor = 0;
1017         r->which = Z_External_single;
1018         
1019         r->u.single_ASN1_type = (Odr_oct *)
1020             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
1021         r->u.single_ASN1_type->buf = (unsigned char *)
1022             odr_malloc (out, item_request_size);
1023         r->u.single_ASN1_type->len = item_request_size;
1024         r->u.single_ASN1_type->size = item_request_size;
1025         memcpy (r->u.single_ASN1_type->buf, item_request_buf,
1026                 item_request_size);
1027         printf ("len = %d\n", item_request_size);
1028     }
1029     return r;
1030 }
1031 #endif
1032
1033 #ifdef YAZ_MODULE_ill
1034 static Z_External *create_external_ILL_APDU(int which)
1035 {
1036     struct ill_get_ctl ctl;
1037     ILL_APDU *ill_apdu;
1038     Z_External *r = 0;
1039     int ill_request_size = 0;
1040     char *ill_request_buf = 0;
1041         
1042     ctl.odr = out;
1043     ctl.clientData = 0;
1044     ctl.f = get_ill_element;
1045
1046     ill_apdu = ill_get_APDU(&ctl, "ill", 0);
1047
1048     if (!ill_APDU (out, &ill_apdu, 0, 0))
1049     {
1050         if (apdu_file)
1051         {
1052             printf ("-------------------\n");
1053             ill_APDU(print, &ill_apdu, 0, 0);
1054             odr_reset(print);
1055             printf ("-------------------\n");
1056         }
1057         ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
1058         if (ill_request_buf)
1059             odr_setbuf (out, ill_request_buf, ill_request_size, 1);
1060         printf ("Couldn't encode ILL-Request, size %d\n", ill_request_size);
1061         return 0;
1062     }
1063     else
1064     {
1065         oident oid;
1066         ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
1067         
1068         oid.proto = PROTO_GENERAL;
1069         oid.oclass = CLASS_GENERAL;
1070         oid.value = VAL_ISO_ILL_1;
1071         
1072         r = (Z_External *) odr_malloc (out, sizeof(*r));
1073         r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
1074         r->indirect_reference = 0;
1075         r->descriptor = 0;
1076         r->which = Z_External_single;
1077         
1078         r->u.single_ASN1_type = (Odr_oct *)
1079             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
1080         r->u.single_ASN1_type->buf = (unsigned char *)
1081             odr_malloc (out, ill_request_size);
1082         r->u.single_ASN1_type->len = ill_request_size;
1083         r->u.single_ASN1_type->size = ill_request_size;
1084         memcpy (r->u.single_ASN1_type->buf, ill_request_buf, ill_request_size);
1085         printf ("len = %d\n", ill_request_size);
1086     }
1087     return r;
1088 }
1089 #endif
1090
1091
1092 static Z_External *create_ItemOrderExternal(const char *type, int itemno)
1093 {
1094     Z_External *r = (Z_External *) odr_malloc(out, sizeof(Z_External));
1095     oident ItemOrderRequest;
1096   
1097     ItemOrderRequest.proto = PROTO_Z3950;
1098     ItemOrderRequest.oclass = CLASS_EXTSERV;
1099     ItemOrderRequest.value = VAL_ITEMORDER;
1100  
1101     r->direct_reference = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest)); 
1102     r->indirect_reference = 0;
1103     r->descriptor = 0;
1104
1105     r->which = Z_External_itemOrder;
1106
1107     r->u.itemOrder = (Z_ItemOrder *) odr_malloc(out,sizeof(Z_ItemOrder));
1108     memset(r->u.itemOrder, 0, sizeof(Z_ItemOrder));
1109 #ifdef ASN_COMPILED
1110     r->u.itemOrder->which=Z_IOItemOrder_esRequest;
1111 #else
1112     r->u.itemOrder->which=Z_ItemOrder_esRequest;
1113 #endif
1114
1115     r->u.itemOrder->u.esRequest = (Z_IORequest *) 
1116         odr_malloc(out,sizeof(Z_IORequest));
1117     memset(r->u.itemOrder->u.esRequest, 0, sizeof(Z_IORequest));
1118
1119     r->u.itemOrder->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
1120         odr_malloc(out,sizeof(Z_IOOriginPartToKeep));
1121     memset(r->u.itemOrder->u.esRequest->toKeep, 0, sizeof(Z_IOOriginPartToKeep));
1122     r->u.itemOrder->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
1123         odr_malloc(out,sizeof(Z_IOOriginPartNotToKeep));
1124     memset(r->u.itemOrder->u.esRequest->notToKeep, 0, sizeof(Z_IOOriginPartNotToKeep));
1125
1126     r->u.itemOrder->u.esRequest->toKeep->supplDescription = NULL;
1127     r->u.itemOrder->u.esRequest->toKeep->contact = NULL;
1128     r->u.itemOrder->u.esRequest->toKeep->addlBilling = NULL;
1129
1130     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem =
1131         (Z_IOResultSetItem *) odr_malloc(out, sizeof(Z_IOResultSetItem));
1132     memset(r->u.itemOrder->u.esRequest->notToKeep->resultSetItem, 0, sizeof(Z_IOResultSetItem));
1133     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->resultSetId = "1";
1134
1135     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item =
1136         (int *) odr_malloc(out, sizeof(int));
1137     *r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item = itemno;
1138
1139 #if YAZ_MODULE_ill
1140     if (!strcmp (type, "item") || !strcmp(type, "2"))
1141     {
1142         printf ("using item-request\n");
1143         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
1144             create_external_itemRequest();
1145     }
1146     else if (!strcmp(type, "ill") || !strcmp(type, "1"))
1147     {
1148         printf ("using ILL-request\n");
1149         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
1150             create_external_ILL_APDU(ILL_APDU_ILL_Request);
1151     }
1152     else if (!strcmp(type, "xml") || !strcmp(type, "3"))
1153     {
1154         const char *xml_buf =
1155                 "<itemorder>\n"
1156                 "  <type>request</type>\n"
1157                 "  <libraryNo>000200</libraryNo>\n"
1158                 "  <borrowerTicketNo> 1212 </borrowerTicketNo>\n"
1159                 "</itemorder>";
1160         r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
1161             z_ext_record (out, VAL_TEXT_XML, xml_buf, strlen(xml_buf));
1162     }
1163     else
1164         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
1165
1166 #else
1167     r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
1168 #endif
1169     return r;
1170 }
1171
1172 static int send_itemorder(const char *type, int itemno)
1173 {
1174     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
1175     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
1176     oident ItemOrderRequest;
1177
1178     ItemOrderRequest.proto = PROTO_Z3950;
1179     ItemOrderRequest.oclass = CLASS_EXTSERV;
1180     ItemOrderRequest.value = VAL_ITEMORDER;
1181     req->packageType = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest));
1182     req->packageName = esPackageName;
1183
1184     req->taskSpecificParameters = create_ItemOrderExternal(type, itemno);
1185
1186     send_apdu(apdu);
1187     return 0;
1188 }
1189
1190 static int cmd_update(char *arg)
1191 {
1192     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
1193     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
1194     Z_External *r;
1195     int oid[OID_SIZE];
1196     Z_IUOriginPartToKeep *toKeep;
1197     Z_IUSuppliedRecords *notToKeep;
1198     oident update_oid;
1199     printf ("Update request\n");
1200     fflush(stdout);
1201
1202     if (!record_last)
1203         return 0;
1204     update_oid.proto = PROTO_Z3950;
1205     update_oid.oclass = CLASS_EXTSERV;
1206     update_oid.value = VAL_DBUPDATE;
1207     oid_ent_to_oid (&update_oid, oid);
1208     req->packageType = odr_oiddup(out,oid);
1209     req->packageName = esPackageName;
1210     
1211     req->referenceId = set_refid (out);
1212
1213     r = req->taskSpecificParameters = (Z_External *)
1214         odr_malloc (out, sizeof(*r));
1215     r->direct_reference = odr_oiddup(out,oid);
1216     r->indirect_reference = 0;
1217     r->descriptor = 0;
1218     r->which = Z_External_update;
1219     r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
1220     r->u.update->which = Z_IUUpdate_esRequest;
1221     r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
1222         odr_malloc(out, sizeof(*r->u.update->u.esRequest));
1223     toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
1224         odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
1225     toKeep->databaseName = databaseNames[0];
1226     toKeep->schema = 0;
1227     toKeep->elementSetName = 0;
1228     toKeep->actionQualifier = 0;
1229     toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
1230     *toKeep->action = Z_IUOriginPartToKeep_recordInsert;
1231
1232     notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
1233         odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
1234     notToKeep->num = 1;
1235     notToKeep->elements = (Z_IUSuppliedRecords_elem **)
1236         odr_malloc(out, sizeof(*notToKeep->elements));
1237     notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
1238         odr_malloc(out, sizeof(**notToKeep->elements));
1239     notToKeep->elements[0]->u.number = 0;
1240     notToKeep->elements[0]->supplementalId = 0;
1241     notToKeep->elements[0]->correlationInfo = 0;
1242     notToKeep->elements[0]->record = record_last;
1243     
1244     send_apdu(apdu);
1245
1246     return 2;
1247 }
1248
1249 /* II : Added to do DALI Item Order Extended services request */
1250 static int cmd_itemorder(char *arg)
1251 {
1252     char type[12];
1253     int itemno;
1254
1255     if (sscanf (arg, "%10s %d", type, &itemno) != 2)
1256         return 0;
1257
1258     printf("Item order request\n");
1259     fflush(stdout);
1260     send_itemorder(type, itemno);
1261     return(2);
1262 }
1263
1264 static int cmd_find(char *arg)
1265 {
1266     if (!*arg)
1267     {
1268         printf("Find what?\n");
1269         return 0;
1270     }
1271     if (!conn)
1272     {
1273         printf("Not connected yet\n");
1274         return 0;
1275     }
1276     if (!send_searchRequest(arg))
1277         return 0;
1278     return 2;
1279 }
1280
1281 static int cmd_delete(char *arg)
1282 {
1283     if (!conn)
1284     {
1285         printf("Not connected yet\n");
1286         return 0;
1287     }
1288     if (!send_deleteResultSetRequest(arg))
1289         return 0;
1290     return 2;
1291 }
1292
1293 static int cmd_ssub(char *arg)
1294 {
1295     if (!(smallSetUpperBound = atoi(arg)))
1296         return 0;
1297     return 1;
1298 }
1299
1300 static int cmd_lslb(char *arg)
1301 {
1302     if (!(largeSetLowerBound = atoi(arg)))
1303         return 0;
1304     return 1;
1305 }
1306
1307 static int cmd_mspn(char *arg)
1308 {
1309     if (!(mediumSetPresentNumber = atoi(arg)))
1310         return 0;
1311     return 1;
1312 }
1313
1314 static int cmd_status(char *arg)
1315 {
1316     printf("smallSetUpperBound: %d\n", smallSetUpperBound);
1317     printf("largeSetLowerBound: %d\n", largeSetLowerBound);
1318     printf("mediumSetPresentNumber: %d\n", mediumSetPresentNumber);
1319     return 1;
1320 }
1321
1322 static int cmd_setnames(char *arg)
1323 {
1324     if (setnumber < 0)
1325     {
1326         printf("Set numbering enabled.\n");
1327         setnumber = 0;
1328     }
1329     else
1330     {
1331         printf("Set numbering disabled.\n");
1332         setnumber = -1;
1333     }
1334     return 1;
1335 }
1336
1337 /* PRESENT SERVICE ----------------------------- */
1338
1339 static int send_presentRequest(char *arg)
1340 {
1341     Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
1342     Z_PresentRequest *req = apdu->u.presentRequest;
1343     Z_RecordComposition compo;
1344     oident prefsyn;
1345     int nos = 1;
1346     int oid[OID_SIZE];
1347     char *p;
1348     char setstring[100];
1349
1350     req->referenceId = set_refid (out);
1351     if ((p = strchr(arg, '+')))
1352     {
1353         nos = atoi(p + 1);
1354         *p = 0;
1355     }
1356     if (*arg)
1357         setno = atoi(arg);
1358     if (p && (p=strchr(p+1, '+')))
1359     {
1360         strcpy (setstring, p+1);
1361         req->resultSetId = setstring;
1362     }
1363     else if (setnumber >= 0)
1364     {
1365         sprintf(setstring, "%d", setnumber);
1366         req->resultSetId = setstring;
1367     }
1368 #if 0
1369     if (1)
1370     {
1371         static Z_Range range;
1372         static Z_Range *rangep = &range;
1373     req->num_ranges = 1;
1374 #endif
1375     req->resultSetStartPoint = &setno;
1376     req->numberOfRecordsRequested = &nos;
1377     prefsyn.proto = protocol;
1378     prefsyn.oclass = CLASS_RECSYN;
1379     prefsyn.value = recordsyntax;
1380     req->preferredRecordSyntax =
1381         odr_oiddup (out, oid_ent_to_oid(&prefsyn, oid));
1382
1383     if (schema != VAL_NONE)
1384     {
1385         oident prefschema;
1386
1387         prefschema.proto = protocol;
1388         prefschema.oclass = CLASS_SCHEMA;
1389         prefschema.value = schema;
1390
1391         req->recordComposition = &compo;
1392         compo.which = Z_RecordComp_complex;
1393         compo.u.complex = (Z_CompSpec *)
1394             odr_malloc(out, sizeof(*compo.u.complex));
1395         compo.u.complex->selectAlternativeSyntax = (bool_t *) 
1396             odr_malloc(out, sizeof(bool_t));
1397         *compo.u.complex->selectAlternativeSyntax = 0;
1398
1399         compo.u.complex->generic = (Z_Specification *)
1400             odr_malloc(out, sizeof(*compo.u.complex->generic));
1401         compo.u.complex->generic->schema = (Odr_oid *)
1402             odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
1403         if (!compo.u.complex->generic->schema)
1404         {
1405             /* OID wasn't a schema! Try record syntax instead. */
1406             prefschema.oclass = CLASS_RECSYN;
1407             compo.u.complex->generic->schema = (Odr_oid *)
1408                 odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
1409         }
1410         if (!elementSetNames)
1411             compo.u.complex->generic->elementSpec = 0;
1412         else
1413         {
1414             compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
1415                 odr_malloc(out, sizeof(Z_ElementSpec));
1416             compo.u.complex->generic->elementSpec->which =
1417                 Z_ElementSpec_elementSetName;
1418             compo.u.complex->generic->elementSpec->u.elementSetName =
1419                 elementSetNames->u.generic;
1420         }
1421         compo.u.complex->num_dbSpecific = 0;
1422         compo.u.complex->dbSpecific = 0;
1423         compo.u.complex->num_recordSyntax = 0;
1424         compo.u.complex->recordSyntax = 0;
1425     }
1426     else if (elementSetNames)
1427     {
1428         req->recordComposition = &compo;
1429         compo.which = Z_RecordComp_simple;
1430         compo.u.simple = elementSetNames;
1431     }
1432     send_apdu(apdu);
1433     printf("Sent presentRequest (%d+%d).\n", setno, nos);
1434     return 2;
1435 }
1436
1437 void process_close(Z_Close *req)
1438 {
1439     Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
1440     Z_Close *res = apdu->u.close;
1441
1442     static char *reasons[] =
1443     {
1444         "finished",
1445         "shutdown",
1446         "system problem",
1447         "cost limit reached",
1448         "resources",
1449         "security violation",
1450         "protocolError",
1451         "lack of activity",
1452         "peer abort",
1453         "unspecified"
1454     };
1455
1456     printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
1457         req->diagnosticInformation ? req->diagnosticInformation : "NULL");
1458     if (sent_close)
1459     {
1460         cs_close (conn);
1461         conn = NULL;
1462         if (session_mem)
1463         {
1464             nmem_destroy (session_mem);
1465             session_mem = NULL;
1466         }
1467         sent_close = 0;
1468     }
1469     else
1470     {
1471         *res->closeReason = Z_Close_finished;
1472         send_apdu(apdu);
1473         printf("Sent response.\n");
1474         sent_close = 1;
1475     }
1476 }
1477
1478 static int cmd_show(char *arg)
1479 {
1480     if (!conn)
1481     {
1482         printf("Not connected yet\n");
1483         return 0;
1484     }
1485     if (!send_presentRequest(arg))
1486         return 0;
1487     return 2;
1488 }
1489
1490 int cmd_quit(char *arg)
1491 {
1492     printf("See you later, alligator.\n");
1493     exit(0);
1494     return 0;
1495 }
1496
1497 int cmd_cancel(char *arg)
1498 {
1499     Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
1500     Z_TriggerResourceControlRequest *req =
1501         apdu->u.triggerResourceControlRequest;
1502     bool_t rfalse = 0;
1503     
1504     if (!conn)
1505     {
1506         printf("Session not initialized yet\n");
1507         return 0;
1508     }
1509     if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
1510     {
1511         printf("Target doesn't support cancel (trigger resource ctrl)\n");
1512         return 0;
1513     }
1514     *req->requestedAction = Z_TriggerResourceCtrl_cancel;
1515     req->resultSetWanted = &rfalse;
1516
1517     send_apdu(apdu);
1518     printf("Sent cancel request\n");
1519     return 2;
1520 }
1521
1522 int send_scanrequest(const char *query, int pp, int num, const char *term)
1523 {
1524     Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
1525     Z_ScanRequest *req = apdu->u.scanRequest;
1526     int use_rpn = 1;
1527 #if YAZ_MODULE_ccl
1528     int oid[OID_SIZE];
1529     
1530     if (queryType == QueryType_CCL2RPN)
1531     {
1532         oident bib1;
1533         int error, pos;
1534         struct ccl_rpn_node *rpn;
1535
1536         rpn = ccl_find_str (bibset,  query, &error, &pos);
1537         if (error)
1538         {
1539             printf("CCL ERROR: %s\n", ccl_err_msg(error));
1540             return -1;
1541         }
1542         use_rpn = 0;
1543         bib1.proto = PROTO_Z3950;
1544         bib1.oclass = CLASS_ATTSET;
1545         bib1.value = VAL_BIB1;
1546         req->attributeSet = oid_ent_to_oid (&bib1, oid);
1547         if (!(req->termListAndStartPoint = ccl_scan_query (out, rpn)))
1548         {
1549             printf("Couldn't convert CCL to Scan term\n");
1550             return -1;
1551         }
1552         ccl_rpn_delete (rpn);
1553     }
1554 #endif
1555     if (use_rpn && !(req->termListAndStartPoint =
1556                      p_query_scan(out, protocol, &req->attributeSet, query)))
1557     {
1558         printf("Prefix query error\n");
1559         return -1;
1560     }
1561     if (term && *term)
1562     {
1563         if (req->termListAndStartPoint->term &&
1564             req->termListAndStartPoint->term->which == Z_Term_general &&
1565             req->termListAndStartPoint->term->u.general)
1566         {
1567             req->termListAndStartPoint->term->u.general->buf =
1568                 (unsigned char *) odr_strdup(out, term);
1569             req->termListAndStartPoint->term->u.general->len =
1570                 req->termListAndStartPoint->term->u.general->size =
1571                 strlen(term);
1572         }
1573     }
1574     req->referenceId = set_refid (out);
1575     req->num_databaseNames = num_databaseNames;
1576     req->databaseNames = databaseNames;
1577     req->numberOfTermsRequested = &num;
1578     req->preferredPositionInResponse = &pp;
1579     send_apdu(apdu);
1580     return 2;
1581 }
1582
1583 int send_sortrequest(char *arg, int newset)
1584 {
1585     Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
1586     Z_SortRequest *req = apdu->u.sortRequest;
1587     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
1588         odr_malloc (out, sizeof(*sksl));
1589     char setstring[32];
1590
1591     if (setnumber >= 0)
1592         sprintf (setstring, "%d", setnumber);
1593     else
1594         sprintf (setstring, "default");
1595
1596     req->referenceId = set_refid (out);
1597
1598 #ifdef ASN_COMPILED
1599     req->num_inputResultSetNames = 1;
1600     req->inputResultSetNames = (Z_InternationalString **)
1601         odr_malloc (out, sizeof(*req->inputResultSetNames));
1602     req->inputResultSetNames[0] = odr_strdup (out, setstring);
1603 #else
1604     req->inputResultSetNames =
1605         (Z_StringList *)odr_malloc (out, sizeof(*req->inputResultSetNames));
1606     req->inputResultSetNames->num_strings = 1;
1607     req->inputResultSetNames->strings =
1608         (char **)odr_malloc (out, sizeof(*req->inputResultSetNames->strings));
1609     req->inputResultSetNames->strings[0] =
1610         odr_strdup (out, setstring);
1611 #endif
1612
1613     if (newset && setnumber >= 0)
1614         sprintf (setstring, "%d", ++setnumber);
1615
1616     req->sortedResultSetName = odr_strdup (out, setstring);
1617
1618     req->sortSequence = yaz_sort_spec (out, arg);
1619     if (!req->sortSequence)
1620     {
1621         printf ("Missing sort specifications\n");
1622         return -1;
1623     }
1624     send_apdu(apdu);
1625     return 2;
1626 }
1627
1628 void display_term(Z_TermInfo *t)
1629 {
1630     if (t->term->which == Z_Term_general)
1631     {
1632         printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
1633         sprintf(last_scan_line, "%.*s", t->term->u.general->len,
1634             t->term->u.general->buf);
1635     }
1636     else
1637         printf("Term (not general)");
1638     if (t->globalOccurrences)
1639         printf (" (%d)\n", *t->globalOccurrences);
1640     else
1641         printf ("\n");
1642 }
1643
1644 void process_scanResponse(Z_ScanResponse *res)
1645 {
1646     int i;
1647     Z_Entry **entries = NULL;
1648     int num_entries = 0;
1649    
1650     printf("Received ScanResponse\n"); 
1651     print_refid (res->referenceId);
1652     printf("%d entries", *res->numberOfEntriesReturned);
1653     if (res->positionOfTerm)
1654         printf (", position=%d", *res->positionOfTerm); 
1655     printf ("\n");
1656     if (*res->scanStatus != Z_Scan_success)
1657         printf("Scan returned code %d\n", *res->scanStatus);
1658     if (!res->entries)
1659         return;
1660     if ((entries = res->entries->entries))
1661         num_entries = res->entries->num_entries;
1662     for (i = 0; i < num_entries; i++)
1663     {
1664         int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
1665         if (entries[i]->which == Z_Entry_termInfo)
1666         {
1667             printf("%c ", i + 1 == pos_term ? '*' : ' ');
1668             display_term(entries[i]->u.termInfo);
1669         }
1670         else
1671             display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
1672     }
1673     if (res->entries->nonsurrogateDiagnostics)
1674         display_diagrecs (res->entries->nonsurrogateDiagnostics,
1675                           res->entries->num_nonsurrogateDiagnostics);
1676 }
1677
1678 void process_sortResponse(Z_SortResponse *res)
1679 {
1680     printf("Received SortResponse: status=");
1681     switch (*res->sortStatus)
1682     {
1683     case Z_SortStatus_success:
1684         printf ("success"); break;
1685     case Z_SortStatus_partial_1:
1686         printf ("partial"); break;
1687     case Z_SortStatus_failure:
1688         printf ("failure"); break;
1689     default:
1690         printf ("unknown (%d)", *res->sortStatus);
1691     }
1692     printf ("\n");
1693     print_refid (res->referenceId);
1694 #ifdef ASN_COMPILED
1695     if (res->diagnostics)
1696         display_diagrecs(res->diagnostics,
1697                          res->num_diagnostics);
1698 #else
1699     if (res->diagnostics)
1700         display_diagrecs(res->diagnostics->diagRecs,
1701                          res->diagnostics->num_diagRecs);
1702 #endif
1703 }
1704
1705 void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
1706 {
1707     printf("Got deleteResultSetResponse status=%d\n",
1708            *res->deleteOperationStatus);
1709     if (res->deleteListStatuses)
1710     {
1711         int i;
1712         for (i = 0; i < res->deleteListStatuses->num; i++)
1713         {
1714             printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
1715                     *res->deleteListStatuses->elements[i]->status);
1716         }
1717     }
1718 }
1719
1720 int cmd_sort_generic(char *arg, int newset)
1721 {
1722     if (!conn)
1723     {
1724         printf("Session not initialized yet\n");
1725         return 0;
1726     }
1727     if (!ODR_MASK_GET(session->options, Z_Options_sort))
1728     {
1729         printf("Target doesn't support sort\n");
1730         return 0;
1731     }
1732     if (*arg)
1733     {
1734         if (send_sortrequest(arg, newset) < 0)
1735             return 0;
1736         return 2;
1737     }
1738     return 0;
1739 }
1740
1741 int cmd_sort(char *arg)
1742 {
1743     return cmd_sort_generic (arg, 0);
1744 }
1745
1746 int cmd_sort_newset (char *arg)
1747 {
1748     return cmd_sort_generic (arg, 1);
1749 }
1750
1751 int cmd_scan(char *arg)
1752 {
1753     if (!conn)
1754     {
1755         printf("Session not initialized yet\n");
1756         return 0;
1757     }
1758     if (!ODR_MASK_GET(session->options, Z_Options_scan))
1759     {
1760         printf("Target doesn't support scan\n");
1761         return 0;
1762     }
1763     if (*arg)
1764     {
1765         strcpy (last_scan_query, arg);
1766         if (send_scanrequest(arg, 1, 20, 0) < 0)
1767             return 0;
1768     }
1769     else
1770     {
1771         if (send_scanrequest(last_scan_query, 1, 20, last_scan_line) < 0)
1772             return 0;
1773     }
1774     return 2;
1775 }
1776
1777 int cmd_schema(char *arg)
1778 {
1779     if (!arg || !*arg)
1780     {
1781         schema = VAL_NONE;
1782         return 1;
1783     }
1784     schema = oid_getvalbyname (arg);
1785     if (schema == VAL_NONE)
1786     {
1787         printf ("unknown schema\n");
1788         return 0;
1789     }
1790     return 1;
1791 }
1792
1793 int cmd_format(char *arg)
1794 {
1795     if (!arg || !*arg)
1796     {
1797         printf("Usage: format <recordsyntax>\n");
1798         return 0;
1799     }
1800     recordsyntax = oid_getvalbyname (arg);
1801     if (recordsyntax == VAL_NONE)
1802     {
1803         printf ("unknown record syntax\n");
1804         return 0;
1805     }
1806     return 1;
1807 }
1808
1809 int cmd_elements(char *arg)
1810 {
1811     static Z_ElementSetNames esn;
1812     static char what[100];
1813
1814     if (!arg || !*arg)
1815     {
1816         elementSetNames = 0;
1817         return 1;
1818     }
1819     strcpy(what, arg);
1820     esn.which = Z_ElementSetNames_generic;
1821     esn.u.generic = what;
1822     elementSetNames = &esn;
1823     return 1;
1824 }
1825
1826 int cmd_attributeset(char *arg)
1827 {
1828     char what[100];
1829
1830     if (!arg || !*arg)
1831     {
1832         printf("Usage: attributeset <setname>\n");
1833         return 0;
1834     }
1835     sscanf(arg, "%s", what);
1836     if (p_query_attset (what))
1837     {
1838         printf("Unknown attribute set name\n");
1839         return 0;
1840     }
1841     return 1;
1842 }
1843
1844 int cmd_querytype (char *arg)
1845 {
1846     if (!strcmp (arg, "ccl"))
1847         queryType = QueryType_CCL;
1848     else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
1849         queryType = QueryType_Prefix;
1850 #if YAZ_MODULE_ccl
1851     else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn"))
1852         queryType = QueryType_CCL2RPN;
1853 #endif
1854     else
1855     {
1856         printf ("Querytype must be one of:\n");
1857         printf (" prefix         - Prefix query\n");
1858         printf (" ccl            - CCL query\n");
1859 #if YAZ_MODULE_ccl
1860         printf (" ccl2rpn        - CCL query converted to RPN\n");
1861 #endif
1862         return 0;
1863     }
1864     return 1;
1865 }
1866
1867 int cmd_refid (char *arg)
1868 {
1869     xfree (refid);
1870     refid = NULL;
1871     if (*arg)
1872     {
1873         refid = (char *) xmalloc (strlen(arg)+1);
1874         strcpy (refid, arg);
1875     }
1876     return 1;
1877 }
1878
1879 int cmd_close(char *arg)
1880 {
1881     Z_APDU *apdu;
1882     Z_Close *req;
1883     if (!conn)
1884         return 0;
1885
1886     apdu = zget_APDU(out, Z_APDU_close);
1887     req = apdu->u.close;
1888     *req->closeReason = Z_Close_finished;
1889     send_apdu(apdu);
1890     printf("Sent close request.\n");
1891     sent_close = 1;
1892     return 2;
1893 }
1894
1895 int cmd_packagename(char* arg) {
1896     xfree (esPackageName);
1897     esPackageName = NULL;
1898     if (*arg)
1899     {
1900         esPackageName = (char *) xmalloc (strlen(arg)+1);
1901         strcpy (esPackageName, arg);
1902     }
1903     return 1;
1904 };
1905
1906 int cmd_proxy(char* arg) {
1907     xfree (yazProxy);
1908     yazProxy = NULL;
1909     if (*arg)
1910     {
1911         yazProxy = (char *) xmalloc (strlen(arg)+1);
1912         strcpy (yazProxy, arg);
1913     } 
1914     return 1;
1915 };
1916
1917 static void initialize(void)
1918 {
1919 #if YAZ_MODULE_ccl
1920     FILE *inf;
1921 #endif
1922     nmem_init();
1923     if (!(out = odr_createmem(ODR_ENCODE)) ||
1924         !(in = odr_createmem(ODR_DECODE)) ||
1925         !(print = odr_createmem(ODR_PRINT)))
1926     {
1927         fprintf(stderr, "failed to allocate ODR streams\n");
1928         exit(1);
1929     }
1930     setvbuf(stdout, 0, _IONBF, 0);
1931     if (apdu_file)
1932         odr_setprint(print, apdu_file);
1933
1934 #if YAZ_MODULE_ccl
1935     bibset = ccl_qual_mk (); 
1936     inf = fopen (ccl_fields, "r");
1937     if (inf)
1938     {
1939         ccl_qual_file (bibset, inf);
1940         fclose (inf);
1941     }
1942 #endif
1943     cmd_base("Default");
1944 }
1945
1946 static int client(int wait)
1947 {
1948     static struct {
1949         char *cmd;
1950         int (*fun)(char *arg);
1951         char *ad;
1952     } cmd[] = {
1953         {"open", cmd_open, "('tcp'|'osi')':'[<tsel>'/']<host>[':'<port>]"},
1954         {"quit", cmd_quit, ""},
1955         {"find", cmd_find, "<query>"},
1956         {"delete", cmd_delete, "<setname>"},
1957         {"base", cmd_base, "<base-name>"},
1958         {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]"},
1959         {"scan", cmd_scan, "<term>"},
1960         {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ..."},
1961         {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ..."},
1962         {"authentication", cmd_authentication, "<acctstring>"},
1963         {"lslb", cmd_lslb, "<largeSetLowerBound>"},
1964         {"ssub", cmd_ssub, "<smallSetUpperBound>"},
1965         {"mspn", cmd_mspn, "<mediumSetPresentNumber>"},
1966         {"status", cmd_status, ""},
1967         {"setnames", cmd_setnames, ""},
1968         {"cancel", cmd_cancel, ""},
1969         {"format", cmd_format, "<recordsyntax>"},
1970         {"schema", cmd_schema, "<schema>"},
1971         {"elements", cmd_elements, "<elementSetName>"},
1972         {"close", cmd_close, ""},
1973         {"attributeset", cmd_attributeset, "<attrset>"},
1974         {"querytype", cmd_querytype, "<type>"},
1975         {"refid", cmd_refid, "<id>"},
1976         {"itemorder", cmd_itemorder, "ill|item <itemno>"},
1977         {"update", cmd_update, "<item>"},
1978         {"packagename", cmd_packagename, "<packagename>"},
1979         {"proxy", cmd_proxy, "('tcp'|'osi')':'[<tsel>'/']<host>[':'<port>]"},
1980 #ifdef ASN_COMPILED
1981         /* Server Admin Functions */
1982         {"adm-reindex", cmd_adm_reindex, "<database-name>"},
1983         {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>"},
1984         {"adm-create", cmd_adm_create, ""},
1985         {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>"},
1986         {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>"},
1987         {"adm-refresh", cmd_adm_refresh, ""},
1988         {"adm-commit", cmd_adm_commit, ""},
1989         {"adm-shutdown", cmd_adm_shutdown, ""},
1990         {"adm-startup", cmd_adm_startup, ""},
1991 #endif
1992         {0,0}
1993     };
1994     char *netbuffer= 0;
1995     int netbufferlen = 0;
1996     int i;
1997     Z_APDU *apdu;
1998 #if HAVE_GETTIMEOFDAY
1999     struct timeval tv_start, tv_end;
2000     gettimeofday (&tv_start, 0);
2001 #endif
2002
2003     while (1)
2004     {
2005         int res;
2006 #ifdef USE_SELECT
2007         fd_set input;
2008 #endif
2009         char line[1024], word[32], arg[1024];
2010         
2011 #ifdef USE_SELECT
2012         FD_ZERO(&input);
2013         FD_SET(0, &input);
2014         if (conn)
2015             FD_SET(cs_fileno(conn), &input);
2016         if ((res = select(20, &input, 0, 0, 0)) < 0)
2017         {
2018             perror("select");
2019             exit(1);
2020         }
2021         if (!res)
2022             continue;
2023         if (!wait && FD_ISSET(0, &input))
2024 #else
2025         if (!wait)
2026 #endif
2027         {
2028 #if HAVE_READLINE_READLINE_H
2029             char* line_in;
2030             line_in=readline(C_PROMPT);
2031             if (!line_in)
2032                 break;
2033 #if HAVE_READLINE_HISTORY_H
2034             if (*line_in)
2035                 add_history(line_in);
2036 #endif
2037             strcpy(line,line_in);
2038             free (line_in);
2039 #else    
2040             char *end_p;
2041             printf (C_PROMPT);
2042             fflush(stdout);
2043             if (!fgets(line, 1023, stdin))
2044                 break;
2045             if ((end_p = strchr (line, '\n')))
2046                 *end_p = '\0';
2047 #endif 
2048 #if HAVE_GETTIMEOFDAY
2049             gettimeofday (&tv_start, 0);
2050 #endif
2051
2052             if ((res = sscanf(line, "%31s %1023[^;]", word, arg)) <= 0)
2053             {
2054                 strcpy(word, last_cmd);
2055                 *arg = '\0';
2056             }
2057             else if (res == 1)
2058                 *arg = 0;
2059             strcpy(last_cmd, word);
2060             for (i = 0; cmd[i].cmd; i++)
2061                 if (!strncmp(cmd[i].cmd, word, strlen(word)))
2062                 {
2063                     res = (*cmd[i].fun)(arg);
2064                     break;
2065                 }
2066             if (!cmd[i].cmd) /* dump our help-screen */
2067             {
2068                 printf("Unknown command: %s.\n", word);
2069                 printf("Currently recognized commands:\n");
2070                 for (i = 0; cmd[i].cmd; i++)
2071                     printf("   %s %s\n", cmd[i].cmd, cmd[i].ad);
2072                 res = 1;
2073             }
2074             if (res < 2)
2075             {
2076                 continue;
2077             }
2078         }
2079         wait = 0;
2080         if (conn
2081 #ifdef USE_SELECT
2082             && FD_ISSET(cs_fileno(conn), &input)
2083 #endif
2084             )
2085         {
2086             do
2087             {
2088                 if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0)
2089                 {
2090                     perror("cs_get");
2091                     exit(1);
2092                 }
2093                 if (!res)
2094                 {
2095                     printf("Target closed connection.\n");
2096                     exit(1);
2097                 }
2098                 odr_reset(in); /* release APDU from last round */
2099                 record_last = 0;
2100                 odr_setbuf(in, netbuffer, res, 0);
2101                 if (!z_APDU(in, &apdu, 0, 0))
2102                 {
2103                     odr_perror(in, "Decoding incoming APDU");
2104                     fprintf(stderr, "[Near %d]\n", odr_offset(in));
2105                     fprintf(stderr, "Packet dump:\n---------\n");
2106                     odr_dumpBER(stderr, netbuffer, res);
2107                     fprintf(stderr, "---------\n");
2108                     if (apdu_file)
2109                         z_APDU(print, &apdu, 0, 0);
2110                     exit(1);
2111                 }
2112                 if (apdu_file && !z_APDU(print, &apdu, 0, 0))
2113                 {
2114                     odr_perror(print, "Failed to print incoming APDU");
2115                     odr_reset(print);
2116                     continue;
2117                 }
2118                 switch(apdu->which)
2119                 {
2120                 case Z_APDU_initResponse:
2121                     process_initResponse(apdu->u.initResponse);
2122                     break;
2123                 case Z_APDU_searchResponse:
2124                     process_searchResponse(apdu->u.searchResponse);
2125                     break;
2126                 case Z_APDU_scanResponse:
2127                     process_scanResponse(apdu->u.scanResponse);
2128                     break;
2129                 case Z_APDU_presentResponse:
2130                     print_refid (apdu->u.presentResponse->referenceId);
2131                     setno +=
2132                         *apdu->u.presentResponse->numberOfRecordsReturned;
2133                     if (apdu->u.presentResponse->records)
2134                         display_records(apdu->u.presentResponse->records);
2135                     else
2136                         printf("No records.\n");
2137                     printf ("nextResultSetPosition = %d\n",
2138                         *apdu->u.presentResponse->nextResultSetPosition);
2139                     break;
2140                 case Z_APDU_sortResponse:
2141                     process_sortResponse(apdu->u.sortResponse);
2142                     break;
2143                 case Z_APDU_extendedServicesResponse:
2144                     printf("Got extended services response\n");
2145                     process_ESResponse(apdu->u.extendedServicesResponse);
2146                     break;
2147                 case Z_APDU_close:
2148                     printf("Target has closed the association.\n");
2149                     process_close(apdu->u.close);
2150                     break;
2151                 case Z_APDU_resourceControlRequest:
2152                     process_resourceControlRequest
2153                         (apdu->u.resourceControlRequest);
2154                     break;
2155                 case Z_APDU_deleteResultSetResponse:
2156                     process_deleteResultSetResponse(apdu->u.
2157                                                     deleteResultSetResponse);
2158                     break;
2159                 default:
2160                     printf("Received unknown APDU type (%d).\n", 
2161                            apdu->which);
2162                     exit(1);
2163                 }
2164             }
2165             while (conn && cs_more(conn));
2166 #if HAVE_GETTIMEOFDAY
2167             gettimeofday (&tv_end, 0);
2168             if (1)
2169             {
2170                 printf ("Elapsed: %.6f\n", (double) tv_end.tv_usec /
2171                                                 1e6 + tv_end.tv_sec -
2172                    ((double) tv_start.tv_usec / 1e6 + tv_start.tv_sec));
2173             }
2174 #endif
2175         }
2176     }
2177     return 0;
2178 }
2179
2180 int main(int argc, char **argv)
2181 {
2182     char *prog = *argv;
2183     char *arg;
2184     int ret;
2185     int opened = 0;
2186
2187     while ((ret = options("c:a:m:v:p:", argv, argc, &arg)) != -2)
2188     {
2189         switch (ret)
2190         {
2191         case 0:
2192             if (!opened)
2193             {
2194                 initialize ();
2195                 if (cmd_open (arg) == 2) {
2196 #if HAVE_READLINE_HISTORY_H
2197                   char* tmp=(char*)malloc(strlen(arg)+6);
2198                   *tmp=0;
2199                   strcat(tmp,"open ");
2200                   strcat(tmp,arg);
2201                   add_history(tmp);
2202                   free(tmp);
2203 #endif
2204                   opened = 1;
2205                 };
2206             }
2207             break;
2208         case 'm':
2209             if (!(marcdump = fopen (arg, "a")))
2210             {
2211                 perror (arg);
2212                 exit (1);
2213             }
2214             break;
2215         case 'c':
2216             strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
2217             ccl_fields[sizeof(ccl_fields)-1] = '\0';
2218             break;
2219         case 'a':
2220             if (!strcmp(arg, "-"))
2221                 apdu_file=stderr;
2222             else
2223                 apdu_file=fopen(arg, "a");
2224             break;
2225         case 'p':
2226             yazProxy=strdup(arg);
2227             break;
2228         case 'v':
2229             yaz_log_init (yaz_log_mask_str(arg), "", NULL);
2230             break;
2231         default:
2232             fprintf (stderr, "Usage: %s [-m <marclog>] [ -a <apdulog>] "
2233                              "[-c cclfields] [-p <proxy-addr>] [<server-addr>]\n",
2234                      prog);
2235             exit (1);
2236         }
2237     }
2238     if (!opened)
2239         initialize ();
2240     return client (opened);
2241 }