46368143247af8c19c29312821714d549b751308
[yaz-moved-to-github.git] / client / client.c
1 /*
2  * Copyright (c) 1995, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: client.c,v $
7  * Revision 1.17  1995-08-17 12:45:02  quinn
8  * Fixed minor problems with GRS-1. Added support in c&s.
9  *
10  * Revision 1.16  1995/08/15  12:00:04  quinn
11  * Updated External
12  *
13  * Revision 1.15  1995/06/22  09:28:03  quinn
14  * Fixed bug in SUTRS processing.
15  *
16  * Revision 1.14  1995/06/19  12:37:41  quinn
17  * Added BER dumper.
18  *
19  * Revision 1.13  1995/06/16  10:29:11  quinn
20  * *** empty log message ***
21  *
22  * Revision 1.12  1995/06/15  07:44:57  quinn
23  * Moving to v3.
24  *
25  * Revision 1.11  1995/06/14  15:26:40  quinn
26  * *** empty log message ***
27  *
28  * Revision 1.10  1995/06/06  14:56:58  quinn
29  * Better diagnostics.
30  *
31  * Revision 1.9  1995/06/06  08:15:19  quinn
32  * Cosmetic.
33  *
34  * Revision 1.8  1995/06/05  10:52:22  quinn
35  * Added SCAN.
36  *
37  * Revision 1.7  1995/06/02  09:50:09  quinn
38  * Smallish.
39  *
40  * Revision 1.6  1995/05/31  08:29:21  quinn
41  * Nothing significant.
42  *
43  * Revision 1.5  1995/05/29  08:10:47  quinn
44  * Moved oid.c to util.
45  *
46  * Revision 1.4  1995/05/22  15:30:13  adam
47  * Client uses prefix query notation.
48  *
49  * Revision 1.3  1995/05/22  15:06:53  quinn
50  * *** empty log message ***
51  *
52  * Revision 1.2  1995/05/22  14:56:40  quinn
53  * *** empty log message ***
54  *
55  * Revision 1.1  1995/05/22  11:30:31  quinn
56  * Added prettier client.
57  *
58  *
59  */
60
61 /*
62  * This is the obligatory little toy client, whose primary purpose is
63  * to illustrate the use of the YAZ service-level API.
64  */
65
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <sys/time.h>
69 #include <assert.h>
70 #ifdef _AIX
71 #include <sys/select.h>
72 #endif
73
74 #include <comstack.h>
75 #include <tcpip.h>
76 #ifdef USE_XTIMOSI
77 #include <xmosi.h>
78 #endif
79
80 #include <proto.h>
81 #include <marcdisp.h>
82 #include <diagbib1.h>
83
84 #ifdef RPN_QUERY
85 #ifdef PREFIX_QUERY
86 #include <pquery.h>
87 #else
88 #include <yaz-ccl.h>
89 #endif
90 #endif
91
92 #define C_PROMPT "Z> "
93
94 static ODR out, in, print;              /* encoding and decoding streams */
95 static COMSTACK conn = 0;               /* our z-association */
96 static Z_IdAuthentication *auth = 0;    /* our current auth definition */
97 static char database[512] = "Default";  /* Database name */
98 static int setnumber = 0;               /* current result set number */
99 static int smallSetUpperBound = 0;
100 static int largeSetLowerBound = 1;
101 static int mediumSetPresentNumber = 0;
102 static int setno = 1;                   /* current set offset */
103 static int protocol = PROTO_Z3950;      /* current app protocol */
104 static int recordsyntax = VAL_USMARC;
105 static ODR_MEM session_mem;                /* memory handle for init-response */
106 static Z_InitResponse *session = 0;        /* session parameters */
107 static char last_scan[512] = "0";
108 static char last_cmd[100] = "?";
109 #ifdef RPN_QUERY
110 #ifndef PREFIX_QUERY
111 static CCL_bibset bibset;               /* CCL bibset handle */
112 #endif
113 #endif
114
115 static void send_apdu(Z_APDU *a)
116 {
117     char *buf;
118     int len;
119
120     if (!z_APDU(out, &a, 0))
121     {
122         odr_perror(out, "Encoding APDU");
123         exit(1);
124     }
125     buf = odr_getbuf(out, &len, 0);
126     odr_reset(out); /* release the APDU */
127     if (cs_put(conn, buf, len) < 0)
128     {
129         fprintf(stderr, "cs_put: %s", cs_errlist[cs_errno(conn)]);
130         exit(1);
131     }
132 }
133
134 /* INIT SERVICE ------------------------------- */
135
136 static void send_initRequest()
137 {
138     Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
139     Z_InitRequest *req = apdu->u.initRequest;
140
141     ODR_MASK_SET(req->options, Z_Options_search);
142     ODR_MASK_SET(req->options, Z_Options_present);
143     ODR_MASK_SET(req->options, Z_Options_namedResultSets);
144     ODR_MASK_SET(req->options, Z_Options_triggerResourceCtrl);
145     ODR_MASK_SET(req->options, Z_Options_scan);
146
147     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
148     ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
149
150     req->idAuthentication = auth;
151
152     send_apdu(apdu);
153     printf("Sent initrequest.\n");
154 }
155
156 static int process_initResponse(Z_InitResponse *res)
157 {
158     /* save session parameters for later use */
159     session_mem = odr_extract_mem(in);
160     session = res;
161
162     if (!*res->result)
163         printf("Connection rejected by target.\n");
164     else
165         printf("Connection accepted by target.\n");
166     if (res->implementationId)
167         printf("ID     : %s\n", res->implementationId);
168     if (res->implementationName)
169         printf("Name   : %s\n", res->implementationName);
170     if (res->implementationVersion)
171         printf("Version: %s\n", res->implementationVersion);
172     if (res->userInformationField)
173     {
174         printf("UserInformationfield:\n");
175         if (!z_External(print, (Z_External**)&res-> userInformationField,
176             0))
177         {
178             odr_perror(print, "Printing userinfo\n");
179             odr_reset(print);
180         }
181         if (res->userInformationField->which == ODR_EXTERNAL_octet)
182         {
183             printf("Guessing visiblestring:\n");
184             printf("'%s'\n", res->userInformationField->u. octet_aligned->buf);
185         }
186     }
187     return 0;
188 }
189
190 int cmd_open(char *arg)
191 {
192     void *add;
193     char type[100], addr[100];
194     CS_TYPE t;
195
196     if (conn)
197     {
198         printf("Already connected.\n");
199         return 0;
200     }
201     if (!*arg || sscanf(arg, "%[^:]:%s", type, addr) < 2)
202     {
203         fprintf(stderr, "Usage: open (osi|tcp) ':' [tsel '/']host[':'port]\n");
204         return 0;
205     }
206 #ifdef USE_XTIMOSI
207     if (!strcmp(type, "osi"))
208     {
209         if (!(add = mosi_strtoaddr(addr)))
210         {
211             perror(arg);
212             return 0;
213         }
214         t = mosi_type;
215         protocol = PROTO_SR;
216     }
217     else
218 #endif
219     if (!strcmp(type, "tcp"))
220     {
221         if (!(add = tcpip_strtoaddr(addr)))
222         {
223             perror(arg);
224             return 0;
225         }
226         t = tcpip_type;
227         protocol = PROTO_Z3950;
228     }
229     else
230     {
231         fprintf(stderr, "Bad type: %s\n", type);
232         return 0;
233     }
234     if (!(conn = cs_create(t, 1, protocol)))
235     {
236         perror("cs_create");
237         return 0;
238     }
239     printf("Connecting...");
240     fflush(stdout);
241     if (cs_connect(conn, add) < 0)
242     {
243         perror("connect");
244         cs_close(conn);
245         conn = 0;
246         return 0;
247     }
248     printf("Ok.\n");
249     send_initRequest();
250     return 2;
251 }
252
253 int cmd_authentication(char *arg)
254 {
255     static Z_IdAuthentication au;
256     static char open[256];
257
258     if (!*arg)
259     {
260         printf("Auth field set to null\n");
261         auth = 0;
262         return 1;
263     }
264     auth = &au;
265     au.which = Z_IdAuthentication_open;
266     au.u.open = open;
267     strcpy(open, arg);
268     return 1;
269 }
270
271 /* SEARCH SERVICE ------------------------------ */
272
273 void display_grs1(Z_GenericRecord *r, int level)
274 {
275     int i;
276
277     if (!r)
278         return;
279     for (i = 0; i < r->num_elements; i++)
280     {
281         Z_TaggedElement *t;
282
283         printf("%*s", level * 4, "");
284         t = r->elements[i];
285         printf("(");
286         if (t->tagType)
287             printf("%d,", *t->tagType);
288         else
289             printf("?,");
290         if (t->tagValue->which == Z_StringOrNumeric_numeric)
291             printf("%d) ", *t->tagValue->u.numeric);
292         else
293             printf("%s) ", t->tagValue->u.string);
294         if (t->content->which == Z_ElementData_subtree)
295         {
296             printf("\n");
297             display_grs1(t->content->u.subtree, level+1);
298         }
299         else if (t->content->which == Z_ElementData_string)
300             printf("%s\n", t->content->u.string);
301         else
302             printf("??????\n");
303     }
304 }
305
306 void display_record(Z_DatabaseRecord *p)
307 {
308     Z_External *r = (Z_External*) p;
309     oident *ent = oid_getentbyoid(r->direct_reference);
310
311     if (r->direct_reference)
312     {
313         printf("Record type: ");
314         if (ent)
315             printf("%s\n", ent->desc);
316         else if (!odr_oid(print, &r->direct_reference, 0))
317         {
318             odr_perror(print, "print oid");
319             odr_reset(print);
320         }
321     }
322     if (r->which == ODR_EXTERNAL_octet && p->u.octet_aligned->len)
323         marc_display ((char*)p->u.octet_aligned->buf, stdout);
324     else if (ent->value == VAL_SUTRS)
325     {
326         if (r->which != Z_External_sutrs)
327         {
328             printf("Expecting single SUTRS type for SUTRS.\n");
329             return;
330         }
331         printf("%.*s", r->u.sutrs->len, r->u.sutrs->buf);
332     }
333     else if (ent->value == VAL_GRS1)
334     {
335         if (r->which != Z_External_grs1)
336         {
337             printf("Expecting single GRS type for GRS.\n");
338             return;
339         }
340         display_grs1(r->u.grs1, 0);
341     }
342     else 
343     {
344         printf("Unknown record representation.\n");
345         if (!z_External(print, &r, 0))
346         {
347             odr_perror(print, "Printing external");
348             odr_reset(print);
349         }
350     }
351 }
352
353 static void display_diagrec(Z_DiagRec *p)
354 {
355     oident *ent;
356 #ifdef Z_95
357     Z_DefaultDiagFormat *r;
358 #else
359     Z_DiagRec *r = p;
360 #endif
361
362     printf("Diagnostic message from database:\n");
363 #ifdef Z_95
364     if (p->which != Z_DiagRec_defaultFormat)
365     {
366         printf("Diagnostic record not in default format.\n");
367         return;
368     }
369     else
370         r = p->u.defaultFormat;
371 #endif
372     if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
373         ent->class != CLASS_DIAGSET || ent->value != VAL_BIB1)
374         printf("Missing or unknown diagset\n");
375     printf("    [%d] %s", *r->condition, diagbib1_str(*r->condition));
376     if (r->addinfo && *r->addinfo)
377         printf(" -- %s\n", r->addinfo);
378     else
379         printf("\n");
380 }
381
382 static void display_nameplusrecord(Z_NamePlusRecord *p)
383 {
384     if (p->databaseName)
385         printf("[%s]", p->databaseName);
386     if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
387         display_diagrec(p->u.surrogateDiagnostic);
388     else
389         display_record(p->u.databaseRecord);
390 }
391
392 static void display_records(Z_Records *p)
393 {
394     int i;
395
396     if (p->which == Z_Records_NSD)
397         display_diagrec(p->u.nonSurrogateDiagnostic);
398     else
399     {
400         printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
401         for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
402             display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
403     }
404 }
405
406 static int send_searchRequest(char *arg)
407 {
408     Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
409     Z_SearchRequest *req = apdu->u.searchRequest;
410     char *databaseNames = database;
411     Z_Query query;
412 #ifdef RPN_QUERY
413 #ifndef PREFIX_QUERY
414     struct ccl_rpn_node *rpn;
415     int error, pos;
416 #endif
417 #endif
418     char setstring[100];
419 #ifdef RPN_QUERY
420     Z_RPNQuery *RPNquery;
421     oident bib1;
422 #else
423     Odr_oct ccl_query;
424 #endif
425
426 #ifdef RPN_QUERY
427 #ifndef PREFIX_QUERY
428     rpn = ccl_find_str(bibset, arg, &error, &pos);
429     if (error)
430     {
431         printf("CCL ERROR: %s\n", ccl_err_msg(error));
432         return 0;
433     }
434 #endif
435 #endif
436
437     if (!strcmp(arg, "@big")) /* strictly for troublemaking */
438     {
439         static unsigned char big[2100];
440         static Odr_oct bigo;
441
442         /* send a very big referenceid to test transport stack etc. */
443         memset(big, 'A', 2100);
444         bigo.len = bigo.size = 2100;
445         bigo.buf = big;
446         req->referenceId = &bigo;
447     }
448
449     if (setnumber >= 0)
450     {
451         sprintf(setstring, "%d", ++setnumber);
452         req->resultSetName = setstring;
453     }
454     *req->smallSetUpperBound = smallSetUpperBound;
455     *req->largeSetLowerBound = largeSetLowerBound;
456     *req->mediumSetPresentNumber = mediumSetPresentNumber;
457     if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
458         mediumSetPresentNumber > 0))
459     {
460         oident prefsyn;
461
462         prefsyn.proto = protocol;
463         prefsyn.class = CLASS_RECSYN;
464         prefsyn.value = recordsyntax;
465         req->preferredRecordSyntax = odr_oiddup(out, oid_getoidbyent(&prefsyn));
466     }
467     req->num_databaseNames = 1;
468     req->databaseNames = &databaseNames;
469
470     req->query = &query;
471
472 #ifdef RPN_QUERY
473     query.which = Z_Query_type_1;
474
475 #ifndef PREFIX_QUERY
476     assert((RPNquery = ccl_rpn_query(rpn)));
477 #else
478     RPNquery = p_query_rpn (out, arg);
479     if (!RPNquery)
480     {
481         printf("Prefix query error\n");
482         return 0;
483     }
484 #endif
485     bib1.proto = protocol;
486     bib1.class = CLASS_ATTSET;
487     bib1.value = VAL_BIB1;
488     RPNquery->attributeSetId = oid_getoidbyent(&bib1);
489     query.u.type_1 = RPNquery;
490 #else
491     query.which = Z_Query_type_2;
492     query.u.type_2 = &ccl_query;
493     ccl_query.buf = (unsigned char*) arg;
494     ccl_query.len = strlen(arg);
495 #endif
496
497     send_apdu(apdu);
498     setno = 1;
499     printf("Sent searchRequest.\n");
500     return 2;
501 }
502
503 static int process_searchResponse(Z_SearchResponse *res)
504 {
505     if (*res->searchStatus)
506         printf("Search was a success.\n");
507     else
508         printf("Search was a bloomin' failure.\n");
509     printf("Number of hits: %d, setno %d\n",
510         *res->resultCount, setnumber);
511     printf("records returned: %d\n",
512         *res->numberOfRecordsReturned);
513     setno += *res->numberOfRecordsReturned;
514     if (res->records)
515         display_records(res->records);
516     return 0;
517 }
518
519 static int cmd_find(char *arg)
520 {
521     if (!*arg)
522     {
523         printf("Find what?\n");
524         return 0;
525     }
526     if (!conn)
527     {
528         printf("Not connected yet\n");
529         return 0;
530     }
531     if (!send_searchRequest(arg))
532         return 0;
533     return 2;
534 }
535
536 static int cmd_ssub(char *arg)
537 {
538     if (!(smallSetUpperBound = atoi(arg)))
539         return 0;
540     return 1;
541 }
542
543 static int cmd_lslb(char *arg)
544 {
545     if (!(largeSetLowerBound = atoi(arg)))
546         return 0;
547     return 1;
548 }
549
550 static int cmd_mspn(char *arg)
551 {
552     if (!(mediumSetPresentNumber = atoi(arg)))
553         return 0;
554     return 1;
555 }
556
557 static int cmd_status(char *arg)
558 {
559     printf("smallSetUpperBound: %d\n", smallSetUpperBound);
560     printf("largeSetLowerBound: %d\n", largeSetLowerBound);
561     printf("mediumSetPresentNumber: %d\n", mediumSetPresentNumber);
562     return 1;
563 }
564
565 static int cmd_base(char *arg)
566 {
567     if (!*arg)
568     {
569         printf("Usage: base <database>\n");
570         return 0;
571     }
572     strcpy(database, arg);
573     return 1;
574 }
575
576 static int cmd_setnames(char *arg)
577 {
578     if (setnumber < 0)
579     {
580         printf("Set numbering enabled.\n");
581         setnumber = 0;
582     }
583     else
584     {
585         printf("Set numbering disabled.\n");
586         setnumber = -1;
587     }
588     return 1;
589 }
590
591 /* PRESENT SERVICE ----------------------------- */
592
593 static int send_presentRequest(char *arg)
594 {
595     Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
596     Z_PresentRequest *req = apdu->u.presentRequest;
597     oident prefsyn;
598     int nos = 1;
599     char *p;
600     char setstring[100];
601
602     if ((p = strchr(arg, '+')))
603     {
604         nos = atoi(p + 1);
605         *p = 0;
606     }
607     if (*arg)
608         setno = atoi(arg);
609
610     if (setnumber >= 0)
611     {
612         sprintf(setstring, "%d", setnumber);
613         req->resultSetId = setstring;
614     }
615     req->resultSetStartPoint = &setno;
616     req->numberOfRecordsRequested = &nos;
617     prefsyn.proto = protocol;
618     prefsyn.class = CLASS_RECSYN;
619     prefsyn.value = recordsyntax;
620     req->preferredRecordSyntax = oid_getoidbyent(&prefsyn);
621     send_apdu(apdu);
622     printf("Sent presentRequest (%d+%d).\n", setno, nos);
623     return 2;
624 }
625
626 static int cmd_show(char *arg)
627 {
628     if (!send_presentRequest(arg))
629         return 0;
630     return 2;
631 }
632
633 int cmd_quit(char *arg)
634 {
635     printf("See you later, alligator.\n");
636     exit(0);
637 }
638
639 int cmd_cancel(char *arg)
640 {
641     Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
642     Z_TriggerResourceControlRequest *req =
643         apdu->u.triggerResourceControlRequest;
644     bool_t false = 0;
645     
646     if (!session)
647     {
648         printf("Session not initialized yet\n");
649         return 0;
650     }
651     if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
652     {
653         printf("Target doesn't support cancel (trigger resource ctrl)\n");
654         return 0;
655     }
656     *req->requestedAction = Z_TriggerResourceCtrl_cancel;
657     req->resultSetWanted = &false;
658
659     send_apdu(apdu);
660     printf("Sent cancel request\n");
661     return 2;
662 }
663
664 int send_scanrequest(char *string, int pp, int num)
665 {
666     Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
667     Z_ScanRequest *req = apdu->u.scanRequest;
668     char *db = database;
669     oident attset;
670
671     req->num_databaseNames = 1;
672     req->databaseNames = &db;
673     attset.proto = protocol;
674     attset.class = CLASS_ATTSET;
675     attset.value = VAL_BIB1;
676     req->attributeSet = oid_getoidbyent(&attset);
677     req->termListAndStartPoint = p_query_scan(out, string);
678     req->numberOfTermsRequested = &num;
679     req->preferredPositionInResponse = &pp;
680     send_apdu(apdu);
681     return 2;
682 }
683
684 void display_term(Z_TermInfo *t)
685 {
686     if (t->term->which == Z_Term_general)
687     {
688         printf("%.*s (%d)\n", t->term->u.general->len, t->term->u.general->buf,
689             t->globalOccurrences ? *t->globalOccurrences : -1);
690         sprintf(last_scan, "%.*s", t->term->u.general->len,
691             t->term->u.general->buf);
692     }
693     else
694         printf("Term type not general.\n");
695 }
696
697 void process_scanResponse(Z_ScanResponse *res)
698 {
699     int i;
700
701     printf("SCAN: %d entries, position=%d\n", *res->numberOfEntriesReturned,
702         *res->positionOfTerm);
703     if (*res->scanStatus != Z_Scan_success)
704         printf("Scan returned code %d\n", *res->scanStatus);
705     if (!res->entries)
706         return;
707     if (res->entries->which == Z_ListEntries_entries)
708     {
709         Z_Entries *ent = res->entries->u.entries;
710
711         for (i = 0; i < ent->num_entries; i++)
712             if (ent->entries[i]->which == Z_Entry_termInfo)
713             {
714                 printf("%c ", i + 1 == *res->positionOfTerm ? '*' : ' ');
715                 display_term(ent->entries[i]->u.termInfo);
716             }
717             else
718                 display_diagrec(ent->entries[i]->u.surrogateDiagnostic);
719     }
720     else
721         display_diagrec(res->entries->u.nonSurrogateDiagnostics->diagRecs[0]);
722 }
723
724 int cmd_scan(char *arg)
725 {
726     if (!session)
727     {
728         printf("Session not initialized yet\n");
729         return 0;
730     }
731     if (!ODR_MASK_GET(session->options, Z_Options_scan))
732     {
733         printf("Target doesn't support scan\n");
734         return 0;
735     }
736     if (*arg)
737     {
738         if (send_scanrequest(arg, 5, 20) < 0)
739             return 0;
740     }
741     else
742         if (send_scanrequest(last_scan, 1, 20) < 0)
743             return 0;
744     return 2;
745 }
746
747 int cmd_format(char *arg)
748 {
749     if (!arg || !*arg)
750     {
751         printf("Usage: format <recordsyntax>\n");
752         return 0;
753     }
754     if (!strcmp(arg, "sutrs"))
755     {
756         printf("Preferred format is SUTRS.\n");
757         recordsyntax = VAL_SUTRS;
758         return 1;
759     }
760     else if (!strcmp(arg, "usmarc"))
761     {
762         printf("Preferred format is USMARC\n");
763         recordsyntax = VAL_USMARC;
764         return 1;
765     }
766     else if (!strcmp(arg, "danmarc"))
767     {
768         printf("Preferred format is DANMARC\n");
769         recordsyntax = VAL_DANMARC;
770         return 1;
771     }
772     else if (!strcmp(arg, "grs1"))
773     {
774         printf("Preferred format is GRS1\n");
775         recordsyntax = VAL_GRS1;
776         return 1;
777     }
778     else
779     {
780         printf("Specify one of {sutrs,usmarc,danmarc,grs1}.\n");
781         return 0;
782     }
783 }
784
785 static void initialize(void)
786 {
787 #ifdef RPN_QUERY
788 #ifndef PREFIX_QUERY
789     FILE *inf;
790 #endif
791 #endif
792
793     if (!(out = odr_createmem(ODR_ENCODE)) ||
794         !(in = odr_createmem(ODR_DECODE)) ||
795         !(print = odr_createmem(ODR_PRINT)))
796     {
797         fprintf(stderr, "failed to allocate ODR streams\n");
798         exit(1);
799     }
800     setvbuf(stdout, 0, _IONBF, 0);
801
802 #ifdef RPN_QUERY
803 #ifndef PREFIX_QUERY
804     bibset = ccl_qual_mk (); 
805     inf = fopen ("default.bib", "r");
806     if (inf)
807     {
808         ccl_qual_file (bibset, inf);
809         fclose (inf);
810     }
811 #endif
812 #endif
813 }
814
815 static int client(void)
816 {
817     static struct {
818         char *cmd;
819         int (*fun)(char *arg);
820         char *ad;
821     } cmd[] = {
822         {"open", cmd_open, "('tcp'|'osi')':'[<TSEL>'/']<HOST>[':'<PORT>]"},
823         {"quit", cmd_quit, ""},
824         {"find", cmd_find, "<CCL-QUERY>"},
825         {"base", cmd_base, "<BASE-NAME>"},
826         {"show", cmd_show, "<REC#>['+'<#RECS>]"},
827         {"scan", cmd_scan, "<TERM>"},
828         {"authentication", cmd_authentication, "<ACCTSTRING>"},
829         {"lslb", cmd_lslb, "<largeSetLowerBound>"},
830         {"ssub", cmd_ssub, "<smallSetUpperBound>"},
831         {"mspn", cmd_mspn, "<mediumSetPresentNumber>"},
832         {"status", cmd_status, ""},
833         {"setnames", cmd_setnames, ""},
834         {"cancel", cmd_cancel, ""},
835         {"format", cmd_format, "<recordsyntax>"},
836         {0,0}
837     };
838     char *netbuffer= 0;
839     int netbufferlen = 0;
840     int i;
841     Z_APDU *apdu;
842
843     while (1)
844     {
845         int res;
846         fd_set input;
847         char line[1024], word[1024], arg[1024];
848
849         FD_ZERO(&input);
850         FD_SET(0, &input);
851         if (conn)
852             FD_SET(cs_fileno(conn), &input);
853         if ((res = select(20, &input, 0, 0, 0)) < 0)
854         {
855             perror("select");
856             exit(1);
857         }
858         if (!res)
859             continue;
860         if (FD_ISSET(0, &input))
861         {
862             /* quick & dirty way to get a command line. */
863             if (!gets(line))
864                 break;
865             if ((res = sscanf(line, "%s %[^;]", word, arg)) <= 0)
866             {
867                 strcpy(word, last_cmd);
868                 *arg = '\0';
869             }
870             else if (res == 1)
871                 *arg = 0;
872             strcpy(last_cmd, word);
873             for (i = 0; cmd[i].cmd; i++)
874                 if (!strncmp(cmd[i].cmd, word, strlen(word)))
875                 {
876                     res = (*cmd[i].fun)(arg);
877                     break;
878                 }
879             if (!cmd[i].cmd) /* dump our help-screen */
880             {
881                 printf("Unknown command: %s.\n", word);
882                 printf("Currently recognized commands:\n");
883                 for (i = 0; cmd[i].cmd; i++)
884                     printf("   %s %s\n", cmd[i].cmd, cmd[i].ad);
885                 res = 1;
886             }
887             if (res < 2)
888                 printf(C_PROMPT);
889         }
890         if (conn && FD_ISSET(cs_fileno(conn), &input))
891         {
892             do
893             {
894                 if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0)
895                 {
896                     perror("cs_get");
897                     exit(1);
898                 }
899                 if (!res)
900                 {
901                     printf("Target closed connection.\n");
902                     exit(1);
903                 }
904                 odr_reset(in); /* release APDU from last round */
905                 odr_setbuf(in, netbuffer, res, 0);
906                 if (!z_APDU(in, &apdu, 0))
907                 {
908                     odr_perror(in, "Decoding incoming APDU");
909                     fprintf(stderr, "Packet dump:\n---------\n");
910                     odr_dumpBER(stderr, netbuffer, res);
911                     fprintf(stderr, "---------\n");
912                     exit(1);
913                 }
914 #if 0
915                 if (!z_APDU(print, &apdu, 0))
916                 {
917                     odr_perror(print, "Failed to print incoming APDU");
918                     odr_reset(print);
919                     continue;
920                 }
921 #endif
922                 switch(apdu->which)
923                 {
924                     case Z_APDU_initResponse:
925                         process_initResponse(apdu->u.initResponse);
926                         break;
927                     case Z_APDU_searchResponse:
928                         process_searchResponse(apdu->u.searchResponse);
929                         break;
930                     case Z_APDU_scanResponse:
931                         process_scanResponse(apdu->u.scanResponse);
932                         break;
933                     case Z_APDU_presentResponse:
934                         printf("Received presentResponse.\n");
935                         setno +=
936                             *apdu->u.presentResponse->numberOfRecordsReturned;
937                         if (apdu->u.presentResponse->records)
938                             display_records(apdu->u.presentResponse->records);
939                         else
940                             printf("No records.\n");
941                         break;
942                     default:
943                         printf("Received unknown APDU type (%d).\n", 
944                             apdu->which);
945                         exit(1);
946                 }
947                 printf("Z> ");
948                 fflush(stdout);
949             }
950             while (cs_more(conn));
951         }
952     }
953     return 0;
954 }
955
956 int main(int argc, char **argv)
957 {
958     initialize();
959     if (argc > 1)
960         cmd_open(argv[1]);
961     else
962         printf(C_PROMPT);
963     return client();
964 }