Comment
[yaz-moved-to-github.git] / client / client.c
index a57f354..a02c99c 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1995-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: client.c,v 1.205 2003-07-23 12:57:22 mike Exp $
+ * $Id: client.c,v 1.215 2003-12-18 17:02:24 mike Exp $
  */
 
 #include <stdio.h>
@@ -60,6 +60,7 @@
 
 static char *codeset = 0;               /* character set for output */
 static int hex_dump = 0;
+static char *dump_file_prefix = 0;
 static ODR out, in, print;              /* encoding and decoding streams */
 #if HAVE_XML2
 static ODR srw_sr_odr_out = 0;
@@ -103,6 +104,8 @@ static char *refid = NULL;
 static char *last_open_command = NULL;
 static int auto_reconnect = 0;
 
+static char cur_host[200];
+
 typedef enum {
     QueryType_Prefix,
     QueryType_CCL,
@@ -114,7 +117,7 @@ typedef enum {
 static QueryType queryType = QueryType_Prefix;
 
 static CCL_bibset bibset;               /* CCL bibset handle */
-static cql_transform_t cqltrans;       /* CQL qualifier-set handle */
+static cql_transform_t cqltrans;       /* CQL context-set handle */
 
 #if HAVE_READLINE_COMPLETION_OVER
 
@@ -174,6 +177,21 @@ static void do_hex_dump(const char* buf, int len)
            printf("\n");
        }
     }
+    if (dump_file_prefix)
+    {
+       static int no = 0;
+       if (++no < 1000 && strlen(dump_file_prefix) < 500)
+       {
+           char fname[1024];
+           FILE *of;
+           sprintf (fname, "%s.%03d.raw", dump_file_prefix, no);
+           of = fopen(fname, "wb");
+           
+           fwrite (buf, 1, len, of);
+           
+           fclose(of);
+       }
+    }
 }
 
 void add_otherInfos(Z_APDU *a) 
@@ -212,13 +230,13 @@ int send_apdu(Z_APDU *a)
     if (ber_file)
         odr_dumpBER(ber_file, buf, len);
     /* printf ("sending APDU of size %d\n", len); */
+    do_hex_dump(buf, len);
     if (cs_put(conn, buf, len) < 0)
     {
         fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
         close_session();
         return 0;
     }
-    do_hex_dump(buf,len);
     odr_reset(out); /* release the APDU structure  */
     return 1;
 }
@@ -309,6 +327,11 @@ static void send_initRequest(const char* type_and_host)
         printf("Sent initrequest.\n");
 }
 
+
+/* These two are used only from process_initResponse() */
+static void render_initUserInfo(Z_OtherInformation *ui1);
+static void render_diag(Z_DiagnosticFormat *diag);
+
 static int process_initResponse(Z_InitResponse *res)
 {
     int ver = 0;
@@ -333,22 +356,24 @@ static int process_initResponse(Z_InitResponse *res)
     if (res->userInformationField)
     {
        Z_External *uif = res->userInformationField;
-        printf("UserInformationfield:\n");
-        if (!z_External(print, (Z_External**)&uif, 0, 0))
-        {
-            odr_perror(print, "Printing userinfo\n");
-            odr_reset(print);
-        }
-        if (uif->which == Z_External_octet)
-        {
-            printf("Guessing visiblestring:\n");
-            printf("'%s'\n", uif->u. octet_aligned->buf);
-        } else if (uif->which == Z_External_single) {
-           /* Peek at any private Init-diagnostic APDUs */
-           Odr_any *sat = uif->u.single_ASN1_type;
-           printf("### NAUGHTY: External is '%s'\n", sat->buf);
+       if (uif->which == Z_External_userInfo1) {
+           render_initUserInfo(uif->u.userInfo1);
+       } else {
+           printf("UserInformationfield:\n");
+           if (!z_External(print, (Z_External**)&uif, 0, 0)) {
+               odr_perror(print, "Printing userinfo\n");
+               odr_reset(print);
+           }
+           if (uif->which == Z_External_octet) {
+               printf("Guessing visiblestring:\n");
+               printf("'%s'\n", uif->u. octet_aligned->buf);
+           } else if (uif->which == Z_External_single) {
+               /* Peek at any private Init-diagnostic APDUs */
+               Odr_any *sat = uif->u.single_ASN1_type;
+               printf("### NAUGHTY: External is '%s'\n", sat->buf);
+           }
+           odr_reset (print);
        }
-        odr_reset (print);
     }
     printf ("Options:");
     if (ODR_MASK_GET(res->options, Z_Options_search))
@@ -404,6 +429,15 @@ static int process_initResponse(Z_InitResponse *res)
             
             yaz_get_response_charneg(session_mem, p, &charset, &lang,
                                      &selected);
+
+           if (outputCharset && negotiationCharset) {
+                   odr_set_charset (out, charset, outputCharset);
+                   odr_set_charset (in, outputCharset, charset);
+           }
+           else {
+                   odr_set_charset (out, 0, 0);
+                   odr_set_charset (in, 0, 0);
+           }
             
             printf("Accepted character set : %s\n", charset);
             printf("Accepted code language : %s\n", lang ? lang : "none");
@@ -414,6 +448,60 @@ static int process_initResponse(Z_InitResponse *res)
     return 0;
 }
 
+
+static void render_initUserInfo(Z_OtherInformation *ui1) {
+    int i;
+    printf("Init response contains %d otherInfo unit%s:\n",
+          ui1->num_elements, ui1->num_elements == 1 ? "" : "s");
+
+    for (i = 0; i < ui1->num_elements; i++) {
+       Z_OtherInformationUnit *unit = ui1->list[i];
+       printf("  %d: otherInfo unit contains ", i+1);
+       if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
+           unit->information.externallyDefinedInfo->which ==
+           Z_External_diag1) {
+           render_diag(unit->information.externallyDefinedInfo->u.diag1);
+       } else {
+           printf("unsupported otherInfo unit type %d\n", unit->which);
+       }
+    }
+}
+
+
+/* ### should this share code with display_diagrecs()? */
+static void render_diag(Z_DiagnosticFormat *diag) {
+    int i;
+
+    printf("%d diagnostic%s:\n", diag->num, diag->num == 1 ? "" : "s");
+    for (i = 0; i < diag->num; i++) {
+       Z_DiagnosticFormat_s *ds = diag->elements[i];
+       printf("    %d: ", i+1);
+       switch (ds->which) {
+       case Z_DiagnosticFormat_s_defaultDiagRec: {
+           Z_DefaultDiagFormat *dd = ds->u.defaultDiagRec;
+           /* ### should check `dd->diagnosticSetId' */
+           printf("code=%d (%s)", *dd->condition,
+                  diagbib1_str(*dd->condition));
+           /* Both types of addinfo are the same, so use type-pun */
+           if (dd->u.v2Addinfo != 0)
+               printf(",\n\taddinfo='%s'", dd->u.v2Addinfo);
+           break;
+       }
+       case Z_DiagnosticFormat_s_explicitDiagnostic:
+           printf("Explicit diagnostic (not supported)");
+           break;
+       default:
+           printf("Unrecognised diagnostic type %d", ds->which);
+           break;
+       }
+
+       if (ds->message != 0)
+           printf(", message='%s'", ds->message);
+       printf("\n");
+    }
+}
+
+
 static int set_base(const char *arg)
 {
     int i;
@@ -543,7 +631,6 @@ int session_connect(const char *arg)
 
 int cmd_open(const char *arg)
 {
-    static char cur_host[200];
     if (arg)
     {
         strncpy (cur_host, arg, sizeof(cur_host)-1);
@@ -1040,7 +1127,7 @@ static int send_deleteResultSetRequest(const char *arg)
 static int send_srw(Z_SRW_PDU *sr)
 {
     const char *charset = negotiationCharset;
-    const char *host_port = 0;
+    const char *host_port = cur_host;
     char *path = 0;
     char ctype[50];
     Z_SOAP_Handler h[2] = {
@@ -1078,7 +1165,7 @@ static int send_srw(Z_SRW_PDU *sr)
             memcpy (h, cp0, cp1 - cp0);
             h[cp1-cp0] = '\0';
             z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
-                              "host", h);
+                              "Host", h);
         }
     }
 
@@ -1110,10 +1197,14 @@ static int send_srw(Z_SRW_PDU *sr)
         char *buf_out;
         int len_out;
         int r;
+       if (apdu_file && !z_GDU(print, &gdu, 0, 0))
+            printf ("Failed to print outgoing APDU\n");
         buf_out = odr_getbuf(out, &len_out, 0);
         
         /* we don't odr_reset(out), since we may need the buffer again */
 
+       do_hex_dump(buf_out, len_out);
+
         r = cs_put(conn, buf_out, len_out);
 
         odr_destroy(o);
@@ -1840,14 +1931,24 @@ static int only_z3950()
     return 0;
 }
 
+static int cmd_update_common(const char *arg, int version);
+
 static int cmd_update(const char *arg)
 {
+    return cmd_update_common(arg, 1);
+}
+
+static int cmd_update0(const char *arg)
+{
+    return cmd_update_common(arg, 0);
+}
+
+static int cmd_update_common(const char *arg, int version)
+{
     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
     Z_External *r;
     int oid[OID_SIZE];
-    Z_IUOriginPartToKeep *toKeep;
-    Z_IUSuppliedRecords *notToKeep;
     oident update_oid;
     char action[20], recid[20], fname[80];
     int action_no;
@@ -1911,7 +2012,10 @@ static int cmd_update(const char *arg)
 
     update_oid.proto = PROTO_Z3950;
     update_oid.oclass = CLASS_EXTSERV;
-    update_oid.value = VAL_DBUPDATE;
+    if (version == 0)
+       update_oid.value = VAL_DBUPDATE0;
+    else
+       update_oid.value = VAL_DBUPDATE;
     oid_ent_to_oid (&update_oid, oid);
     req->packageType = odr_oiddup(out,oid);
     req->packageName = esPackageName;
@@ -1923,41 +2027,90 @@ static int cmd_update(const char *arg)
     r->direct_reference = odr_oiddup(out,oid);
     r->indirect_reference = 0;
     r->descriptor = 0;
-    r->which = Z_External_update;
-    r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
-    r->u.update->which = Z_IUUpdate_esRequest;
-    r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
-        odr_malloc(out, sizeof(*r->u.update->u.esRequest));
-    toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
-        odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
-    toKeep->databaseName = databaseNames[0];
-    toKeep->schema = 0;
-    toKeep->elementSetName = 0;
-    toKeep->actionQualifier = 0;
-    toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
-    *toKeep->action = action_no;
-
-    notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
-        odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
-    notToKeep->num = 1;
-    notToKeep->elements = (Z_IUSuppliedRecords_elem **)
-        odr_malloc(out, sizeof(*notToKeep->elements));
-    notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
-        odr_malloc(out, sizeof(**notToKeep->elements));
-    notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
-    if (*recid)
-    {
-        notToKeep->elements[0]->u.opaque = (Odr_oct *)
-            odr_malloc (out, sizeof(Odr_oct));
-        notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
-        notToKeep->elements[0]->u.opaque->size = strlen(recid);
-        notToKeep->elements[0]->u.opaque->len = strlen(recid);
+    if (version == 0)
+    {
+       Z_IU0OriginPartToKeep *toKeep;
+       Z_IU0SuppliedRecords *notToKeep;
+
+       r->which = Z_External_update0;
+       r->u.update0 = (Z_IU0Update *) odr_malloc(out, sizeof(*r->u.update0));
+       r->u.update0->which = Z_IUUpdate_esRequest;
+       r->u.update0->u.esRequest = (Z_IU0UpdateEsRequest *)
+           odr_malloc(out, sizeof(*r->u.update0->u.esRequest));
+       toKeep = r->u.update0->u.esRequest->toKeep = (Z_IU0OriginPartToKeep *)
+           odr_malloc(out, sizeof(*r->u.update0->u.esRequest->toKeep));
+       
+       toKeep->databaseName = databaseNames[0];
+       toKeep->schema = 0;
+       toKeep->elementSetName = 0;
+
+       toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
+       *toKeep->action = action_no;
+       
+       notToKeep = r->u.update0->u.esRequest->notToKeep = (Z_IU0SuppliedRecords *)
+           odr_malloc(out, sizeof(*r->u.update0->u.esRequest->notToKeep));
+       notToKeep->num = 1;
+       notToKeep->elements = (Z_IU0SuppliedRecords_elem **)
+           odr_malloc(out, sizeof(*notToKeep->elements));
+       notToKeep->elements[0] = (Z_IU0SuppliedRecords_elem *)
+           odr_malloc(out, sizeof(**notToKeep->elements));
+       notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
+       if (*recid)
+       {
+           notToKeep->elements[0]->u.opaque = (Odr_oct *)
+               odr_malloc (out, sizeof(Odr_oct));
+           notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
+           notToKeep->elements[0]->u.opaque->size = strlen(recid);
+           notToKeep->elements[0]->u.opaque->len = strlen(recid);
+       }
+       else
+           notToKeep->elements[0]->u.opaque = 0;
+       notToKeep->elements[0]->supplementalId = 0;
+       notToKeep->elements[0]->correlationInfo = 0;
+       notToKeep->elements[0]->record = record_this;
     }
     else
-        notToKeep->elements[0]->u.opaque = 0;
-    notToKeep->elements[0]->supplementalId = 0;
-    notToKeep->elements[0]->correlationInfo = 0;
-    notToKeep->elements[0]->record = record_this;
+    {
+       Z_IUOriginPartToKeep *toKeep;
+       Z_IUSuppliedRecords *notToKeep;
+
+       r->which = Z_External_update;
+       r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
+       r->u.update->which = Z_IUUpdate_esRequest;
+       r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
+           odr_malloc(out, sizeof(*r->u.update->u.esRequest));
+       toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
+           odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
+       
+       toKeep->databaseName = databaseNames[0];
+       toKeep->schema = 0;
+       toKeep->elementSetName = 0;
+       toKeep->actionQualifier = 0;
+       toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
+       *toKeep->action = action_no;
+
+       notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
+           odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
+       notToKeep->num = 1;
+       notToKeep->elements = (Z_IUSuppliedRecords_elem **)
+           odr_malloc(out, sizeof(*notToKeep->elements));
+       notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
+           odr_malloc(out, sizeof(**notToKeep->elements));
+       notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
+       if (*recid)
+       {
+           notToKeep->elements[0]->u.opaque = (Odr_oct *)
+               odr_malloc (out, sizeof(Odr_oct));
+           notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
+           notToKeep->elements[0]->u.opaque->size = strlen(recid);
+           notToKeep->elements[0]->u.opaque->len = strlen(recid);
+       }
+       else
+           notToKeep->elements[0]->u.opaque = 0;
+       notToKeep->elements[0]->supplementalId = 0;
+       notToKeep->elements[0]->correlationInfo = 0;
+       notToKeep->elements[0]->record = record_this;
+    }
     
     send_apdu(apdu);
 
@@ -2421,7 +2574,9 @@ int send_sortrequest(const char *arg, int newset)
 
 void display_term(Z_TermInfo *t)
 {
-    if (t->term->which == Z_Term_general)
+    if (t->displayTerm)
+        printf("%s", t->displayTerm);
+    else if (t->term->which == Z_Term_general)
     {
         printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
         sprintf(last_scan_line, "%.*s", t->term->u.general->len,
@@ -2762,16 +2917,7 @@ int cmd_charset(const char* arg)
         else
             printf ("Output charset conversion disabled\n");
     } 
-    if (outputCharset && negotiationCharset)
-    {
-        odr_set_charset (out, negotiationCharset, outputCharset);
-        odr_set_charset (in, outputCharset, negotiationCharset);
-    }
-    else
-    {
-        odr_set_charset (out, 0, 0);
-        odr_set_charset (in, 0, 0);
-    }
+
     return 1;
 }
 
@@ -3192,17 +3338,20 @@ static void http_response(Z_HTTP_Response *hres)
         }
         close_session();
     }
-    if (!strcmp(hres->version, "1.0"))
-    {
-        /* HTTP 1.0: only if Keep-Alive we stay alive.. */
-        if (!connection_head || strcmp(connection_head, "Keep-Alive"))
-            close_session();
-    }
-    else 
+    else
     {
-        /* HTTP 1.1: only if no close we stay alive .. */
-        if (connection_head && !strcmp(connection_head, "close"))
-            close_session();
+       if (!strcmp(hres->version, "1.0"))
+       {
+           /* HTTP 1.0: only if Keep-Alive we stay alive.. */
+           if (!connection_head || strcmp(connection_head, "Keep-Alive"))
+               close_session();
+       }
+       else 
+       {
+           /* HTTP 1.1: only if no close we stay alive .. */
+           if (connection_head && !strcmp(connection_head, "close"))
+               close_session();
+       }
     }
 }
 #endif
@@ -3231,6 +3380,8 @@ void wait_and_handle_response()
                 
                 buf_out = odr_getbuf(out, &len_out, 0);
                 
+               do_hex_dump(buf_out, len_out);
+
                 cs_put(conn, buf_out, len_out);
                 
                 odr_reset(out);
@@ -3586,6 +3737,7 @@ static struct {
     {"refid", cmd_refid, "<id>",NULL,0,NULL},
     {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
     {"update", cmd_update, "<action> <recid> [<file>]",NULL,0,NULL},
+    {"update0", cmd_update0, "<action> <recid> [<file>]",NULL,0,NULL},
     {"packagename", cmd_packagename, "<packagename>",NULL,0,NULL},
     {"proxy", cmd_proxy, "[('tcp'|'ssl')]<host>[':'<port>]",NULL,0,NULL},
     {"charset", cmd_charset, "<nego_charset> <output_charset>",NULL,0,NULL},
@@ -3916,7 +4068,7 @@ int main(int argc, char **argv)
     if (codeset)
        outputCharset = xstrdup(codeset);
 
-    while ((ret = options("k:c:q:a:b:m:v:p:u:t:Vx", argv, argc, &arg)) != -2)
+    while ((ret = options("k:c:q:a:b:m:v:p:u:t:Vxd:", argv, argc, &arg)) != -2)
     {
         switch (ret)
         {
@@ -3928,6 +4080,9 @@ int main(int argc, char **argv)
                 strcat (open_command, arg);
             }
             break;
+       case 'd':
+           dump_file_prefix = arg;
+           break;
         case 'k':
             kilobytes = atoi(arg);
             break;
@@ -3985,7 +4140,7 @@ int main(int argc, char **argv)
             fprintf (stderr, "Usage: %s [-m <marclog>] [ -a <apdulog>] "
                      "[-b berdump] [-c cclfields] \n"
                     "[-q cqlfields] [-p <proxy-addr>] [-u <auth>] "
-                     "[-k size] [-V] [<server-addr>]\n",
+                     "[-k size] [-d dump] [-V] [<server-addr>]\n",
                      prog);
             exit (1);
         }