Added support for adding tab completions to any command with out a build in
[yaz-moved-to-github.git] / client / client.c
1 /*
2  * Copyright (c) 1995-2002, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: client.c,v 1.159 2002-06-17 14:57:34 ja7 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 #include <yaz/charneg.h>
24
25 #include <yaz/pquery.h>
26 #include <yaz/sortspec.h>
27
28 #include <yaz/ill.h>
29
30 #include <yaz/yaz-ccl.h>
31
32 #if HAVE_READLINE_READLINE_H
33 #include <readline/readline.h>
34 #endif
35 #if HAVE_READLINE_HISTORY_H
36 #include <readline/history.h>
37 #endif
38
39 #include <sys/stat.h>
40
41
42 #include "admin.h"
43 #include "tabcomplete.h"
44
45 #define C_PROMPT "Z> "
46
47 static ODR out, in, print;              /* encoding and decoding streams */
48 static FILE *apdu_file = 0;
49 static COMSTACK conn = 0;               /* our z-association */
50 static Z_IdAuthentication *auth = 0;    /* our current auth definition */
51 char *databaseNames[128];
52 int num_databaseNames = 0;
53 static Z_External *record_last = 0;
54 static int setnumber = -1;               /* current result set number */
55 static int smallSetUpperBound = 0;
56 static int largeSetLowerBound = 1;
57 static int mediumSetPresentNumber = 0;
58 static Z_ElementSetNames *elementSetNames = 0; 
59 static int setno = 1;                   /* current set offset */
60 static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
61 static enum oid_value recordsyntax = VAL_USMARC;
62 static enum oid_value schema = VAL_NONE;
63 static int sent_close = 0;
64 static NMEM session_mem = NULL;      /* memory handle for init-response */
65 static Z_InitResponse *session = 0;     /* session parameters */
66 static char last_scan_line[512] = "0";
67 static char last_scan_query[512] = "0";
68 static char ccl_fields[512] = "default.bib";
69 static char* esPackageName = 0;
70 static char* yazProxy = 0;
71 static int kilobytes = 1024;
72 static char* yazCharset = 0;
73 static char* yazLang = 0;
74
75
76 static char last_cmd[32] = "?";
77 static FILE *marcdump = 0;
78 static char *refid = NULL;
79
80 typedef enum {
81     QueryType_Prefix,
82     QueryType_CCL,
83     QueryType_CCL2RPN
84 } QueryType;
85
86 static QueryType queryType = QueryType_Prefix;
87
88 static CCL_bibset bibset;               /* CCL bibset handle */
89
90 #if HAVE_READLINE_COMPLETION_OVER
91
92 #else
93 /* readline doesn't have this var. Define it ourselves. */
94 int rl_attempted_completion_over = 0;
95 #endif
96
97 /* set this one to 1, to avoid decode of unknown MARCs  */
98 #define AVOID_MARC_DECODE 1
99
100 /* nice helper macro as extensive tabbing gives spaces at the en of the args lines */
101 #define REMOVE_TAILING_BLANKS(a) {\
102   char* args_end=(a)+strlen(a)-1; \
103   while(isspace(*args_end)) {*args_end=0;--args_end;}; \
104   }
105
106
107 void process_cmd_line(char* line);
108 char ** readline_completer(char *text, int start, int end);
109 char *command_generator(const char *text, int state);
110 char** curret_global_list=NULL;
111 int cmd_register_tab(char* arg);
112
113 ODR getODROutputStream()
114 {
115     return out;
116 }
117
118 void send_apdu(Z_APDU *a)
119 {
120     char *buf;
121     int len;
122
123     if (apdu_file)
124     {
125         z_APDU(print, &a, 0, 0);
126         odr_reset(print);
127     }
128     if (!z_APDU(out, &a, 0, 0))
129     {
130         odr_perror(out, "Encoding APDU");
131         exit(1);
132     }
133     buf = odr_getbuf(out, &len, 0);
134     /* printf ("sending APDU of size %d\n", len); */
135     if (cs_put(conn, buf, len) < 0)
136     {
137         fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
138         exit(1);
139     }
140     odr_reset(out); /* release the APDU structure  */
141 }
142
143 static void print_stringn(const unsigned char *buf, size_t len)
144 {
145    size_t i;
146    for (i = 0; i<len; i++)
147        if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
148            printf ("%c", buf[i]);
149        else
150            printf ("\\X%02X", buf[i]);
151 }
152
153 static void print_refid (Z_ReferenceId *id)
154 {
155     if (id)
156     {
157         printf ("Reference Id: ");
158         print_stringn (id->buf, id->len);
159         printf ("\n");
160     }
161 }
162
163 static Z_ReferenceId *set_refid (ODR out)
164 {
165     Z_ReferenceId *id;
166     if (!refid)
167         return 0;
168     id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
169     id->size = id->len = strlen(refid);
170     id->buf = (unsigned char *) odr_malloc (out, id->len);
171     memcpy (id->buf, refid, id->len);
172     return id;
173 }   
174
175 /* INIT SERVICE ------------------------------- */
176
177 static void send_initRequest(const char* type_and_host)
178 {
179     Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
180     Z_InitRequest *req = apdu->u.initRequest;
181
182     ODR_MASK_SET(req->options, Z_Options_search);
183     ODR_MASK_SET(req->options, Z_Options_present);
184     ODR_MASK_SET(req->options, Z_Options_namedResultSets);
185     ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl);
186     ODR_MASK_SET(req->options, Z_Options_scan);
187     ODR_MASK_SET(req->options, Z_Options_sort);
188     ODR_MASK_SET(req->options, Z_Options_extendedServices);
189     ODR_MASK_SET(req->options, Z_Options_delSet);
190
191     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
192     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
193     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
194
195     *req->maximumRecordSize = 1024*kilobytes;
196     *req->preferredMessageSize = 1024*kilobytes;
197
198     req->idAuthentication = auth;
199
200     req->referenceId = set_refid (out);
201
202     if (yazProxy) 
203         yaz_oi_set_string_oidval(&req->otherInfo, out, VAL_PROXY,
204         1, type_and_host);
205     
206     if (yazCharset || yazLang) {
207         Z_OtherInformation **p;
208         Z_OtherInformationUnit *p0;
209         
210         yaz_oi_APDU(apdu, &p);
211         
212         if (p0=yaz_oi_update(p, out, NULL, 0, 0)) {
213                 ODR_MASK_SET(req->options, Z_Options_negotiationModel);
214                 
215                 p0->which = Z_OtherInfo_externallyDefinedInfo;
216                 p0->information.externallyDefinedInfo =
217                         yaz_set_proposal_charneg(out,
218                                 (const char**)&yazCharset, (yazCharset)?1:0,
219                                 (const char**)&yazLang, (yazLang)?1:0, 1);
220         }
221     }
222     
223     send_apdu(apdu);
224     printf("Sent initrequest.\n");
225 }
226
227 static int process_initResponse(Z_InitResponse *res)
228 {
229     /* save session parameters for later use */
230     session_mem = odr_extract_mem(in);
231     session = res;
232
233     if (!*res->result)
234         printf("Connection rejected by target.\n");
235     else
236         printf("Connection accepted by target.\n");
237     if (res->implementationId)
238         printf("ID     : %s\n", res->implementationId);
239     if (res->implementationName)
240         printf("Name   : %s\n", res->implementationName);
241     if (res->implementationVersion)
242         printf("Version: %s\n", res->implementationVersion);
243     if (res->userInformationField)
244     {
245         printf("UserInformationfield:\n");
246         if (!z_External(print, (Z_External**)&res-> userInformationField,
247             0, 0))
248         {
249             odr_perror(print, "Printing userinfo\n");
250             odr_reset(print);
251         }
252         if (res->userInformationField->which == Z_External_octet)
253         {
254             printf("Guessing visiblestring:\n");
255             printf("'%s'\n", res->userInformationField->u. octet_aligned->buf);
256         }
257         odr_reset (print);
258     }
259     printf ("Options:");
260     if (ODR_MASK_GET(res->options, Z_Options_search))
261         printf (" search");
262     if (ODR_MASK_GET(res->options, Z_Options_present))
263         printf (" present");
264     if (ODR_MASK_GET(res->options, Z_Options_delSet))
265         printf (" delSet");
266     if (ODR_MASK_GET(res->options, Z_Options_resourceReport))
267         printf (" resourceReport");
268     if (ODR_MASK_GET(res->options, Z_Options_resourceCtrl))
269         printf (" resourceCtrl");
270     if (ODR_MASK_GET(res->options, Z_Options_accessCtrl))
271         printf (" accessCtrl");
272     if (ODR_MASK_GET(res->options, Z_Options_scan))
273         printf (" scan");
274     if (ODR_MASK_GET(res->options, Z_Options_sort))
275         printf (" sort");
276     if (ODR_MASK_GET(res->options, Z_Options_extendedServices))
277         printf (" extendedServices");
278     if (ODR_MASK_GET(res->options, Z_Options_level_1Segmentation))
279         printf (" level1Segmentation");
280     if (ODR_MASK_GET(res->options, Z_Options_level_2Segmentation))
281         printf (" level2Segmentation");
282     if (ODR_MASK_GET(res->options, Z_Options_concurrentOperations))
283         printf (" concurrentOperations");
284     if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
285     {
286         printf (" namedResultSets");
287         setnumber = 0;
288     }
289     if (ODR_MASK_GET(res->options, Z_Options_encapsulation))
290         printf (" encapsulation");
291     if (ODR_MASK_GET(res->options, Z_Options_resultCount))
292         printf (" resultCount");
293     if (ODR_MASK_GET(res->options, Z_Options_negotiationModel))
294         printf (" negotiationModel");
295     if (ODR_MASK_GET(res->options, Z_Options_duplicateDetection))
296         printf (" duplicateDetection");
297     if (ODR_MASK_GET(res->options, Z_Options_queryType104))
298         printf (" queryType104");
299     printf ("\n");
300     
301     if (ODR_MASK_GET(res->options, Z_Options_negotiationModel)) {
302     
303         Z_CharSetandLanguageNegotiation *p =
304                 yaz_get_charneg_record(res->otherInfo);
305         
306         if (p) {
307         
308                 char *charset=NULL, *lang=NULL;
309                 int selected;
310                 
311                 yaz_get_response_charneg(session_mem, p, &charset, &lang, &selected);
312                 
313                 printf("Accepted character set : `%s'\n", charset);
314                 printf("Accepted code language : `%s'\n", lang);
315                 printf("Accepted records in ...: %d\n", selected );
316         }
317     }
318     fflush (stdout);
319     return 0;
320 }
321
322 static int cmd_base(char *arg)
323 {
324     int i;
325     char *cp;
326
327     if (!*arg)
328     {
329         printf("Usage: base <database> <database> ...\n");
330         return 0;
331     }
332     for (i = 0; i<num_databaseNames; i++)
333         xfree (databaseNames[i]);
334     num_databaseNames = 0;
335     while (1)
336     {
337         if (!(cp = strchr(arg, ' ')))
338             cp = arg + strlen(arg);
339         if (cp - arg < 1)
340             break;
341         databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
342         memcpy (databaseNames[num_databaseNames], arg, cp - arg);
343         databaseNames[num_databaseNames++][cp - arg] = '\0';
344         if (!*cp)
345             break;
346         arg = cp+1;
347     }
348     return 1;
349 }
350
351 int cmd_open(char *arg)
352 {
353     void *add;
354     char type_and_host[101], base[101];
355     CS_TYPE t;
356     
357     if (conn)
358     {
359         printf("Already connected.\n");
360         
361         cs_close (conn);
362         conn = NULL;
363         if (session_mem)
364         {
365             nmem_destroy (session_mem);
366             session_mem = NULL;
367         }
368     }
369         if (strncmp (arg, "unix:", 5) == 0)
370         {
371         base[0] = '\0';
372         conn = cs_create_host(arg, 1, &add);
373         }
374         else
375         {
376                 t = tcpip_type;
377                 base[0] = '\0';
378                 if (sscanf (arg, "%100[^/]/%100s", type_and_host, base) < 1)
379                         return 0;
380                 
381                 if(yazProxy) 
382                         conn = cs_create_host(yazProxy, 1, &add);
383                 else 
384                         conn = cs_create_host(type_and_host, 1, &add);
385                 
386     }
387     if (!conn)
388     {
389         printf ("Couldn't create comstack\n");
390         return 0;
391     }
392     printf("Connecting...");
393     fflush(stdout);
394     if (cs_connect(conn, add) < 0)
395     {
396         printf ("error = %s\n", cs_strerror(conn));
397         if (conn->cerrno == CSYSERR)
398             perror("system");
399         cs_close(conn);
400         conn = 0;
401         return 0;
402     }
403     printf("Ok.\n");
404     
405     send_initRequest(type_and_host);
406     if (*base)
407         cmd_base (base);
408     return 2;
409 }
410
411 int cmd_authentication(char *arg)
412 {
413     static Z_IdAuthentication au;
414     static char user[40], group[40], pass[40];
415     static Z_IdPass idPass;
416     int r;
417
418     if (!*arg)
419     {
420         printf("Auth field set to null\n");
421         auth = 0;
422         return 1;
423     }
424     r = sscanf (arg, "%39s %39s %39s", user, group, pass);
425     if (r == 0)
426     {
427         printf("Auth field set to null\n");
428         auth = 0;
429     }
430     if (r == 1)
431     {
432         auth = &au;
433         au.which = Z_IdAuthentication_open;
434         au.u.open = user;
435     }
436     if (r == 2)
437     {
438         auth = &au;
439         au.which = Z_IdAuthentication_idPass;
440         au.u.idPass = &idPass;
441         idPass.groupId = NULL;
442         idPass.userId = user;
443         idPass.password = group;
444     }
445     if (r == 3)
446     {
447         auth = &au;
448         au.which = Z_IdAuthentication_idPass;
449         au.u.idPass = &idPass;
450         idPass.groupId = group;
451         idPass.userId = user;
452         idPass.password = pass;
453     }
454     return 1;
455 }
456
457 /* SEARCH SERVICE ------------------------------ */
458 static void display_record(Z_External *r);
459
460 static void display_variant(Z_Variant *v, int level)
461 {
462     int i;
463
464     for (i = 0; i < v->num_triples; i++)
465     {
466         printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass,
467             *v->triples[i]->type);
468         if (v->triples[i]->which == Z_Triple_internationalString)
469             printf(",value=%s\n", v->triples[i]->value.internationalString);
470         else
471             printf("\n");
472     }
473 }
474
475 static void display_grs1(Z_GenericRecord *r, int level)
476 {
477     int i;
478
479     if (!r)
480     {
481         return;
482     }
483     for (i = 0; i < r->num_elements; i++)
484     {
485         Z_TaggedElement *t;
486
487         printf("%*s", level * 4, "");
488         t = r->elements[i];
489         printf("(");
490         if (t->tagType)
491             printf("%d,", *t->tagType);
492         else
493             printf("?,");
494         if (t->tagValue->which == Z_StringOrNumeric_numeric)
495             printf("%d) ", *t->tagValue->u.numeric);
496         else
497             printf("%s) ", t->tagValue->u.string);
498         if (t->content->which == Z_ElementData_subtree)
499         {
500             if (!t->content->u.subtree)
501                 printf (" (no subtree)\n");
502             else
503             {
504                 printf("\n");
505                 display_grs1(t->content->u.subtree, level+1);
506             }
507         }
508         else if (t->content->which == Z_ElementData_string)
509             printf("%s\n", t->content->u.string);
510         else if (t->content->which == Z_ElementData_numeric)
511             printf("%d\n", *t->content->u.numeric);
512         else if (t->content->which == Z_ElementData_oid)
513         {
514             int *ip = t->content->u.oid;
515             oident *oent;
516             
517             if ((oent = oid_getentbyoid(t->content->u.oid)))
518                 printf("OID: %s\n", oent->desc);
519             else
520             {
521                 printf("{");
522                 while (ip && *ip >= 0)
523                     printf(" %d", *(ip++));
524                 printf(" }\n");
525             }
526         }
527         else if (t->content->which == Z_ElementData_noDataRequested)
528             printf("[No data requested]\n");
529         else if (t->content->which == Z_ElementData_elementEmpty)
530             printf("[Element empty]\n");
531         else if (t->content->which == Z_ElementData_elementNotThere)
532             printf("[Element not there]\n");
533         else if (t->content->which == Z_ElementData_date)
534             printf("Date: %s\n", t->content->u.date);
535         else if (t->content->which == Z_ElementData_ext)
536         {
537             printf ("External\n");
538             display_record (t->content->u.ext);
539         } 
540         else
541             printf("? type = %d\n",t->content->which);
542         if (t->appliedVariant)
543             display_variant(t->appliedVariant, level+1);
544         if (t->metaData && t->metaData->supportedVariants)
545         {
546             int c;
547
548             printf("%*s---- variant list\n", (level+1)*4, "");
549             for (c = 0; c < t->metaData->num_supportedVariants; c++)
550             {
551                 printf("%*svariant #%d\n", (level+1)*4, "", c);
552                 display_variant(t->metaData->supportedVariants[c], level + 2);
553             }
554         }
555     }
556 }
557
558
559 static void print_record(const unsigned char *buf, size_t len)
560 {
561     size_t i = len;
562     print_stringn (buf, len);
563     /* add newline if not already added ... */
564     if (i <= 0 || buf[i-1] != '\n')
565         printf ("\n");
566 }
567
568 static void display_record(Z_External *r)
569 {
570     oident *ent = oid_getentbyoid(r->direct_reference);
571
572     record_last = r;
573     /*
574      * Tell the user what we got.
575      */
576     if (r->direct_reference)
577     {
578         printf("Record type: ");
579         if (ent)
580             printf("%s\n", ent->desc);
581         else if (!odr_oid(print, &r->direct_reference, 0, 0))
582         {
583             odr_perror(print, "print oid");
584             odr_reset(print);
585         }
586     }
587     /* Check if this is a known, ASN.1 type tucked away in an octet string */
588     if (ent && r->which == Z_External_octet)
589     {
590         Z_ext_typeent *type = z_ext_getentbyref(ent->value);
591         void *rr;
592
593         if (type)
594         {
595             /*
596              * Call the given decoder to process the record.
597              */
598             odr_setbuf(in, (char*)r->u.octet_aligned->buf,
599                 r->u.octet_aligned->len, 0);
600             if (!(*type->fun)(in, (char **)&rr, 0, 0))
601             {
602                 odr_perror(in, "Decoding constructed record.");
603                 fprintf(stderr, "[Near %d]\n", odr_offset(in));
604                 fprintf(stderr, "Packet dump:\n---------\n");
605                 odr_dumpBER(stderr, (char*)r->u.octet_aligned->buf,
606                     r->u.octet_aligned->len);
607                 fprintf(stderr, "---------\n");
608                 exit(1);
609             }
610             /*
611              * Note: we throw away the original, BER-encoded record here.
612              * Do something else with it if you want to keep it.
613              */
614             r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
615             r->which = type->what;
616         }
617     }
618     if (ent && ent->oclass != CLASS_RECSYN)
619         return;
620     if (ent && ent->value == VAL_SOIF)
621         print_record((const unsigned char *) r->u.octet_aligned->buf,
622                      r->u.octet_aligned->len);
623     else if (r->which == Z_External_octet && r->u.octet_aligned->len)
624     {
625         const char *octet_buf = (char*)r->u.octet_aligned->buf;
626         if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML ||
627             ent->value == VAL_HTML)
628         {
629             print_record((const unsigned char *) octet_buf,
630                          r->u.octet_aligned->len);
631         }
632         else if (ent->value == VAL_POSTSCRIPT)
633         {
634             int size = r->u.octet_aligned->len;
635             if (size > 100)
636                 size = 100;
637             print_record((const unsigned char *) octet_buf, size);
638         }
639         else
640         {
641             if ( 
642 #if AVOID_MARC_DECODE
643                 /* primitive check for a marc OID 5.1-29 except 16 */
644                 ent->oidsuffix[0] == 5 && ent->oidsuffix[1] < 30 &&
645                 ent->oidsuffix[1] != 16
646 #else
647                 1
648 #endif
649                 )
650             {
651                 if (marc_display_exl (octet_buf, NULL, 0 /* debug */,
652                                       r->u.octet_aligned->len) <= 0)
653                 {
654                     printf ("bad MARC. Dumping as it is:\n");
655                     print_record((const unsigned char*) octet_buf,
656                                  r->u.octet_aligned->len);
657                 }
658             }
659             else
660             {
661                 print_record((const unsigned char*) octet_buf,
662                              r->u.octet_aligned->len);
663             }
664         }
665         if (marcdump)
666             fwrite (octet_buf, 1, r->u.octet_aligned->len, marcdump);
667     }
668     else if (ent && ent->value == VAL_SUTRS)
669     {
670         if (r->which != Z_External_sutrs)
671         {
672             printf("Expecting single SUTRS type for SUTRS.\n");
673             return;
674         }
675         print_record(r->u.sutrs->buf, r->u.sutrs->len);
676     }
677     else if (ent && ent->value == VAL_GRS1)
678     {
679         if (r->which != Z_External_grs1)
680         {
681             printf("Expecting single GRS type for GRS.\n");
682             return;
683         }
684         display_grs1(r->u.grs1, 0);
685     }
686     else 
687     {
688         printf("Unknown record representation.\n");
689         if (!z_External(print, &r, 0, 0))
690         {
691             odr_perror(print, "Printing external");
692             odr_reset(print);
693         }
694     }
695 }
696
697 static void display_diagrecs(Z_DiagRec **pp, int num)
698 {
699     int i;
700     oident *ent;
701     Z_DefaultDiagFormat *r;
702
703     printf("Diagnostic message(s) from database:\n");
704     for (i = 0; i<num; i++)
705     {
706         Z_DiagRec *p = pp[i];
707         if (p->which != Z_DiagRec_defaultFormat)
708         {
709             printf("Diagnostic record not in default format.\n");
710             return;
711         }
712         else
713             r = p->u.defaultFormat;
714         if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
715             ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
716             printf("Missing or unknown diagset\n");
717         printf("    [%d] %s", *r->condition, diagbib1_str(*r->condition));
718         switch (r->which)
719         {
720         case Z_DefaultDiagFormat_v2Addinfo:
721             printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
722             break;
723         case Z_DefaultDiagFormat_v3Addinfo:
724             printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
725             break;
726         }
727     }
728 }
729
730
731 static void display_nameplusrecord(Z_NamePlusRecord *p)
732 {
733     if (p->databaseName)
734         printf("[%s]", p->databaseName);
735     if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
736         display_diagrecs(&p->u.surrogateDiagnostic, 1);
737     else if (p->which == Z_NamePlusRecord_databaseRecord)
738         display_record(p->u.databaseRecord);
739 }
740
741 static void display_records(Z_Records *p)
742 {
743     int i;
744
745     if (p->which == Z_Records_NSD)
746     {
747         Z_DiagRec dr, *dr_p = &dr;
748         dr.which = Z_DiagRec_defaultFormat;
749         dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
750         display_diagrecs (&dr_p, 1);
751     }
752     else if (p->which == Z_Records_multipleNSD)
753         display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs,
754                           p->u.multipleNonSurDiagnostics->num_diagRecs);
755     else 
756     {
757         printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
758         for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
759             display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
760     }
761 }
762
763 static int send_deleteResultSetRequest(char *arg)
764 {
765     char names[8][32];
766     int i;
767
768     Z_APDU *apdu = zget_APDU(out, Z_APDU_deleteResultSetRequest);
769     Z_DeleteResultSetRequest *req = apdu->u.deleteResultSetRequest;
770
771     req->referenceId = set_refid (out);
772
773     req->num_resultSetList =
774         sscanf (arg, "%30s %30s %30s %30s %30s %30s %30s %30s",
775                 names[0], names[1], names[2], names[3],
776                 names[4], names[5], names[6], names[7]);
777
778     req->deleteFunction = (int *)
779         odr_malloc (out, sizeof(*req->deleteFunction));
780     if (req->num_resultSetList > 0)
781     {
782         *req->deleteFunction = Z_DeleteRequest_list;
783         req->resultSetList = (char **)
784             odr_malloc (out, sizeof(*req->resultSetList)*
785                         req->num_resultSetList);
786         for (i = 0; i<req->num_resultSetList; i++)
787             req->resultSetList[i] = names[i];
788     }
789     else
790     {
791         *req->deleteFunction = Z_DeleteRequest_all;
792         req->resultSetList = 0;
793     }
794     
795     send_apdu(apdu);
796     printf("Sent deleteResultSetRequest.\n");
797     return 2;
798 }
799
800 static int send_searchRequest(char *arg)
801 {
802     Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
803     Z_SearchRequest *req = apdu->u.searchRequest;
804     Z_Query query;
805     int oid[OID_SIZE];
806     struct ccl_rpn_node *rpn = NULL;
807     int error, pos;
808     char setstring[100];
809     Z_RPNQuery *RPNquery;
810     Odr_oct ccl_query;
811
812     if (queryType == QueryType_CCL2RPN)
813     {
814         rpn = ccl_find_str(bibset, arg, &error, &pos);
815         if (error)
816         {
817             printf("CCL ERROR: %s\n", ccl_err_msg(error));
818             return 0;
819         }
820     }
821     req->referenceId = set_refid (out);
822     if (!strcmp(arg, "@big")) /* strictly for troublemaking */
823     {
824         static unsigned char big[2100];
825         static Odr_oct bigo;
826
827         /* send a very big referenceid to test transport stack etc. */
828         memset(big, 'A', 2100);
829         bigo.len = bigo.size = 2100;
830         bigo.buf = big;
831         req->referenceId = &bigo;
832     }
833     
834     if (setnumber >= 0)
835     {
836         sprintf(setstring, "%d", ++setnumber);
837         req->resultSetName = setstring;
838     }
839     *req->smallSetUpperBound = smallSetUpperBound;
840     *req->largeSetLowerBound = largeSetLowerBound;
841     *req->mediumSetPresentNumber = mediumSetPresentNumber;
842     if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
843         mediumSetPresentNumber > 0))
844     {
845         oident prefsyn;
846
847         prefsyn.proto = protocol;
848         prefsyn.oclass = CLASS_RECSYN;
849         prefsyn.value = recordsyntax;
850         req->preferredRecordSyntax =
851             odr_oiddup(out, oid_ent_to_oid(&prefsyn, oid));
852         req->smallSetElementSetNames =
853             req->mediumSetElementSetNames = elementSetNames;
854     }
855     req->num_databaseNames = num_databaseNames;
856     req->databaseNames = databaseNames;
857
858     req->query = &query;
859
860     switch (queryType)
861     {
862     case QueryType_Prefix:
863         query.which = Z_Query_type_1;
864         RPNquery = p_query_rpn (out, protocol, arg);
865         if (!RPNquery)
866         {
867             printf("Prefix query error\n");
868             return 0;
869         }
870         query.u.type_1 = RPNquery;
871         break;
872     case QueryType_CCL:
873         query.which = Z_Query_type_2;
874         query.u.type_2 = &ccl_query;
875         ccl_query.buf = (unsigned char*) arg;
876         ccl_query.len = strlen(arg);
877         break;
878     case QueryType_CCL2RPN:
879         query.which = Z_Query_type_1;
880         RPNquery = ccl_rpn_query(out, rpn);
881         if (!RPNquery)
882         {
883             printf ("Couldn't convert from CCL to RPN\n");
884             return 0;
885         }
886         query.u.type_1 = RPNquery;
887         ccl_rpn_delete (rpn);
888         break;
889     default:
890         printf ("Unsupported query type\n");
891         return 0;
892     }
893     send_apdu(apdu);
894     setno = 1;
895     printf("Sent searchRequest.\n");
896     return 2;
897 }
898
899 /* display Query Expression as part of searchResult-1 */
900 static void display_queryExpression (Z_QueryExpression *qe)
901 {
902     if (!qe)
903         return;
904     if (qe->which == Z_QueryExpression_term)
905     {
906         if (qe->u.term->queryTerm)
907         {
908             Z_Term *term = qe->u.term->queryTerm;
909             if (term->which == Z_Term_general)
910                 printf (" %.*s", term->u.general->len, term->u.general->buf);
911         }
912     }
913
914 }
915
916 /* see if we can find USR:SearchResult-1 */
917 static void display_searchResult (Z_OtherInformation *o)
918 {
919     int i;
920     if (!o)
921         return ;
922     for (i = 0; i < o->num_elements; i++)
923     {
924         if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo)
925         {
926             Z_External *ext = o->list[i]->information.externallyDefinedInfo;
927             
928             if (ext->which == Z_External_searchResult1)
929             {
930                 int j;
931                 Z_SearchInfoReport *sr = ext->u.searchResult1;
932                 printf ("SearchResult-1:");
933                 for (j = 0; j < sr->num; j++)
934                 {
935                     if (!sr->elements[j]->subqueryExpression)
936                         printf (" %d", j);
937                     display_queryExpression (
938                         sr->elements[j]->subqueryExpression);
939                     display_queryExpression (
940                         sr->elements[j]->subqueryInterpretation);
941                     display_queryExpression (
942                         sr->elements[j]->subqueryRecommendation);
943                     if (sr->elements[j]->subqueryCount)
944                         printf ("(%d)", *sr->elements[j]->subqueryCount);
945                 }
946                 printf ("\n");
947             }
948         }
949     }
950 }
951
952 static int process_searchResponse(Z_SearchResponse *res)
953 {
954     printf ("Received SearchResponse.\n");
955     print_refid (res->referenceId);
956     if (*res->searchStatus)
957         printf("Search was a success.\n");
958     else
959         printf("Search was a bloomin' failure.\n");
960     printf("Number of hits: %d", *res->resultCount);
961     if (setnumber >= 0)
962         printf (", setno %d", setnumber);
963     printf ("\n");
964     display_searchResult (res->additionalSearchInfo);
965     printf("records returned: %d\n",
966            *res->numberOfRecordsReturned);
967     setno += *res->numberOfRecordsReturned;
968     if (res->records)
969         display_records(res->records);
970     return 0;
971 }
972
973 static void print_level(int iLevel)
974 {
975     int i;
976     for (i = 0; i < iLevel * 4; i++)
977         printf(" ");
978 }
979
980 static void print_int(int iLevel, const char *pTag, int *pInt)
981 {
982     if (pInt != NULL)
983     {
984         print_level(iLevel);
985         printf("%s: %d\n", pTag, *pInt);
986     }
987 }
988
989 static void print_string(int iLevel, const char *pTag, const char *pString)
990 {
991     if (pString != NULL)
992     {
993         print_level(iLevel);
994         printf("%s: %s\n", pTag, pString);
995     }
996 }
997
998 static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
999 {
1000     if (pOid != NULL)
1001     {
1002         int *pInt = pOid;
1003
1004         print_level(iLevel);
1005         printf("%s:", pTag);
1006         for (; *pInt != -1; pInt++)
1007             printf(" %d", *pInt);
1008         printf("\n");
1009     }
1010 }
1011
1012 static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
1013 {
1014     if (referenceId != NULL)
1015     {
1016         int i;
1017
1018         print_level(iLevel);
1019         printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
1020         for (i = 0; i < referenceId->len; i++)
1021             printf("%c", referenceId->buf[i]);
1022         printf("\n");
1023     }
1024 }
1025
1026 static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
1027 {
1028     if (pStringNumeric != NULL)
1029     {
1030         switch (pStringNumeric->which)
1031         {
1032         case Z_StringOrNumeric_string:
1033             print_string(iLevel, pTag, pStringNumeric->u.string);
1034             break;
1035             
1036         case Z_StringOrNumeric_numeric:
1037             print_int(iLevel, pTag, pStringNumeric->u.numeric);
1038             break;
1039             
1040         default:
1041             print_level(iLevel);
1042             printf("%s: valid type for Z_StringOrNumeric\n", pTag);
1043             break;
1044         }
1045     }
1046 }
1047
1048 static void print_universe_report_duplicate(int iLevel, Z_UniverseReportDuplicate *pUniverseReportDuplicate)
1049 {
1050     if (pUniverseReportDuplicate != NULL)
1051     {
1052         print_level(iLevel);
1053         printf("Universe Report Duplicate: \n");
1054         iLevel++;
1055         print_string_or_numeric(iLevel, "Hit No",
1056                                 pUniverseReportDuplicate->hitno);
1057     }
1058 }
1059
1060 static void
1061 print_universe_report_hits(int iLevel,
1062                            Z_UniverseReportHits *pUniverseReportHits)
1063 {
1064     if (pUniverseReportHits != NULL)
1065     {
1066         print_level(iLevel);
1067         printf("Universe Report Hits: \n");
1068         iLevel++;
1069         print_string_or_numeric(iLevel, "Database",
1070                                 pUniverseReportHits->database);
1071         print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
1072     }
1073 }
1074
1075 static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
1076 {
1077     if (pUniverseReport != NULL)
1078     {
1079         print_level(iLevel);
1080         printf("Universe Report: \n");
1081         iLevel++;
1082         print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
1083         switch (pUniverseReport->which)
1084         {
1085         case Z_UniverseReport_databaseHits:
1086             print_universe_report_hits(iLevel, pUniverseReport->u.databaseHits);
1087             break;
1088             
1089         case Z_UniverseReport_duplicate:
1090             print_universe_report_duplicate(iLevel, pUniverseReport->u.duplicate);
1091             break;
1092             
1093         default:
1094             print_level(iLevel);
1095             printf("Type: %d\n", pUniverseReport->which);
1096             break;
1097         }
1098     }
1099 }
1100
1101 static void print_external(int iLevel, Z_External *pExternal)
1102 {
1103     if (pExternal != NULL)
1104     {
1105         print_level(iLevel);
1106         printf("External: \n");
1107         iLevel++;
1108         print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
1109         print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
1110         print_string(iLevel, "Descriptor", pExternal->descriptor);
1111         switch (pExternal->which)
1112         {
1113         case Z_External_universeReport:
1114             print_universe_report(iLevel, pExternal->u.universeReport);
1115             break;
1116             
1117         default:
1118             print_level(iLevel);
1119             printf("Type: %d\n", pExternal->which);
1120             break;
1121         }
1122     }
1123 }
1124
1125 static int process_resourceControlRequest (Z_ResourceControlRequest *req)
1126 {
1127     printf ("Received ResourceControlRequest.\n");
1128     print_referenceId(1, req->referenceId);
1129     print_int(1, "Suspended Flag", req->suspendedFlag);
1130     print_int(1, "Partial Results Available", req->partialResultsAvailable);
1131     print_int(1, "Response Required", req->responseRequired);
1132     print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
1133     print_external(1, req->resourceReport);
1134     return 0;
1135 }
1136
1137 void process_ESResponse(Z_ExtendedServicesResponse *res)
1138 {
1139     printf("Status: ");
1140     switch (*res->operationStatus)
1141     {
1142     case Z_ExtendedServicesResponse_done:
1143         printf ("done\n");
1144         break;
1145     case Z_ExtendedServicesResponse_accepted:
1146         printf ("accepted\n");
1147         break;
1148     case Z_ExtendedServicesResponse_failure:
1149         printf ("failure\n");
1150         display_diagrecs(res->diagnostics, res->num_diagnostics);
1151         break;
1152     default:
1153         printf ("unknown\n");
1154     }
1155     if ( (*res->operationStatus != Z_ExtendedServicesResponse_failure) &&
1156         (res->num_diagnostics != 0) ) {
1157         display_diagrecs(res->diagnostics, res->num_diagnostics);
1158     }
1159     print_refid (res->referenceId);
1160     if (res->taskPackage && 
1161         res->taskPackage->which == Z_External_extendedService)
1162     {
1163         Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
1164         Odr_oct *id = taskPackage->targetReference;
1165         Z_External *ext = taskPackage->taskSpecificParameters;
1166         
1167         if (id)
1168         {
1169             printf ("Target Reference: ");
1170             print_stringn (id->buf, id->len);
1171             printf ("\n");
1172         }
1173         if (ext->which == Z_External_update)
1174         {
1175             Z_IUUpdateTaskPackage *utp = ext->u.update->u.taskPackage;
1176             if (utp && utp->targetPart)
1177             {
1178                 Z_IUTargetPart *targetPart = utp->targetPart;
1179                 int i;
1180
1181                 for (i = 0; i<targetPart->num_taskPackageRecords;  i++)
1182                 {
1183
1184                     Z_IUTaskPackageRecordStructure *tpr =
1185                         targetPart->taskPackageRecords[i];
1186                     printf ("task package record %d\n", i+1);
1187                     if (tpr->which == Z_IUTaskPackageRecordStructure_record)
1188                     {
1189                         display_record (tpr->u.record);
1190                     }
1191                     else
1192                     {
1193                         printf ("other type\n");
1194                     }
1195                 }
1196             }
1197         }
1198     }
1199 }
1200
1201 const char *get_ill_element (void *clientData, const char *element)
1202 {
1203     return 0;
1204 }
1205
1206 static Z_External *create_external_itemRequest()
1207 {
1208     struct ill_get_ctl ctl;
1209     ILL_ItemRequest *req;
1210     Z_External *r = 0;
1211     int item_request_size = 0;
1212     char *item_request_buf = 0;
1213
1214     ctl.odr = out;
1215     ctl.clientData = 0;
1216     ctl.f = get_ill_element;
1217     
1218     req = ill_get_ItemRequest(&ctl, "ill", 0);
1219     if (!req)
1220         printf ("ill_get_ItemRequest failed\n");
1221         
1222     if (!ill_ItemRequest (out, &req, 0, 0))
1223     {
1224         if (apdu_file)
1225         {
1226             ill_ItemRequest(print, &req, 0, 0);
1227             odr_reset(print);
1228         }
1229         item_request_buf = odr_getbuf (out, &item_request_size, 0);
1230         if (item_request_buf)
1231             odr_setbuf (out, item_request_buf, item_request_size, 1);
1232         printf ("Couldn't encode ItemRequest, size %d\n", item_request_size);
1233         return 0;
1234     }
1235     else
1236     {
1237         oident oid;
1238         
1239         item_request_buf = odr_getbuf (out, &item_request_size, 0);
1240         oid.proto = PROTO_GENERAL;
1241         oid.oclass = CLASS_GENERAL;
1242         oid.value = VAL_ISO_ILL_1;
1243         
1244         r = (Z_External *) odr_malloc (out, sizeof(*r));
1245         r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
1246         r->indirect_reference = 0;
1247         r->descriptor = 0;
1248         r->which = Z_External_single;
1249         
1250         r->u.single_ASN1_type = (Odr_oct *)
1251             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
1252         r->u.single_ASN1_type->buf = (unsigned char *)
1253         odr_malloc (out, item_request_size);
1254         r->u.single_ASN1_type->len = item_request_size;
1255         r->u.single_ASN1_type->size = item_request_size;
1256         memcpy (r->u.single_ASN1_type->buf, item_request_buf,
1257                 item_request_size);
1258         printf ("len = %d\n", item_request_size);
1259     }
1260     return r;
1261 }
1262
1263 static Z_External *create_external_ILL_APDU(int which)
1264 {
1265     struct ill_get_ctl ctl;
1266     ILL_APDU *ill_apdu;
1267     Z_External *r = 0;
1268     int ill_request_size = 0;
1269     char *ill_request_buf = 0;
1270         
1271     ctl.odr = out;
1272     ctl.clientData = 0;
1273     ctl.f = get_ill_element;
1274
1275     ill_apdu = ill_get_APDU(&ctl, "ill", 0);
1276
1277     if (!ill_APDU (out, &ill_apdu, 0, 0))
1278     {
1279         if (apdu_file)
1280         {
1281             printf ("-------------------\n");
1282             ill_APDU(print, &ill_apdu, 0, 0);
1283             odr_reset(print);
1284             printf ("-------------------\n");
1285         }
1286         ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
1287         if (ill_request_buf)
1288             odr_setbuf (out, ill_request_buf, ill_request_size, 1);
1289         printf ("Couldn't encode ILL-Request, size %d\n", ill_request_size);
1290         return 0;
1291     }
1292     else
1293     {
1294         oident oid;
1295         ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
1296         
1297         oid.proto = PROTO_GENERAL;
1298         oid.oclass = CLASS_GENERAL;
1299         oid.value = VAL_ISO_ILL_1;
1300         
1301         r = (Z_External *) odr_malloc (out, sizeof(*r));
1302         r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
1303         r->indirect_reference = 0;
1304         r->descriptor = 0;
1305         r->which = Z_External_single;
1306         
1307         r->u.single_ASN1_type = (Odr_oct *)
1308             odr_malloc (out, sizeof(*r->u.single_ASN1_type));
1309         r->u.single_ASN1_type->buf = (unsigned char *)
1310         odr_malloc (out, ill_request_size);
1311         r->u.single_ASN1_type->len = ill_request_size;
1312         r->u.single_ASN1_type->size = ill_request_size;
1313         memcpy (r->u.single_ASN1_type->buf, ill_request_buf, ill_request_size);
1314         printf ("len = %d\n", ill_request_size);
1315     }
1316     return r;
1317 }
1318
1319
1320 static Z_External *create_ItemOrderExternal(const char *type, int itemno)
1321 {
1322     Z_External *r = (Z_External *) odr_malloc(out, sizeof(Z_External));
1323     oident ItemOrderRequest;
1324   
1325     ItemOrderRequest.proto = PROTO_Z3950;
1326     ItemOrderRequest.oclass = CLASS_EXTSERV;
1327     ItemOrderRequest.value = VAL_ITEMORDER;
1328  
1329     r->direct_reference = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest)); 
1330     r->indirect_reference = 0;
1331     r->descriptor = 0;
1332
1333     r->which = Z_External_itemOrder;
1334
1335     r->u.itemOrder = (Z_ItemOrder *) odr_malloc(out,sizeof(Z_ItemOrder));
1336     memset(r->u.itemOrder, 0, sizeof(Z_ItemOrder));
1337     r->u.itemOrder->which=Z_IOItemOrder_esRequest;
1338
1339     r->u.itemOrder->u.esRequest = (Z_IORequest *) 
1340         odr_malloc(out,sizeof(Z_IORequest));
1341     memset(r->u.itemOrder->u.esRequest, 0, sizeof(Z_IORequest));
1342
1343     r->u.itemOrder->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
1344         odr_malloc(out,sizeof(Z_IOOriginPartToKeep));
1345     memset(r->u.itemOrder->u.esRequest->toKeep, 0, sizeof(Z_IOOriginPartToKeep));
1346     r->u.itemOrder->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
1347         odr_malloc(out,sizeof(Z_IOOriginPartNotToKeep));
1348     memset(r->u.itemOrder->u.esRequest->notToKeep, 0, sizeof(Z_IOOriginPartNotToKeep));
1349
1350     r->u.itemOrder->u.esRequest->toKeep->supplDescription = NULL;
1351     r->u.itemOrder->u.esRequest->toKeep->contact = NULL;
1352     r->u.itemOrder->u.esRequest->toKeep->addlBilling = NULL;
1353
1354     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem =
1355         (Z_IOResultSetItem *) odr_malloc(out, sizeof(Z_IOResultSetItem));
1356     memset(r->u.itemOrder->u.esRequest->notToKeep->resultSetItem, 0, sizeof(Z_IOResultSetItem));
1357     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->resultSetId = "1";
1358
1359     r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item =
1360         (int *) odr_malloc(out, sizeof(int));
1361     *r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item = itemno;
1362
1363 #if YAZ_MODULE_ill
1364     if (!strcmp (type, "item") || !strcmp(type, "2"))
1365     {
1366         printf ("using item-request\n");
1367         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
1368             create_external_itemRequest();
1369     }
1370     else if (!strcmp(type, "ill") || !strcmp(type, "1"))
1371     {
1372         printf ("using ILL-request\n");
1373         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
1374             create_external_ILL_APDU(ILL_APDU_ILL_Request);
1375     }
1376     else if (!strcmp(type, "xml") || !strcmp(type, "3"))
1377     {
1378     const char *xml_buf =
1379         "<itemorder>\n"
1380         "  <type>request</type>\n"
1381         "  <libraryNo>000200</libraryNo>\n"
1382         "  <borrowerTicketNo> 1212 </borrowerTicketNo>\n"
1383         "</itemorder>";
1384         r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
1385             z_ext_record (out, VAL_TEXT_XML, xml_buf, strlen(xml_buf));
1386     }
1387     else
1388         r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
1389
1390 #else
1391     r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
1392 #endif
1393     return r;
1394 }
1395
1396 static int send_itemorder(const char *type, int itemno)
1397 {
1398     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
1399     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
1400     oident ItemOrderRequest;
1401
1402     ItemOrderRequest.proto = PROTO_Z3950;
1403     ItemOrderRequest.oclass = CLASS_EXTSERV;
1404     ItemOrderRequest.value = VAL_ITEMORDER;
1405     req->packageType = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest));
1406     req->packageName = esPackageName;
1407
1408     req->taskSpecificParameters = create_ItemOrderExternal(type, itemno);
1409
1410     send_apdu(apdu);
1411     return 0;
1412 }
1413
1414 static int cmd_update(char *arg)
1415 {
1416     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
1417     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
1418     Z_External *r;
1419     int oid[OID_SIZE];
1420     Z_IUOriginPartToKeep *toKeep;
1421     Z_IUSuppliedRecords *notToKeep;
1422     oident update_oid;
1423     printf ("Update request\n");
1424     fflush(stdout);
1425     
1426     if (!record_last)
1427         return 0;
1428     update_oid.proto = PROTO_Z3950;
1429     update_oid.oclass = CLASS_EXTSERV;
1430     update_oid.value = VAL_DBUPDATE;
1431     oid_ent_to_oid (&update_oid, oid);
1432     req->packageType = odr_oiddup(out,oid);
1433     req->packageName = esPackageName;
1434     
1435     req->referenceId = set_refid (out);
1436
1437     r = req->taskSpecificParameters = (Z_External *)
1438         odr_malloc (out, sizeof(*r));
1439     r->direct_reference = odr_oiddup(out,oid);
1440     r->indirect_reference = 0;
1441     r->descriptor = 0;
1442     r->which = Z_External_update;
1443     r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
1444     r->u.update->which = Z_IUUpdate_esRequest;
1445     r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
1446         odr_malloc(out, sizeof(*r->u.update->u.esRequest));
1447     toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
1448         odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
1449     toKeep->databaseName = databaseNames[0];
1450     toKeep->schema = 0;
1451     toKeep->elementSetName = 0;
1452     toKeep->actionQualifier = 0;
1453     toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
1454     *toKeep->action = Z_IUOriginPartToKeep_recordInsert;
1455
1456     notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
1457         odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
1458     notToKeep->num = 1;
1459     notToKeep->elements = (Z_IUSuppliedRecords_elem **)
1460         odr_malloc(out, sizeof(*notToKeep->elements));
1461     notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
1462         odr_malloc(out, sizeof(**notToKeep->elements));
1463     notToKeep->elements[0]->u.number = 0;
1464     notToKeep->elements[0]->supplementalId = 0;
1465     notToKeep->elements[0]->correlationInfo = 0;
1466     notToKeep->elements[0]->record = record_last;
1467     
1468     send_apdu(apdu);
1469
1470     return 2;
1471 }
1472
1473 static int cmd_itemorder(char *arg)
1474 {
1475     char type[12];
1476     int itemno;
1477     
1478     if (sscanf (arg, "%10s %d", type, &itemno) != 2)
1479         return 0;
1480
1481     printf("Item order request\n");
1482     fflush(stdout);
1483     send_itemorder(type, itemno);
1484     return 2;
1485 }
1486
1487 static int cmd_find(char *arg)
1488 {
1489     if (!*arg)
1490     {
1491         printf("Find what?\n");
1492         return 0;
1493     }
1494     if (!conn)
1495     {
1496         printf("Not connected yet\n");
1497         return 0;
1498     }
1499     if (!send_searchRequest(arg))
1500         return 0;
1501     return 2;
1502 }
1503
1504 static int cmd_delete(char *arg)
1505 {
1506     if (!conn)
1507     {
1508         printf("Not connected yet\n");
1509         return 0;
1510     }
1511     if (!send_deleteResultSetRequest(arg))
1512         return 0;
1513     return 2;
1514 }
1515
1516 static int cmd_ssub(char *arg)
1517 {
1518     if (!(smallSetUpperBound = atoi(arg)))
1519         return 0;
1520     return 1;
1521 }
1522
1523 static int cmd_lslb(char *arg)
1524 {
1525     if (!(largeSetLowerBound = atoi(arg)))
1526         return 0;
1527     return 1;
1528 }
1529
1530 static int cmd_mspn(char *arg)
1531 {
1532     if (!(mediumSetPresentNumber = atoi(arg)))
1533         return 0;
1534     return 1;
1535 }
1536
1537 static int cmd_status(char *arg)
1538 {
1539     printf("smallSetUpperBound: %d\n", smallSetUpperBound);
1540     printf("largeSetLowerBound: %d\n", largeSetLowerBound);
1541     printf("mediumSetPresentNumber: %d\n", mediumSetPresentNumber);
1542     return 1;
1543 }
1544
1545 static int cmd_setnames(char *arg)
1546 {
1547     if (*arg == '1')         /* enable ? */
1548         setnumber = 0;
1549     else if (*arg == '0')    /* disable ? */
1550         setnumber = -1;
1551     else if (setnumber < 0)  /* no args, toggle .. */
1552         setnumber = 0;
1553     else
1554         setnumber = -1;
1555    
1556     if (setnumber >= 0)
1557         printf("Set numbering enabled.\n");
1558     else
1559         printf("Set numbering disabled.\n");
1560     return 1;
1561 }
1562
1563 /* PRESENT SERVICE ----------------------------- */
1564
1565 static int send_presentRequest(char *arg)
1566 {
1567     Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
1568     Z_PresentRequest *req = apdu->u.presentRequest;
1569     Z_RecordComposition compo;
1570     oident prefsyn;
1571     int nos = 1;
1572     int oid[OID_SIZE];
1573     char *p;
1574     char setstring[100];
1575
1576     req->referenceId = set_refid (out);
1577     if ((p = strchr(arg, '+')))
1578     {
1579         nos = atoi(p + 1);
1580         *p = 0;
1581     }
1582     if (*arg)
1583         setno = atoi(arg);
1584     if (p && (p=strchr(p+1, '+')))
1585     {
1586         strcpy (setstring, p+1);
1587         req->resultSetId = setstring;
1588     }
1589     else if (setnumber >= 0)
1590     {
1591         sprintf(setstring, "%d", setnumber);
1592         req->resultSetId = setstring;
1593     }
1594     req->resultSetStartPoint = &setno;
1595     req->numberOfRecordsRequested = &nos;
1596     prefsyn.proto = protocol;
1597     prefsyn.oclass = CLASS_RECSYN;
1598     prefsyn.value = recordsyntax;
1599     req->preferredRecordSyntax =
1600         odr_oiddup (out, oid_ent_to_oid(&prefsyn, oid));
1601
1602     if (schema != VAL_NONE)
1603     {
1604         oident prefschema;
1605
1606         prefschema.proto = protocol;
1607         prefschema.oclass = CLASS_SCHEMA;
1608         prefschema.value = schema;
1609
1610         req->recordComposition = &compo;
1611         compo.which = Z_RecordComp_complex;
1612         compo.u.complex = (Z_CompSpec *)
1613             odr_malloc(out, sizeof(*compo.u.complex));
1614         compo.u.complex->selectAlternativeSyntax = (bool_t *) 
1615             odr_malloc(out, sizeof(bool_t));
1616         *compo.u.complex->selectAlternativeSyntax = 0;
1617
1618         compo.u.complex->generic = (Z_Specification *)
1619             odr_malloc(out, sizeof(*compo.u.complex->generic));
1620         compo.u.complex->generic->schema = (Odr_oid *)
1621             odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
1622         if (!compo.u.complex->generic->schema)
1623         {
1624             /* OID wasn't a schema! Try record syntax instead. */
1625             prefschema.oclass = CLASS_RECSYN;
1626             compo.u.complex->generic->schema = (Odr_oid *)
1627                 odr_oiddup(out, oid_ent_to_oid(&prefschema, oid));
1628         }
1629         if (!elementSetNames)
1630             compo.u.complex->generic->elementSpec = 0;
1631         else
1632         {
1633             compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
1634                 odr_malloc(out, sizeof(Z_ElementSpec));
1635             compo.u.complex->generic->elementSpec->which =
1636                 Z_ElementSpec_elementSetName;
1637             compo.u.complex->generic->elementSpec->u.elementSetName =
1638                 elementSetNames->u.generic;
1639         }
1640         compo.u.complex->num_dbSpecific = 0;
1641         compo.u.complex->dbSpecific = 0;
1642         compo.u.complex->num_recordSyntax = 0;
1643         compo.u.complex->recordSyntax = 0;
1644     }
1645     else if (elementSetNames)
1646     {
1647         req->recordComposition = &compo;
1648         compo.which = Z_RecordComp_simple;
1649         compo.u.simple = elementSetNames;
1650     }
1651     send_apdu(apdu);
1652     printf("Sent presentRequest (%d+%d).\n", setno, nos);
1653     return 2;
1654 }
1655     
1656 static void close_session (void)
1657 {
1658     cs_close (conn);
1659     conn = 0;
1660     if (session_mem)
1661     {
1662         nmem_destroy (session_mem);
1663         session_mem = NULL;
1664     }
1665     sent_close = 0;
1666 }
1667
1668 void process_close(Z_Close *req)
1669 {
1670     Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
1671     Z_Close *res = apdu->u.close;
1672
1673     static char *reasons[] =
1674     {
1675         "finished",
1676         "shutdown",
1677         "system problem",
1678         "cost limit reached",
1679         "resources",
1680         "security violation",
1681         "protocolError",
1682         "lack of activity",
1683         "peer abort",
1684         "unspecified"
1685     };
1686
1687     printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
1688         req->diagnosticInformation ? req->diagnosticInformation : "NULL");
1689     if (sent_close)
1690         close_session ();
1691     else
1692     {
1693         *res->closeReason = Z_Close_finished;
1694         send_apdu(apdu);
1695         printf("Sent response.\n");
1696         sent_close = 1;
1697     }
1698 }
1699
1700 static int cmd_show(char *arg)
1701 {
1702     if (!conn)
1703     {
1704         printf("Not connected yet\n");
1705         return 0;
1706     }
1707     if (!send_presentRequest(arg))
1708         return 0;
1709     return 2;
1710 }
1711
1712 int cmd_quit(char *arg)
1713 {
1714     printf("See you later, alligator.\n");
1715     xmalloc_trav ("");
1716     exit(0);
1717     return 0;
1718 }
1719
1720 int cmd_cancel(char *arg)
1721 {
1722     Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
1723     Z_TriggerResourceControlRequest *req =
1724         apdu->u.triggerResourceControlRequest;
1725     bool_t rfalse = 0;
1726     
1727     if (!conn)
1728     {
1729         printf("Session not initialized yet\n");
1730         return 0;
1731     }
1732     if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
1733     {
1734         printf("Target doesn't support cancel (trigger resource ctrl)\n");
1735         return 0;
1736     }
1737     *req->requestedAction = Z_TriggerResourceCtrl_cancel;
1738     req->resultSetWanted = &rfalse;
1739
1740     send_apdu(apdu);
1741     printf("Sent cancel request\n");
1742     return 2;
1743 }
1744
1745 int send_scanrequest(const char *query, int pp, int num, const char *term)
1746 {
1747     Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
1748     Z_ScanRequest *req = apdu->u.scanRequest;
1749     int use_rpn = 1;
1750     int oid[OID_SIZE];
1751     
1752     if (queryType == QueryType_CCL2RPN)
1753     {
1754         oident bib1;
1755         int error, pos;
1756         struct ccl_rpn_node *rpn;
1757
1758         rpn = ccl_find_str (bibset,  query, &error, &pos);
1759         if (error)
1760         {
1761             printf("CCL ERROR: %s\n", ccl_err_msg(error));
1762             return -1;
1763         }
1764         use_rpn = 0;
1765         bib1.proto = PROTO_Z3950;
1766         bib1.oclass = CLASS_ATTSET;
1767         bib1.value = VAL_BIB1;
1768         req->attributeSet = oid_ent_to_oid (&bib1, oid);
1769         if (!(req->termListAndStartPoint = ccl_scan_query (out, rpn)))
1770         {
1771             printf("Couldn't convert CCL to Scan term\n");
1772             return -1;
1773         }
1774         ccl_rpn_delete (rpn);
1775     }
1776     if (use_rpn && !(req->termListAndStartPoint =
1777                      p_query_scan(out, protocol, &req->attributeSet, query)))
1778     {
1779         printf("Prefix query error\n");
1780         return -1;
1781     }
1782     if (term && *term)
1783     {
1784         if (req->termListAndStartPoint->term &&
1785             req->termListAndStartPoint->term->which == Z_Term_general &&
1786             req->termListAndStartPoint->term->u.general)
1787         {
1788             req->termListAndStartPoint->term->u.general->buf =
1789                 (unsigned char *) odr_strdup(out, term);
1790             req->termListAndStartPoint->term->u.general->len =
1791                 req->termListAndStartPoint->term->u.general->size =
1792                 strlen(term);
1793         }
1794     }
1795     req->referenceId = set_refid (out);
1796     req->num_databaseNames = num_databaseNames;
1797     req->databaseNames = databaseNames;
1798     req->numberOfTermsRequested = &num;
1799     req->preferredPositionInResponse = &pp;
1800     send_apdu(apdu);
1801     return 2;
1802 }
1803
1804 int send_sortrequest(char *arg, int newset)
1805 {
1806     Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
1807     Z_SortRequest *req = apdu->u.sortRequest;
1808     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
1809         odr_malloc (out, sizeof(*sksl));
1810     char setstring[32];
1811
1812     if (setnumber >= 0)
1813         sprintf (setstring, "%d", setnumber);
1814     else
1815         sprintf (setstring, "default");
1816
1817     req->referenceId = set_refid (out);
1818
1819     req->num_inputResultSetNames = 1;
1820     req->inputResultSetNames = (Z_InternationalString **)
1821         odr_malloc (out, sizeof(*req->inputResultSetNames));
1822     req->inputResultSetNames[0] = odr_strdup (out, setstring);
1823
1824     if (newset && setnumber >= 0)
1825         sprintf (setstring, "%d", ++setnumber);
1826
1827     req->sortedResultSetName = odr_strdup (out, setstring);
1828
1829     req->sortSequence = yaz_sort_spec (out, arg);
1830     if (!req->sortSequence)
1831     {
1832         printf ("Missing sort specifications\n");
1833         return -1;
1834     }
1835     send_apdu(apdu);
1836     return 2;
1837 }
1838
1839 void display_term(Z_TermInfo *t)
1840 {
1841     if (t->term->which == Z_Term_general)
1842     {
1843         printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
1844         sprintf(last_scan_line, "%.*s", t->term->u.general->len,
1845             t->term->u.general->buf);
1846     }
1847     else
1848         printf("Term (not general)");
1849     if (t->globalOccurrences)
1850         printf (" (%d)\n", *t->globalOccurrences);
1851     else
1852         printf ("\n");
1853 }
1854
1855 void process_scanResponse(Z_ScanResponse *res)
1856 {
1857     int i;
1858     Z_Entry **entries = NULL;
1859     int num_entries = 0;
1860    
1861     printf("Received ScanResponse\n"); 
1862     print_refid (res->referenceId);
1863     printf("%d entries", *res->numberOfEntriesReturned);
1864     if (res->positionOfTerm)
1865         printf (", position=%d", *res->positionOfTerm); 
1866     printf ("\n");
1867     if (*res->scanStatus != Z_Scan_success)
1868         printf("Scan returned code %d\n", *res->scanStatus);
1869     if (!res->entries)
1870         return;
1871     if ((entries = res->entries->entries))
1872         num_entries = res->entries->num_entries;
1873     for (i = 0; i < num_entries; i++)
1874     {
1875         int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
1876         if (entries[i]->which == Z_Entry_termInfo)
1877         {
1878             printf("%c ", i + 1 == pos_term ? '*' : ' ');
1879             display_term(entries[i]->u.termInfo);
1880         }
1881         else
1882             display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
1883     }
1884     if (res->entries->nonsurrogateDiagnostics)
1885         display_diagrecs (res->entries->nonsurrogateDiagnostics,
1886                           res->entries->num_nonsurrogateDiagnostics);
1887 }
1888
1889 void process_sortResponse(Z_SortResponse *res)
1890 {
1891     printf("Received SortResponse: status=");
1892     switch (*res->sortStatus)
1893     {
1894     case Z_SortStatus_success:
1895         printf ("success"); break;
1896     case Z_SortStatus_partial_1:
1897         printf ("partial"); break;
1898     case Z_SortStatus_failure:
1899         printf ("failure"); break;
1900     default:
1901         printf ("unknown (%d)", *res->sortStatus);
1902     }
1903     printf ("\n");
1904     print_refid (res->referenceId);
1905     if (res->diagnostics)
1906         display_diagrecs(res->diagnostics,
1907                          res->num_diagnostics);
1908 }
1909
1910 void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
1911 {
1912     printf("Got deleteResultSetResponse status=%d\n",
1913            *res->deleteOperationStatus);
1914     if (res->deleteListStatuses)
1915     {
1916         int i;
1917         for (i = 0; i < res->deleteListStatuses->num; i++)
1918         {
1919             printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
1920                     *res->deleteListStatuses->elements[i]->status);
1921         }
1922     }
1923 }
1924
1925 int cmd_sort_generic(char *arg, int newset)
1926 {
1927     if (!conn)
1928     {
1929         printf("Session not initialized yet\n");
1930         return 0;
1931     }
1932     if (!ODR_MASK_GET(session->options, Z_Options_sort))
1933     {
1934         printf("Target doesn't support sort\n");
1935         return 0;
1936     }
1937     if (*arg)
1938     {
1939         if (send_sortrequest(arg, newset) < 0)
1940             return 0;
1941         return 2;
1942     }
1943     return 0;
1944 }
1945
1946 int cmd_sort(char *arg)
1947 {
1948     return cmd_sort_generic (arg, 0);
1949 }
1950
1951 int cmd_sort_newset (char *arg)
1952 {
1953     return cmd_sort_generic (arg, 1);
1954 }
1955
1956 int cmd_scan(char *arg)
1957 {
1958     if (!conn)
1959     {
1960         printf("Session not initialized yet\n");
1961         return 0;
1962     }
1963     if (!ODR_MASK_GET(session->options, Z_Options_scan))
1964     {
1965         printf("Target doesn't support scan\n");
1966         return 0;
1967     }
1968     if (*arg)
1969     {
1970         strcpy (last_scan_query, arg);
1971         if (send_scanrequest(arg, 1, 20, 0) < 0)
1972             return 0;
1973     }
1974     else
1975     {
1976         if (send_scanrequest(last_scan_query, 1, 20, last_scan_line) < 0)
1977             return 0;
1978     }
1979     return 2;
1980 }
1981
1982 int cmd_schema(char *arg)
1983 {
1984     if (!arg || !*arg)
1985     {
1986         schema = VAL_NONE;
1987         return 1;
1988     }
1989     schema = oid_getvalbyname (arg);
1990     if (schema == VAL_NONE)
1991     {
1992         printf ("unknown schema\n");
1993         return 0;
1994     }
1995     return 1;
1996 }
1997
1998 int cmd_format(char *arg)
1999 {
2000     if (!arg || !*arg)
2001     {
2002         printf("Usage: format <recordsyntax>\n");
2003         return 0;
2004     }
2005     recordsyntax = oid_getvalbyname (arg);
2006     if (recordsyntax == VAL_NONE)
2007     {
2008         printf ("unknown record syntax\n");
2009         return 0;
2010     }
2011     return 1;
2012 }
2013
2014 int cmd_elements(char *arg)
2015 {
2016     static Z_ElementSetNames esn;
2017     static char what[100];
2018
2019     if (!arg || !*arg)
2020     {
2021         elementSetNames = 0;
2022         return 1;
2023     }
2024     strcpy(what, arg);
2025     esn.which = Z_ElementSetNames_generic;
2026     esn.u.generic = what;
2027     elementSetNames = &esn;
2028     return 1;
2029 }
2030
2031 int cmd_attributeset(char *arg)
2032 {
2033     char what[100];
2034
2035     if (!arg || !*arg)
2036     {
2037         printf("Usage: attributeset <setname>\n");
2038         return 0;
2039     }
2040     sscanf(arg, "%s", what);
2041     if (p_query_attset (what))
2042     {
2043         printf("Unknown attribute set name\n");
2044         return 0;
2045     }
2046     return 1;
2047 }
2048
2049 int cmd_querytype (char *arg)
2050 {
2051     if (!strcmp (arg, "ccl"))
2052         queryType = QueryType_CCL;
2053     else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
2054         queryType = QueryType_Prefix;
2055     else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn"))
2056         queryType = QueryType_CCL2RPN;
2057     else
2058     {
2059         printf ("Querytype must be one of:\n");
2060         printf (" prefix         - Prefix query\n");
2061         printf (" ccl            - CCL query\n");
2062         printf (" ccl2rpn        - CCL query converted to RPN\n");
2063         return 0;
2064     }
2065     return 1;
2066 }
2067
2068 int cmd_refid (char *arg)
2069 {
2070     xfree (refid);
2071     refid = NULL;
2072     if (*arg)
2073     {
2074         refid = (char *) xmalloc (strlen(arg)+1);
2075         strcpy (refid, arg);
2076     }
2077     return 1;
2078 }
2079
2080 int cmd_close(char *arg)
2081 {
2082     Z_APDU *apdu;
2083     Z_Close *req;
2084     if (!conn)
2085         return 0;
2086
2087     apdu = zget_APDU(out, Z_APDU_close);
2088     req = apdu->u.close;
2089     *req->closeReason = Z_Close_finished;
2090     send_apdu(apdu);
2091     printf("Sent close request.\n");
2092     sent_close = 1;
2093     return 2;
2094 }
2095
2096 int cmd_packagename(char* arg)
2097 {
2098     xfree (esPackageName);
2099     esPackageName = NULL;
2100     if (*arg)
2101     {
2102         esPackageName = (char *) xmalloc (strlen(arg)+1);
2103         strcpy (esPackageName, arg);
2104     }
2105     return 1;
2106 }
2107
2108 int cmd_proxy(char* arg)
2109 {
2110     if (*arg == '\0') {
2111         printf("Current proxy is `%s'\n", (yazCharset)?yazProxy:NULL);
2112         return 1;
2113     }
2114     xfree (yazProxy);
2115     yazProxy = NULL;
2116     if (*arg)
2117     {
2118         yazProxy = (char *) xmalloc (strlen(arg)+1);
2119         strcpy (yazProxy, arg);
2120     } 
2121     return 1;
2122 }
2123
2124 int cmd_charset(char* arg)
2125 {
2126     if (*arg == '\0') {
2127         printf("Current character set is `%s'\n", (yazCharset)?yazCharset:NULL);
2128         return 1;
2129     }
2130     xfree (yazCharset);
2131     yazCharset = NULL;
2132     if (*arg)
2133     {
2134         yazCharset = (char *) xmalloc (strlen(arg)+1);
2135         strcpy (yazCharset, arg);
2136     } 
2137     return 1;
2138 }
2139
2140 int cmd_lang(char* arg)
2141 {
2142     if (*arg == '\0') {
2143         printf("Current language is `%s'\n", (yazLang)?yazLang:NULL);
2144         return 1;
2145     }
2146     xfree (yazLang);
2147     yazLang = NULL;
2148     if (*arg)
2149     {
2150         yazLang = (char *) xmalloc (strlen(arg)+1);
2151         strcpy (yazLang, arg);
2152     } 
2153     return 1;
2154 }
2155
2156 int cmd_source(char* arg) 
2157 {
2158     /* first should open the file and read one line at a time.. */
2159     FILE* includeFile;
2160     char line[1024], *cp;
2161
2162     {
2163         char* args_end=(arg)+strlen(arg)-1; 
2164         while(isspace(*args_end)) 
2165         {*args_end=0;
2166         --args_end;}; 
2167     }
2168
2169     REMOVE_TAILING_BLANKS(arg);
2170     
2171     if(strlen(arg)<1) {
2172         fprintf(stderr,"Error in source command use a filename\n");
2173         return -1;
2174     }
2175     
2176     includeFile = fopen (arg, "r");
2177     
2178     if(!includeFile) {
2179         fprintf(stderr,"Unable to open file %s for reading\n",arg);
2180         return -1;
2181     }
2182     
2183     while(!feof(includeFile)) {
2184         memset(line,0,sizeof(line));
2185         fgets(line,sizeof(line),includeFile);
2186         
2187         if(strlen(line) < 2) continue;
2188         if(line[0] == '#') continue;
2189         
2190         if ((cp = strrchr (line, '\n')))
2191             *cp = '\0';
2192         
2193         process_cmd_line(line);
2194     }
2195     
2196     if(fclose(includeFile)<0) {
2197         perror("unable to close include file");
2198         exit(1);
2199     }
2200     return 1;
2201 }
2202
2203 int cmd_subshell(char* args)
2204 {
2205     if(strlen(args)) 
2206         system(args);
2207     else 
2208         system(getenv("SHELL"));
2209     
2210     printf("\n");
2211     return 1;
2212 }
2213
2214 int cmd_set_apdufile(char* arg)
2215 {
2216     REMOVE_TAILING_BLANKS(arg);
2217   
2218     if(apdu_file && apdu_file != stderr) { /* don't close stdout*/
2219         perror("unable to close apdu log file");      
2220     }
2221     apdu_file=NULL;
2222   
2223     if(strlen(arg)<1) {
2224         return 1;
2225     }
2226   
2227     if(!strcmp(arg,"-")) 
2228         apdu_file=stderr;      
2229     else 
2230         apdu_file=fopen(arg, "a");
2231   
2232     if(!apdu_file) {
2233         perror("unable to open apdu log file no apdu log loaded");
2234     } else {
2235         odr_setprint(print, apdu_file); 
2236     }
2237   
2238     return 1;
2239 }
2240
2241 int cmd_set_cclfields(char* arg)
2242 {  
2243     FILE *inf;
2244
2245     REMOVE_TAILING_BLANKS(arg);
2246
2247     bibset = ccl_qual_mk (); 
2248     inf = fopen (arg, "r");
2249     if (inf)
2250     {
2251         ccl_qual_file (bibset, inf);
2252         fclose (inf);
2253     }
2254     
2255     return 1;
2256 }
2257
2258 int cmd_set_marcdump(char* arg)
2259 {
2260     if(marcdump && marcdump != stderr) { /* don't close stdout*/
2261         perror("unable to close apdu log file");      
2262     }
2263     marcdump=NULL;
2264     
2265     if(strlen(arg)<1) {
2266         return 1;
2267     }
2268   
2269     if(!strcmp(arg,"-")) 
2270         marcdump=stderr;      
2271     else 
2272         marcdump=fopen(arg, "a");
2273   
2274     if(!marcdump) {
2275         perror("unable to open apdu marcdump file no marcdump done\n");
2276     }
2277   
2278     return 1;
2279 }
2280
2281 int cmd_set_proxy(char* arg) {
2282     if(yazProxy) free(yazProxy);
2283     yazProxy=NULL;
2284
2285     if(strlen(arg) > 1) {
2286         yazProxy=strdup(arg);
2287     }
2288     return 1;
2289 }
2290
2291 /* 
2292    this command takes 3 arge {name class oid} 
2293  */
2294 int cmd_register_oid(char* args) {
2295     static struct {
2296         char* className;
2297         oid_class oclass;
2298     } oid_classes[] = {
2299         {"appctx",CLASS_APPCTX},
2300         {"absyn",CLASS_ABSYN},
2301         {"attset",CLASS_ATTSET},
2302         {"transyn",CLASS_TRANSYN},
2303         {"diagset",CLASS_DIAGSET},
2304         {"recsyn",CLASS_RECSYN},
2305         {"resform",CLASS_RESFORM},
2306         {"accform",CLASS_ACCFORM},
2307         {"extserv",CLASS_EXTSERV},
2308         {"userinfo",CLASS_USERINFO},
2309         {"elemspec",CLASS_ELEMSPEC},
2310         {"varset",CLASS_VARSET},
2311         {"schema",CLASS_SCHEMA},
2312         {"tagset",CLASS_TAGSET},
2313         {"general",CLASS_GENERAL},
2314         {0,0}
2315     };
2316     char oname_str[101], oclass_str[101], oid_str[101];  
2317     char* name;
2318     int i;
2319     oid_class oidclass = CLASS_GENERAL;
2320     int val = 0, oid[OID_SIZE];
2321     struct oident * new_oident=NULL;
2322     
2323     if (sscanf (args, "%100[^ ] %100[^ ] %100s",
2324                 oname_str,oclass_str, oid_str) < 1) {
2325         printf("Error in regristrate command \n");
2326         return 0;
2327     }
2328     
2329     for (i = 0; oid_classes[i].className; i++) {
2330         if (!strcmp(oid_classes[i].className, oclass_str))
2331         {
2332             oidclass=oid_classes[i].oclass;
2333             break;
2334         }
2335     }
2336     
2337     if(!(oid_classes[i].className)) {
2338         printf("Unknonwn oid class %s\n",oclass_str);
2339         return 0;
2340     }
2341
2342     i = 0;
2343     name = oid_str;
2344     val = 0;
2345     
2346     while (isdigit (*name))
2347     {
2348         val = val*10 + (*name - '0');
2349         name++;
2350         if (*name == '.')
2351         {
2352             if (i < OID_SIZE-1)
2353                 oid[i++] = val;
2354             val = 0;
2355             name++;
2356         }
2357     }
2358     oid[i] = val;
2359     oid[i+1] = -1;
2360     
2361     new_oident=oid_addent (oid,PROTO_GENERAL,oidclass,oname_str,VAL_DYNAMIC);  
2362     if(strcmp(new_oident->desc,oname_str)) {
2363         fprintf(stderr,"oid is already named as %s, regristration faild\n",
2364                 new_oident->desc);
2365     }
2366     return 1;  
2367 }
2368
2369 int cmd_push_command(char* arg) 
2370 {
2371 #if HAVE_READLINE_HISTORY_H
2372     if(strlen(arg)>1) 
2373         add_history(arg);
2374 #else 
2375     fprintf(stderr,"Not compiled with the readline/history module\n");
2376 #endif
2377     return 1;
2378 }
2379
2380 void source_rcfile() 
2381 {
2382     /*  Look for a $HOME/.yazclientrc and source it if it exists */
2383     struct stat statbuf;
2384     char buffer[1000];
2385     char* homedir=getenv("HOME");
2386
2387     if(!homedir) return;
2388     
2389     sprintf(buffer,"%s/.yazclientrc",homedir);
2390     
2391     if(stat(buffer,&statbuf)==0) {
2392         cmd_source(buffer);
2393     }
2394     
2395     if(stat(".yazclientrc",&statbuf)==0) {
2396         cmd_source(".yazclientrc");
2397     }
2398 }
2399
2400
2401 static void initialize(void)
2402 {
2403 #if YAZ_MODULE_ccl
2404     FILE *inf;
2405 #endif
2406     if (!(out = odr_createmem(ODR_ENCODE)) ||
2407         !(in = odr_createmem(ODR_DECODE)) ||
2408         !(print = odr_createmem(ODR_PRINT)))
2409     {
2410         fprintf(stderr, "failed to allocate ODR streams\n");
2411         exit(1);
2412     }
2413     oid_init();
2414
2415     setvbuf(stdout, 0, _IONBF, 0);
2416     if (apdu_file)
2417         odr_setprint(print, apdu_file);
2418
2419 #if YAZ_MODULE_ccl
2420     bibset = ccl_qual_mk (); 
2421     inf = fopen (ccl_fields, "r");
2422     if (inf)
2423     {
2424         ccl_qual_file (bibset, inf);
2425         fclose (inf);
2426     }
2427 #endif
2428     cmd_base("Default");
2429
2430 #if HAVE_READLINE_READLINE_H
2431     rl_attempted_completion_function = (CPPFunction*)readline_completer;
2432 #endif
2433
2434     source_rcfile();
2435 }
2436
2437
2438 #if HAVE_GETTIMEOFDAY
2439 struct timeval tv_start, tv_end;
2440 #endif
2441
2442 void wait_and_handle_responce() 
2443 {
2444     
2445     int res;
2446     char *netbuffer= 0;
2447     int netbufferlen = 0;
2448     Z_APDU *apdu;
2449     
2450     
2451     if (conn)
2452     {
2453         do
2454         {
2455             if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0)
2456             {
2457                 printf("Target closed connection\n");
2458                 close_session ();
2459                 break;
2460             }
2461             if (!res)
2462             {
2463                 printf("Target closed connection.\n");
2464                 close_session ();
2465                 break;
2466             }
2467             odr_reset(in); /* release APDU from last round */
2468             record_last = 0;
2469             odr_setbuf(in, netbuffer, res, 0);
2470             if (!z_APDU(in, &apdu, 0, 0))
2471             {
2472                 odr_perror(in, "Decoding incoming APDU");
2473                 fprintf(stderr, "[Near %d]\n", odr_offset(in));
2474                 fprintf(stderr, "Packet dump:\n---------\n");
2475                 odr_dumpBER(stderr, netbuffer, res);
2476                 fprintf(stderr, "---------\n");
2477                 if (apdu_file)
2478                     z_APDU(print, &apdu, 0, 0);
2479                 close_session ();
2480                 break;
2481             }
2482             if (apdu_file && !z_APDU(print, &apdu, 0, 0))
2483             {
2484                 odr_perror(print, "Failed to print incoming APDU");
2485                 odr_reset(print);
2486                 continue;
2487             }
2488             switch(apdu->which)
2489             {
2490             case Z_APDU_initResponse:
2491                 process_initResponse(apdu->u.initResponse);
2492                 break;
2493             case Z_APDU_searchResponse:
2494                 process_searchResponse(apdu->u.searchResponse);
2495                 break;
2496             case Z_APDU_scanResponse:
2497                 process_scanResponse(apdu->u.scanResponse);
2498                 break;
2499             case Z_APDU_presentResponse:
2500                 print_refid (apdu->u.presentResponse->referenceId);
2501                 setno +=
2502                     *apdu->u.presentResponse->numberOfRecordsReturned;
2503                 if (apdu->u.presentResponse->records)
2504                     display_records(apdu->u.presentResponse->records);
2505                 else
2506                     printf("No records.\n");
2507                 printf ("nextResultSetPosition = %d\n",
2508                         *apdu->u.presentResponse->nextResultSetPosition);
2509                 break;
2510             case Z_APDU_sortResponse:
2511                 process_sortResponse(apdu->u.sortResponse);
2512                 break;
2513             case Z_APDU_extendedServicesResponse:
2514                 printf("Got extended services response\n");
2515                 process_ESResponse(apdu->u.extendedServicesResponse);
2516                 break;
2517             case Z_APDU_close:
2518                 printf("Target has closed the association.\n");
2519                 process_close(apdu->u.close);
2520                 break;
2521             case Z_APDU_resourceControlRequest:
2522                 process_resourceControlRequest
2523                     (apdu->u.resourceControlRequest);
2524                 break;
2525             case Z_APDU_deleteResultSetResponse:
2526                 process_deleteResultSetResponse(apdu->u.
2527                                                 deleteResultSetResponse);
2528                 break;
2529             default:
2530                 printf("Received unknown APDU type (%d).\n", 
2531                        apdu->which);
2532                 close_session ();
2533             }
2534         }
2535         while (conn && cs_more(conn));
2536 #if HAVE_GETTIMEOFDAY
2537         gettimeofday (&tv_end, 0);
2538 #if 0
2539         printf ("S/U S/U=%ld/%ld %ld/%ld",
2540                 (long) tv_start.tv_sec,
2541                 (long) tv_start.tv_usec,
2542                 (long) tv_end.tv_sec,
2543                 (long) tv_end.tv_usec);
2544 #endif
2545         printf ("Elapsed: %.6f\n",
2546                 (double) tv_end.tv_usec / 1e6 + tv_end.tv_sec -
2547                 ((double) tv_start.tv_usec / 1e6 + tv_start.tv_sec));
2548 #endif
2549     }
2550     xfree (netbuffer);
2551 }
2552
2553
2554 static int cmd_help (char *line);
2555
2556 typedef char *(*completerFunctionType)(const char *text, int state);
2557
2558 static struct {
2559     char *cmd;
2560     int (*fun)(char *arg);
2561     char *ad;
2562         completerFunctionType rl_completerfunction;
2563     //char *(*rl_completerfunction)(const char *text, int state);
2564     int complete_filenames;
2565         char **local_tabcompletes;
2566 } cmd[] = {
2567     {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
2568     {"quit", cmd_quit, "",NULL,0,NULL},
2569     {"find", cmd_find, "<query>",NULL,0,NULL},
2570     {"delete", cmd_delete, "<setname>",NULL,0,NULL},
2571     {"base", cmd_base, "<base-name>",NULL,0,NULL},
2572     {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]",NULL,0,NULL},
2573     {"scan", cmd_scan, "<term>",NULL,0,NULL},
2574     {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
2575     {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
2576     {"authentication", cmd_authentication, "<acctstring>",NULL,0,NULL},
2577     {"lslb", cmd_lslb, "<largeSetLowerBound>",NULL,0,NULL},
2578     {"ssub", cmd_ssub, "<smallSetUpperBound>",NULL,0,NULL},
2579     {"mspn", cmd_mspn, "<mediumSetPresentNumber>",NULL,0,NULL},
2580     {"status", cmd_status, "",NULL,0,NULL},
2581     {"setnames", cmd_setnames, "",NULL,0,NULL},
2582     {"cancel", cmd_cancel, "",NULL,0,NULL},
2583     {"format", cmd_format, "<recordsyntax>",complete_format,0,NULL},
2584     {"schema", cmd_schema, "<schema>",complete_schema,0,NULL},
2585     {"elements", cmd_elements, "<elementSetName>",NULL,0,NULL},
2586     {"close", cmd_close, "",NULL,0,NULL},
2587     {"attributeset", cmd_attributeset, "<attrset>",complete_attributeset,0,NULL},
2588     {"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
2589     {"refid", cmd_refid, "<id>",NULL,0,NULL},
2590     {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
2591     {"update", cmd_update, "<item>",NULL,0,NULL},
2592     {"packagename", cmd_packagename, "<packagename>",NULL,0,NULL},
2593     {"proxy", cmd_proxy, "[('tcp'|'ssl')]<host>[':'<port>]",NULL,0,NULL},
2594     {"charset", cmd_charset, "<charset_name>",NULL,0,NULL},
2595     {"lang", cmd_lang, "<language_code>",NULL,0,NULL},
2596     {".", cmd_source, "<filename>",NULL,1,NULL},
2597     {"!", cmd_subshell, "Subshell command",NULL,1,NULL},
2598     {"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
2599     {"set_marcdump", cmd_set_marcdump," <filename>",NULL,1,NULL},
2600     {"set_cclfiele", cmd_set_cclfields," <filename>",NULL,1,NULL},
2601     {"register_oid", cmd_register_oid,"<name> <class> <oid>",NULL,0,NULL},
2602     {"push_command", cmd_push_command,"<command>",command_generator,0,NULL},
2603         {"register_tab", cmd_register_tab,"<commandname> <tab>",command_generator,0,NULL},
2604     /* Server Admin Functions */
2605     {"adm-reindex", cmd_adm_reindex, "<database-name>",NULL,0,NULL},
2606     {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>",NULL,0,NULL},
2607     {"adm-create", cmd_adm_create, "",NULL,0,NULL},
2608     {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>",NULL,0,NULL},
2609     {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>",NULL,0,NULL},
2610     {"adm-refresh", cmd_adm_refresh, "",NULL,0,NULL},
2611     {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
2612     {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
2613     {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},
2614     {"help", cmd_help, "", NULL,0,NULL},
2615     {0,0,0,0,0,0}
2616 };
2617
2618 static int cmd_help (char *line)
2619 {
2620     int i;
2621     char topic[21];
2622     
2623     *topic = 0;
2624     sscanf (line, "%20s", topic);
2625
2626     if (*topic == 0)
2627         printf("Commands:\n");
2628     for (i = 0; cmd[i].cmd; i++)
2629         if (*topic == 0 || strcmp (topic, cmd[i].cmd) == 0)
2630             printf("   %s %s\n", cmd[i].cmd, cmd[i].ad);
2631     if (strcmp (topic, "find") == 0)
2632     {
2633         printf ("RPN:\n");
2634         printf (" \"term\"                        Simple Term\n");
2635         printf (" @attr [attset] type=value op  Attribute\n");
2636         printf (" @and opl opr                  And\n");
2637         printf (" @or opl opr                   Or\n");
2638         printf (" @not opl opr                  And-Not\n");
2639         printf (" @set set                      Result set\n");
2640         printf ("\n");
2641         printf ("Bib-1 attribute types\n");
2642         printf ("1=Use:         ");
2643         printf ("4=Title 7=ISBN 8=ISSN 30=Date 62=Abstract 1003=Author 1016=Any\n");
2644         printf ("2=Relation:    ");
2645         printf ("1<   2<=  3=  4>=  5>  6!=  102=Relevance\n");
2646         printf ("3=Position:    ");
2647         printf ("1=First in Field  2=First in subfield  3=Any position\n");
2648         printf ("4=Structure:   ");
2649         printf ("1=Phrase  2=Word  3=Key  4=Year  5=Date  6=WordList\n");
2650         printf ("5=Truncation:  ");
2651         printf ("1=Right  2=Left  3=L&R  100=No  101=#  102=Re-1  103=Re-2\n");
2652         printf ("6=Completeness:");
2653         printf ("1=Incomplete subfield  2=Complete subfield  3=Complete field\n");
2654     }
2655     return 1;
2656 }
2657
2658 int cmd_register_tab(char* arg) {
2659         
2660         char command[101], tabargument[101];
2661         int i, res;
2662         int num_of_tabs;
2663         char** tabslist;
2664
2665         if (sscanf (arg, "%100s %100s", command, tabargument) < 1) {
2666                 return 0;
2667         };
2668
2669         /* locate the amdn in the list */
2670         for (i = 0; cmd[i].cmd; i++) {
2671                 if (!strncmp(cmd[i].cmd, command, strlen(command))) {
2672                         break;
2673                 }
2674         }
2675         
2676         if(!cmd[i].cmd) { 
2677                 fprintf(stderr,"Unknown command %s\n",command);
2678                 return 1;
2679         };
2680         
2681
2682
2683         if(!cmd[i].local_tabcompletes) {
2684                 cmd[i].local_tabcompletes = calloc(1,sizeof(char**));
2685         };
2686         
2687         num_of_tabs=0;          
2688         
2689         tabslist = cmd[i].local_tabcompletes;
2690         for(;tabslist && *tabslist;tabslist++) {
2691                 num_of_tabs++;
2692         };  
2693
2694         cmd[i].local_tabcompletes=realloc(cmd[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
2695         tabslist=cmd[i].local_tabcompletes;
2696         tabslist[num_of_tabs]=strdup(tabargument);
2697         tabslist[num_of_tabs+1]=NULL;
2698 }
2699
2700 void process_cmd_line(char* line)
2701 {  
2702     int i,res;
2703     char word[32], arg[1024];
2704     
2705 #if HAVE_GETTIMEOFDAY
2706     gettimeofday (&tv_start, 0);
2707 #endif
2708     
2709     if ((res = sscanf(line, "%31s %1023[^;]", word, arg)) <= 0)
2710     {
2711         strcpy(word, last_cmd);
2712         *arg = '\0';
2713     }
2714     else if (res == 1)
2715         *arg = 0;
2716     strcpy(last_cmd, word);
2717     
2718     /* removed tailing spaces from the arg command */
2719     { 
2720         char* p;
2721         char* lastnonspace=NULL;
2722         p = arg;
2723         
2724         for(;*p; ++p) {
2725             if(!isspace(*p)) {
2726                 lastnonspace = p;
2727             }
2728         }
2729         if(lastnonspace) 
2730             *(++lastnonspace) = 0;
2731     }
2732     
2733
2734     for (i = 0; cmd[i].cmd; i++)
2735         if (!strncmp(cmd[i].cmd, word, strlen(word)))
2736         {
2737             res = (*cmd[i].fun)(arg);
2738             break;
2739         }
2740
2741     if (!cmd[i].cmd) /* dump our help-screen */
2742     {
2743         printf("Unknown command: %s.\n", word);
2744         cmd_help ("");
2745         res = 1;
2746     }
2747
2748     if(apdu_file) fflush(apdu_file);
2749     
2750     if (res >= 2)
2751         wait_and_handle_responce();
2752
2753     if(apdu_file)
2754         fflush(apdu_file);
2755     if(marcdump)
2756         fflush(marcdump);
2757 }
2758
2759
2760 char *command_generator(const char *text, int state) 
2761 {
2762     static int idx; 
2763     if (state==0) {
2764         idx = 0;
2765     }
2766     for( ; cmd[idx].cmd; ++idx) {
2767         if (!strncmp(cmd[idx].cmd,text,strlen(text))) {
2768             ++idx;  /* skip this entry on the next run */
2769             return strdup(cmd[idx-1].cmd);
2770         }
2771     }
2772     return NULL;
2773 }
2774
2775
2776 /* 
2777    This function only known how to complete on the first word
2778 */
2779 char ** readline_completer(char *text, int start, int end) {
2780 #if HAVE_READLINE_READLINE_H
2781
2782         completerFunctionType completerToUse;
2783         
2784     if(start == 0) {
2785 #if HAVE_READLINE_RL_COMPLETION_MATCHES
2786         char** res=rl_completion_matches(text,
2787                                       command_generator); 
2788 #else
2789         char** res=completion_matches(text,
2790                                       (CPFunction*)command_generator); 
2791 #endif
2792         rl_attempted_completion_over = 1;
2793         return res;
2794     } else {
2795         char arg[1024],word[32];
2796         int i=0 ,res;
2797         if ((res = sscanf(rl_line_buffer, "%31s %1023[^;]", word, arg)) <= 0) {     
2798             rl_attempted_completion_over = 1;
2799             return NULL;
2800         }
2801     
2802         if(start != strlen(word) +1 ) {
2803             rl_attempted_completion_over = 1;
2804             return 0;
2805         }
2806         for (i = 0; cmd[i].cmd; i++) {
2807             if (!strncmp(cmd[i].cmd, word, strlen(word))) {
2808                 break;
2809             }
2810         }
2811     
2812                 if(!cmd[i].cmd) return NULL;
2813
2814
2815                 curret_global_list = cmd[i].local_tabcompletes;
2816                 
2817                 completerToUse = cmd[i].rl_completerfunction;
2818                 if(completerToUse==NULL)  /* if no pr. command completer is defined use the default completer */
2819                         completerToUse = default_completer;
2820                 
2821         if(completerToUse) {
2822 #ifdef HAVE_READLINE_RL_COMPLETION_MATCHES
2823             char** res=
2824                 rl_completion_matches(text,
2825                                    completerToUse);
2826 #else
2827             char** res=
2828                 completion_matches(text,
2829                                    (CPFunction*)completerToUse);
2830 #endif
2831                         if(!cmd[i].complete_filenames) 
2832                                 rl_attempted_completion_over = 1;
2833                         return res;
2834         } else {
2835                         if(!cmd[i].complete_filenames) 
2836                                 rl_attempted_completion_over = 1;
2837             return 0;
2838         }
2839     }
2840 #else 
2841     return 0;
2842 #endif 
2843 }
2844
2845
2846 static void client(void)
2847 {
2848     char line[1024];
2849
2850     line[1023] = '\0';
2851
2852 #if HAVE_GETTIMEOFDAY
2853     gettimeofday (&tv_start, 0);
2854 #endif
2855
2856     while (1)
2857     {
2858         char *line_in = NULL;
2859 #if HAVE_READLINE_READLINE_H
2860         if (isatty(0))
2861         {
2862             line_in=readline(C_PROMPT);
2863             if (!line_in)
2864                 break;
2865 #if HAVE_READLINE_HISTORY_H
2866             if (*line_in)
2867                 add_history(line_in);
2868 #endif
2869             strncpy(line, line_in, 1023);
2870             free (line_in);
2871         }
2872 #endif 
2873         if (!line_in)
2874         {
2875             char *end_p;
2876             printf (C_PROMPT);
2877             fflush(stdout);
2878             if (!fgets(line, 1023, stdin))
2879                 break;
2880             if ((end_p = strchr (line, '\n')))
2881                 *end_p = '\0';
2882         }
2883         process_cmd_line(line);
2884     }
2885 }
2886
2887 int main(int argc, char **argv)
2888 {
2889     char *prog = *argv;
2890     char *open_command = 0;
2891     char *auth_command = 0;
2892     char *arg;
2893     int ret;
2894     
2895     while ((ret = options("k:c:a:m:v:p:u:", argv, argc, &arg)) != -2)
2896     {
2897         switch (ret)
2898         {
2899         case 0:
2900             if (!open_command)
2901             {
2902                 open_command = (char *) xmalloc (strlen(arg)+6);
2903                 strcpy (open_command, "open ");
2904                 strcat (open_command, arg);
2905             }
2906             break;
2907         case 'k':
2908             kilobytes = atoi(arg);
2909             break;
2910         case 'm':
2911             if (!(marcdump = fopen (arg, "a")))
2912             {
2913                 perror (arg);
2914                 exit (1);
2915             }
2916             break;
2917     case 'c':
2918         strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
2919         ccl_fields[sizeof(ccl_fields)-1] = '\0';
2920         break;
2921         case 'a':
2922             if (!strcmp(arg, "-"))
2923                 apdu_file=stderr;
2924             else
2925                 apdu_file=fopen(arg, "a");
2926             break;
2927     case 'p':
2928         yazProxy=strdup(arg);
2929         break;
2930         case 'u':
2931             if (!auth_command)
2932             {
2933                 auth_command = (char *) xmalloc (strlen(arg)+6);
2934                 strcpy (auth_command, "auth ");
2935                 strcat (auth_command, arg);
2936             }
2937             break;
2938         case 'v':
2939             yaz_log_init (yaz_log_mask_str(arg), "", NULL);
2940             break;
2941         default:
2942             fprintf (stderr, "Usage: %s [-m <marclog>] [ -a <apdulog>] "
2943                      "[-c cclfields]\n      [-p <proxy-addr>] [-u <auth>] "
2944                      "[-k size] [<server-addr>]\n",
2945                      prog);
2946             exit (1);
2947         }      
2948     }
2949     initialize();
2950     if (auth_command)
2951     {
2952 #ifdef HAVE_GETTIMEOFDAY
2953         gettimeofday (&tv_start, 0);
2954 #endif
2955         process_cmd_line (auth_command);
2956 #if HAVE_READLINE_HISTORY_H
2957         add_history(auth_command);
2958 #endif
2959         xfree(auth_command);
2960     }
2961     if (open_command)
2962     {
2963 #ifdef HAVE_GETTIMEOFDAY
2964         gettimeofday (&tv_start, 0);
2965 #endif
2966         process_cmd_line (open_command);
2967 #if HAVE_READLINE_HISTORY_H
2968         add_history(open_command);
2969 #endif
2970         xfree(open_command);
2971     }
2972     client ();
2973     exit (0);
2974 }
2975
2976
2977 /*
2978  * Local variables:
2979  * tab-width: 4
2980  * c-basic-offset: 4
2981  * End:
2982  */