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