bb6265592cbb99de42597bc7abfa266e110b3ef9
[yaz-moved-to-github.git] / util / yaz-illclient.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: yaz-illclient.c,v 1.8 2007-06-08 10:01:07 heikki Exp $
6  */
7
8 /* WARNING - This is work in progress - not at all ready */
9
10 /** \file yaz-illclient.c
11  *  \brief client for ILL requests (ISO 10161-1)
12  *
13  *  This is a test client for handling ISO 10161-1 ILL requests.
14  *  Those are not directly Z39.50, but the protocol is quite similar
15  *  and yaz already provides the APDUS for it.
16  *
17  *  This is not an interactive client like yaz-client, but driven by command-
18  *  line arguments. Its output is a return code, and possibly some text on 
19  *  stdout.
20  *
21  *  Exit codes  (note, the program exits as soon as it finds a good reason)
22  *     0   ok
23  *     1   errors in arguments
24  *     2   Internal errors in creating objects (comstack, odr...)
25  *         mostly programming errors.
26  *     3   could not connect
27  *     4   could not send request
28  *     5   No reponse received
29  *     6   Error decoding response packet
30  *     7   Server returned an error (see log or stdout)
31  *
32  *
33  *
34  *
35  */
36
37 #include <stdlib.h>
38 #include <stdio.h>
39
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #if HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46 #if HAVE_SYS_TIME_H
47 #include <sys/time.h>
48 #endif
49
50
51 #include <yaz/yaz-util.h>
52 #include <yaz/proto.h>
53 #include <yaz/comstack.h>
54 #include <yaz/tcpip.h>
55 #include <yaz/unix.h>
56 #include <yaz/odr.h>
57 #include <yaz/log.h>
58 #include <yaz/ill.h>
59 #include <yaz/oclc-ill-req-ext.h>
60
61
62 /* A structure for holding name-value pairs in a linked list */
63 struct nameval {
64     char *name;
65     char *val;
66     struct nameval *next;
67 };
68
69 /* A structure for storing all the arguments */
70 struct prog_args {
71     char *host;
72     char *auth_userid;
73     char *auth_passwd;
74     char *oclc_recno; /* record number in oclc-mode */
75     int oclc_auth;  /* 1=use oclc-type auth */
76     struct nameval* namevals; /* circular list, points to last */
77 } ;
78
79
80
81 /* Call-back to be called for every field in the ill-request */
82 /* It can set values to any field, perhaps from the prog_args */
83 const char *get_ill_element(void *clientData, const char *element) {
84     struct prog_args *args = (struct prog_args *) clientData;
85     struct nameval *nv=args->namevals;
86     char *ret=0;
87     if (!nv)
88         return "";
89     do  {
90         nv=nv->next;
91         /* printf("comparing '%s' with '%s' \n",element, nv->name ); */
92         if ( strcmp(element, nv->name) == 0 )
93             ret = nv->val;
94     } while ( ( !ret) && ( nv != args->namevals) );
95     yaz_log(YLOG_DEBUG,"get_ill_element:'%s'->'%s'", element, ret );
96     return ret;
97 }
98
99
100 /* * * * * * * * * * * * * * * * * */
101
102 /** \brief parse a parameter string */
103 /* string is like 'name=value' */
104 struct nameval *parse_nameval( char *arg ) {
105     struct nameval *nv = (struct nameval *) xmalloc(sizeof(*nv));
106     char *p=arg;
107     int len;
108     if (!p || !*p) 
109         return 0; /* yeah, leaks a bit of memory. so what */
110     while ( *p && ( *p != '=' ) ) 
111         p++;
112     len = p - arg;
113     if (!len)
114         return 0;
115     nv->name = (char *) xmalloc(len+1);
116     strncpy(nv->name, arg, len);
117     nv->name[len]='\0';
118     if (*p == '=' )
119         p++; /* skip the '=' */
120     else
121         return 0; /* oops, no '=' */
122     if (!*p)
123         return 0; /* no value */
124     nv->val=xstrdup(p);
125     nv->next=0;
126     yaz_log(YLOG_DEBUG,"parse_nameval: n='%s' v='%s'", nv->name, nv->val );
127     return nv;
128 }
129
130 /** \brief append nv to the list of namevals */
131 void append_nameval (struct prog_args *args, struct nameval *nv) {
132     if (!nv)
133         return;
134     if (args->namevals) {
135         nv->next=args->namevals->next; /* first */
136         args->namevals->next=nv; 
137         args->namevals=nv;
138     } else {
139         nv->next=nv;
140         args->namevals=nv;
141     }
142 } /* append_nameval */
143
144 /** \brief parse a parameter file */
145 void parse_paramfile(char *arg, struct prog_args *args) {
146     FILE *f=fopen(arg,"r");
147 #define BUFSIZE 4096    
148     char buf[BUFSIZE];
149     int len;
150     struct nameval *nv;
151     if (!f) {
152         yaz_log(YLOG_FATAL,"Could not open param file '%s' ", arg);
153         printf("Could not open file '%s' \n",arg);
154         exit(1);
155     }
156     yaz_log(YLOG_DEBUG,"Opened input file '%s' ",arg );
157     while (fgets(buf,BUFSIZE,f)) {
158         if (buf[0] != '#' ) {
159             len=strlen(buf)-1;
160             if (buf[len] == '\n')
161                 buf[len] = '\0' ;
162             nv=parse_nameval(buf);
163             append_nameval(args, nv);
164         } /* not a comment */
165     }
166     (void) fclose(f);
167
168     if (0) {
169         nv=args->namevals;
170         printf("nv chain: ================ \n");
171         printf("(last:) %p: '%s' = '%s' (%p) \n",nv, nv->name, nv->val, nv->next );
172         do {
173             nv=nv->next;
174             printf("%p: '%s' = '%s' (%p)\n",nv, nv->name, nv->val, nv->next );
175         } while (nv != args->namevals );
176         exit(1);
177     }
178
179 } /* parse_paramfile */
180
181
182 /** \brief  Parse program arguments */
183 void parseargs( int argc, char * argv[],  struct prog_args *args) {
184     int ret;
185     char *arg;
186     char *prog=*argv;
187     char *version="$Id: yaz-illclient.c,v 1.8 2007-06-08 10:01:07 heikki Exp $"; /* from cvs */
188     struct nameval *nv;
189
190     /* default values */
191     args->host = 0; /* not known (yet) */
192     args->namevals=0; /* none set up */
193     args->oclc_auth=0;
194     args->oclc_recno=0;
195     args->auth_userid = 0;
196     args->auth_passwd = 0;
197 #if 0    
198     /* Example 3 - directly from OCLC, supposed to work on their test server*/
199     args->auth_userid = "100-310-658" ; /* FIXME - get from cmd line */
200     args->auth_passwd = "apii2test" ;   /* FIXME - get from cmd line */
201 #endif
202
203     while ((ret = options("Vov:p:u:D:f:r:l:", argv, argc, &arg)) != -2)
204     {
205         yaz_log(YLOG_DEBUG,"parsing option '%c' '%s'",ret, arg);
206         switch (ret)
207         {
208         case 0:
209             if (!args->host)
210             {
211                 args->host = xstrdup (arg);
212             }
213             else
214             {
215                 fprintf(stderr, "%s: Specify at most one server address\n",
216                         prog);
217                 exit(1);
218             }
219             break;
220         case 'v':
221             yaz_log_init(yaz_log_mask_str(arg), "", 0);
222             break;
223         case 'l':
224             yaz_log_init_file(arg);
225             break;
226         case 'V':
227             printf("%s %s",prog, version );
228             break;
229         case 'D':
230             nv=parse_nameval(arg);
231             append_nameval(args,nv);
232             break;
233         case 'f':
234             parse_paramfile(arg,args);
235             break;
236         case 'o':
237             args->oclc_auth=1;
238             break;
239         case 'u':
240             args->auth_userid=xstrdup(arg);
241             break;
242         case 'p':
243             args->auth_passwd=xstrdup(arg);
244             break;
245         case 'r':
246             args->oclc_recno=xstrdup(arg);
247             break;
248         default:
249             fprintf (stderr, "Usage: %s "
250                      " [-f filename]"
251                      " [-v loglevel...]"
252                      " [-D name=value ]"
253                      " [-o -u user -p passwd]"
254                      " [-V]"
255                      " <server-addr>\n",
256                      prog);
257             exit (1);
258         }
259     }
260 } /* parseargs */
261
262 /* * * * * * * * * * * */
263 /** \brief  Validate the arguments make sense */
264 void validateargs( struct prog_args *args) {
265     if (!args->host) {
266         fprintf(stderr, "Specify a connection address, "
267                         "as in 'bagel.indexdata.dk:210' \n");
268         exit(1);
269     }
270     if (args->oclc_auth && ((!args->auth_userid) || (!args->auth_passwd))){
271         fprintf(stderr, "-o option requires -u <user> and -p <pwd>\n");
272         exit(1);
273     }
274 } /* validateargs */
275
276
277 /* * * * * * * * * * * * * * * */
278 /** \brief  Connect to the target */
279 COMSTACK connect_to( char *hostaddr ){
280     COMSTACK stack;
281     void *server_address_ip;
282     int status;
283
284     yaz_log(YLOG_DEBUG,"Connecting to '%s'", hostaddr);
285     stack = cs_create_host(hostaddr, 1, &server_address_ip );
286     if (!stack) {
287         yaz_log(YLOG_FATAL,"Error in creating the comstack '%s' ",
288                  hostaddr );
289         exit(2);
290     }
291     
292     yaz_log(YLOG_DEBUG,"Created stack ok ");
293
294     status = cs_connect(stack, server_address_ip);
295     if (status != 0) {
296         yaz_log(YLOG_FATAL|YLOG_ERRNO,"Can not connect '%s' ",
297                  hostaddr );
298         exit(3);
299     }
300     yaz_log(YLOG_DEBUG,"Connected OK to '%s'", hostaddr);
301     return stack;
302 }
303
304
305 /* * * * * * * * * * * * * * * */
306 /* Makes a Z39.50-like prompt package with username and password */
307 Z_PromptObject1 *makeprompt(struct prog_args *args, ODR odr) {
308     Z_PromptObject1 *p = (Z_PromptObject1 *) odr_malloc(odr, sizeof(*p) );
309     Z_ResponseUnit1 *ru = (Z_ResponseUnit1 *) odr_malloc(odr, sizeof(*ru) );
310     
311     p->which=Z_PromptObject1_response;
312     p->u.response = (Z_Response1*) odr_malloc(odr, sizeof(*(p->u.response)) );
313     p->u.response->num=2;
314     p->u.response->elements= (Z_ResponseUnit1 **) odr_malloc(odr, 
315              p->u.response->num*sizeof(*(p->u.response->elements)) );
316     /* user id, aka "oclc authorization number" */
317     p->u.response->elements[0] = ru;
318     ru->promptId = (Z_PromptId *) odr_malloc(odr, sizeof(*(ru->promptId) ));
319     ru->promptId->which = Z_PromptId_enumeratedPrompt;
320     ru->promptId->u.enumeratedPrompt = (Z_PromptIdEnumeratedPrompt *)
321         odr_malloc(odr, sizeof(*(ru->promptId->u.enumeratedPrompt) ));
322     ru->promptId->u.enumeratedPrompt->type = 
323          odr_intdup(odr,Z_PromptIdEnumeratedPrompt_userId);
324     ru->promptId->u.enumeratedPrompt->suggestedString = 0 ;
325     ru->which = Z_ResponseUnit1_string ;
326     ru->u.string = odr_strdup(odr, args->auth_userid);
327     /* password */
328     ru = (Z_ResponseUnit1 *) odr_malloc(odr, sizeof(*ru) );
329     p->u.response->elements[1] = ru;
330     ru->promptId = (Z_PromptId *) odr_malloc(odr, sizeof(*(ru->promptId) ));
331     ru->promptId->which = Z_PromptId_enumeratedPrompt;
332     ru->promptId->u.enumeratedPrompt =  (Z_PromptIdEnumeratedPrompt *)
333         odr_malloc(odr, sizeof(*(ru->promptId->u.enumeratedPrompt) ));
334     ru->promptId->u.enumeratedPrompt->type = 
335          odr_intdup(odr,Z_PromptIdEnumeratedPrompt_password);
336     ru->promptId->u.enumeratedPrompt->suggestedString = 0 ;
337     ru->which = Z_ResponseUnit1_string ;
338     ru->u.string = odr_strdup(odr, args->auth_passwd);
339     return p;
340 } /* makeprompt */
341
342 ILL_Extension *makepromptextension(struct prog_args *args, ODR odr) {
343     ODR odr_ext = odr_createmem(ODR_ENCODE);
344     ODR odr_prt = odr_createmem(ODR_PRINT);
345     ILL_Extension *e = (ILL_Extension *) odr_malloc(odr, sizeof(*e));
346     Z_PromptObject1 *p = makeprompt(args,odr_ext);
347     char * buf;
348     int siz;
349     Z_External *ext = (Z_External *) odr_malloc(odr, sizeof(*ext));
350     ext->direct_reference = odr_getoidbystr(odr,"1.2.840.10003.8.1");
351     ext->indirect_reference=0;
352     ext->descriptor=0;
353     ext->which=Z_External_single;
354     if ( ! z_PromptObject1(odr_ext, &p, 0,0 ) ) {
355         yaz_log(YLOG_FATAL,"Encoding of z_PromptObject1 failed ");
356         exit (6);
357     }
358     
359     printf ("Prompt: \n"); /*!*/
360     z_PromptObject1(odr_prt, &p, 0,0 ); /*!*/
361
362     buf= odr_getbuf(odr_ext,&siz,0);
363     ext->u.single_ASN1_type=(Odr_any *) 
364         odr_malloc(odr,sizeof(*ext->u.single_ASN1_type));
365     ext->u.single_ASN1_type->buf= (unsigned char *) odr_malloc(odr, siz);
366     memcpy(ext->u.single_ASN1_type->buf,buf, siz );
367     ext->u.single_ASN1_type->len = ext->u.single_ASN1_type->size = siz;
368     odr_reset(odr_ext);
369     odr_reset(odr_prt); /*!*/
370
371     e->identifier = odr_intdup(odr,1);
372     e->critical = odr_intdup(odr,0);
373     e->item = (Odr_any *) odr_malloc(odr,sizeof(*e->item));
374     if ( ! z_External(odr_ext, &ext,0,0) ) {
375         yaz_log(YLOG_FATAL,"Encoding of z_External failed ");
376         exit (6);
377     }
378     printf("External: \n");
379     z_External(odr_prt, &ext,0,0);  /*!*/
380     buf= odr_getbuf(odr_ext,&siz,0); 
381     e->item->buf= (unsigned char *) odr_malloc(odr, siz);
382     memcpy(e->item->buf,buf, siz );
383     e->item->len = e->item->size = siz;
384
385     odr_destroy(odr_prt);
386     odr_destroy(odr_ext);
387     return e;
388 } /* makepromptextension */
389
390 ILL_Extension *makeoclcextension(struct prog_args *args, ODR odr) {
391     /* The oclc extension is required, but only contains optional */
392     /* fields. Here we just null them all out */
393     ODR odr_ext = odr_createmem(ODR_ENCODE);
394     ODR odr_prt = odr_createmem(ODR_PRINT);
395     ILL_Extension *e = (ILL_Extension *) odr_malloc(odr, sizeof(*e));
396     ILL_OCLCILLRequestExtension *oc = (ILL_OCLCILLRequestExtension *)
397         odr_malloc(odr_ext, sizeof(*oc));
398     char * buf;
399     int siz;
400     Z_External *ext = (Z_External *) odr_malloc(odr, sizeof(*ext));
401     oc->clientDepartment = 0;
402     oc->paymentMethod = 0;
403     oc->uniformTitle = 0;
404     oc->dissertation = 0;
405     oc->issueNumber = 0;
406     oc->volume = 0;
407     oc->affiliations = 0;
408     oc->source = 0;
409     ext->direct_reference = odr_getoidbystr(odr,"1.0.10161.13.2");
410     ext->indirect_reference=0;
411     ext->descriptor=0;
412     ext->which=Z_External_single;
413     if ( ! ill_OCLCILLRequestExtension(odr_ext, &oc, 0,0 ) ) {
414         yaz_log(YLOG_FATAL,"Encoding of ill_OCLCILLRequestExtension failed ");
415         exit (6);
416     }
417     
418     printf ("OCLC: \n"); /*!*/
419     ill_OCLCILLRequestExtension(odr_prt, &oc, 0,0 ); /*!*/
420
421     buf= odr_getbuf(odr_ext,&siz,0);
422     ext->u.single_ASN1_type = (Odr_any*)
423         odr_malloc(odr,sizeof(*ext->u.single_ASN1_type));
424     ext->u.single_ASN1_type->buf = (unsigned char *) odr_malloc(odr, siz);
425     memcpy(ext->u.single_ASN1_type->buf,buf, siz );
426     ext->u.single_ASN1_type->len = ext->u.single_ASN1_type->size = siz;
427     odr_reset(odr_ext);
428     odr_reset(odr_prt); /*!*/
429
430     e->identifier = odr_intdup(odr,1);
431     e->critical = odr_intdup(odr,0);
432     e->item = (Odr_any *) odr_malloc(odr,sizeof(*e->item));
433     if ( ! z_External(odr_ext, &ext,0,0) ) {
434         yaz_log(YLOG_FATAL,"Encoding of z_External failed ");
435         exit (6);
436     }
437     printf("External: \n");
438     z_External(odr_prt, &ext,0,0);  /*!*/
439     buf= odr_getbuf(odr_ext,&siz,0); 
440     e->item->buf= (unsigned char *) odr_malloc(odr, siz);
441     memcpy(e->item->buf, buf, siz);
442     e->item->len = e->item->size = siz;
443
444     odr_destroy(odr_prt);
445     odr_destroy(odr_ext);
446     return e;
447
448 } /* makeoclcextension */
449
450 ILL_APDU *createrequest( struct prog_args *args, ODR odr) {
451     struct ill_get_ctl ctl;
452     ILL_APDU *apdu;
453     ILL_Request *req;
454
455     ctl.odr = odr;
456     ctl.clientData = args;
457     ctl.f = get_ill_element;
458     apdu = (ILL_APDU *) odr_malloc( odr, sizeof(*apdu) );
459     apdu->which=ILL_APDU_ILL_Request;
460     req = ill_get_ILLRequest(&ctl, "ill", 0);
461     apdu->u.illRequest=req;
462     if (args->oclc_auth) {
463         req->num_iLL_request_extensions=2;
464         req->iLL_request_extensions=
465             odr_malloc(odr, req->num_iLL_request_extensions*
466                             sizeof(*req->iLL_request_extensions));
467         req->iLL_request_extensions[0]=makepromptextension(args,odr);
468         req->iLL_request_extensions[1]=makeoclcextension(args,odr);
469     }
470     if (!req) {
471         yaz_log(YLOG_FATAL,"Could not create ill request");
472         exit(2);
473     }
474     return apdu;
475 } /* createrequest */
476
477
478 /* * * * * * * * * * * * * * * */
479 /** \brief Send the request */
480 void sendrequest(ILL_APDU *apdu, ODR odr, COMSTACK stack ) {
481     char *buf_out;
482     int len_out;
483     int res;
484     if (!ill_APDU  (odr, &apdu, 0, 0)) { 
485         yaz_log(YLOG_FATAL,"ill_Apdu failed");
486         exit(2);
487     }
488     buf_out = odr_getbuf(odr, &len_out, 0);
489     if (0) {
490         yaz_log(YLOG_DEBUG,"Request PDU Dump");
491         odr_dumpBER(yaz_log_file(), buf_out, len_out);
492     }
493     if (!buf_out) {
494         yaz_log(YLOG_FATAL,"Encoding failed. Len=%d", len_out);
495         odr_perror(odr, "encoding failed");
496         exit(2);
497     }
498     yaz_log(YLOG_DEBUG,"About to send the request. Len=%d", len_out);
499     res = cs_put(stack, buf_out, len_out);
500     if ( res<0 ) {
501         yaz_log(YLOG_FATAL,"Could not send packet. code %d",res );
502         exit (4);
503     }
504     if (1) {
505         FILE *F = fopen("req.apdu","w");
506         fwrite ( buf_out, 1, len_out, F);
507         fclose(F);
508     }
509     
510 } /* sendrequest */
511
512 /* * * * * * * * * * * * * * * */
513 /** \brief  Get a response */
514 ILL_APDU *getresponse( COMSTACK stack, ODR in_odr ){
515     ILL_APDU *resp;
516     int res;
517     char *buf_in=0;
518     int len_in=0;
519     yaz_log(YLOG_DEBUG,"About to wait for a response");
520     res = cs_get(stack, &buf_in, &len_in);
521     yaz_log(YLOG_DEBUG,"Got a response of %d bytes at %p. res=%d", len_in,buf_in, res);
522     if (res<0) {
523         yaz_log(YLOG_FATAL,"Could not receive packet. code %d",res );
524         yaz_log(YLOG_DEBUG,"%02x %02x %02x %02x %02x %02x %02x %02x ...", 
525                 buf_in[0], buf_in[1], buf_in[2], buf_in[3],
526                 buf_in[4], buf_in[5], buf_in[6], buf_in[7]  );
527         yaz_log(YLOG_DEBUG,"PDU Dump:");
528         odr_dumpBER(yaz_log_file(), buf_in, len_in);
529         exit (5);
530     }
531     odr_setbuf(in_odr, buf_in, res, 0);
532     if (!ill_APDU (in_odr, &resp, 0, 0))
533     {
534         int x;
535         int err = odr_geterrorx(in_odr, &x);
536         char msg[60];
537         const char *element = odr_getelement(in_odr);
538         sprintf(msg, "ODR code %d:%d element=%-20s",
539                 err, x, element ? element : "<unknown>");
540         yaz_log(YLOG_FATAL,"Error decoding incoming packet: %s",msg);
541         yaz_log(YLOG_DEBUG,"%02x %02x %02x %02x %02x %02x %02x %02x ...", 
542                 buf_in[0], buf_in[1], buf_in[2], buf_in[3],
543                 buf_in[4], buf_in[5], buf_in[6], buf_in[7]  );
544         yaz_log(YLOG_DEBUG,"PDU Dump:");
545         odr_dumpBER(yaz_log_file(), buf_in, len_in);
546         yaz_log(YLOG_FATAL,"Error decoding incoming packet: %s",msg);
547         exit(6);
548     }
549     return resp;
550 } /* getresponse */
551
552
553 /** \brief Dump a apdu */
554 void dumpapdu( ILL_APDU *apdu) {
555     ODR print_odr = odr_createmem(ODR_PRINT);
556     ill_APDU (print_odr, &apdu, 0, 0);
557     odr_destroy(print_odr);
558 } /* dumpapdu */
559
560 /** \brief  Check apdu type and extract the status_or_error */
561 ILL_Status_Or_Error_Report *getstaterr( ILL_APDU *resp, ODR in_odr ) {
562     if (resp->which != ILL_APDU_Status_Or_Error_Report ) {
563         const char *element = odr_getelement(in_odr);
564         if (!element) 
565             element="unknown";
566         printf("Server returned wrong packet type: %d\n", resp->which);
567         yaz_log(YLOG_FATAL,"Server returned a (%d) and "
568                  "not a 'Status_Or_Error_Report' (%d) ",
569                  resp->which, ILL_APDU_Status_Or_Error_Report);
570         exit(6);
571     }
572     return resp->u.Status_Or_Error_Report;
573 } /* getstaterr */
574
575 /** \brief  Return a printable string from an ILL_String */
576 char *getillstring( ILL_String *s) {
577     if (s->which == ILL_String_GeneralString ) 
578         return s->u.GeneralString;
579     else if (s->which == ILL_String_EDIFACTString ) 
580         return s->u.EDIFACTString;
581     else {
582         yaz_log(YLOG_FATAL,"Invalid ILL_String ");
583         exit (6);
584     }
585 } /* getillstring */
586
587 /** \brief Check if the status was an error packet */
588 /* The presence of an error_report indicates it was an error */
589 /* Then the problem is to find the right message. We dig around */
590 /* until we find the first message, print that, and exit the program */
591 void checkerr( ILL_Status_Or_Error_Report *staterr ) {
592     yaz_log(YLOG_DEBUG, "err= %p ",staterr->error_report );
593     if (staterr->error_report) {
594         ILL_Error_Report *err= staterr->error_report;
595         if ( err->user_error_report) {
596             ILL_User_Error_Report *uerr= err->user_error_report;
597             switch( uerr->which ) {
598                 case ILL_User_Error_Report_already_forwarded:
599                     printf("Already forwarded: \n");
600                     break;
601                 case ILL_User_Error_Report_intermediary_problem:
602                     printf("Intermediary problem: %d\n", 
603                         *uerr->u.intermediary_problem);
604                     break;
605                 case ILL_User_Error_Report_security_problem:
606                     printf("Security problem: %s\n", 
607                         getillstring(uerr->u.security_problem));
608                     break;
609                 case ILL_User_Error_Report_unable_to_perform:
610                     printf("Unable to perform: %d\n", 
611                           *uerr->u.unable_to_perform);
612                     break;
613                 default:
614                     printf("Unknown problem");
615             }
616             exit(7);
617         }
618         if ( err->provider_error_report) {
619             ILL_Provider_Error_Report *perr= err->provider_error_report;
620             switch( perr->which ) {
621                 case ILL_Provider_Error_Report_general_problem:
622                     printf("General Problem: %d:", 
623                           *perr->u.general_problem);
624                     break;
625                 case ILL_Provider_Error_Report_transaction_id_problem:
626                     printf("Transaction Id Problem: %d:", 
627                           *perr->u.general_problem);
628                     break;
629                 case ILL_Provider_Error_Report_state_transition_prohibited:
630                     printf("State Transition prohibited:");
631                     break;
632             }
633             /*exit(7);*/
634         } 
635         /* fallbacks */
636         if ( staterr->note ) 
637             printf("%s", getillstring(staterr->note));
638         else 
639             printf("Unknown error type");
640         printf("\n");
641         exit(7);
642     }
643 } /* checkerr */
644
645
646
647 /* * * * * * * * * * * * * * * */
648
649 /** \brief Main program 
650  *
651  * Parse arguments
652  * Validate arguments
653  * Establish connection
654  * Build a request
655  * Send a request
656  * Get a reply
657  * Parse reply
658  * Produce output
659  */
660
661 int main (int argc, char * argv[]) {
662     struct prog_args args;
663     COMSTACK stack;
664     ODR out_odr = odr_createmem(ODR_ENCODE);
665     ODR in_odr = odr_createmem(ODR_DECODE);
666     ILL_APDU *apdu;
667     ILL_APDU *resp;
668     ILL_Status_Or_Error_Report *staterr;
669
670     parseargs( argc, argv,  &args);
671     validateargs(&args);
672     stack = connect_to(args.host);
673     apdu = createrequest(&args, out_odr);
674     if (1) 
675         dumpapdu(apdu);
676     sendrequest(apdu, out_odr, stack ); 
677     resp = getresponse(stack, in_odr );
678     if (1) 
679         dumpapdu(resp);
680     staterr=getstaterr(resp, in_odr);
681     checkerr(staterr);
682
683
684     printf ("Ok\n"); /* while debugging */
685     exit (0);
686 }
687
688 /*
689  * Local variables:
690  * c-basic-offset: 4
691  * indent-tabs-mode: nil
692  * End:
693  * vim: shiftwidth=4 tabstop=8 expandtab
694  */
695