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