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