Don't set syntax to none if bad syntax is supplied
[yaz-moved-to-github.git] / client / client.c
index 98b8bd5..bb3b465 100644 (file)
@@ -1,13 +1,28 @@
 /* 
- * Copyright (c) 1995-2002, Index Data
+ * Copyright (c) 1995-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: client.c,v 1.169 2002-09-17 11:07:30 adam Exp $
+ * $Id: client.c,v 1.179 2003-01-27 21:31:35 adam Exp $
  */
 
 #include <stdio.h>
 #include <stdlib.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
 #include <time.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#define S_ISREG(x) (x & _S_IFREG)
+#define S_ISDIR(x) (x & _S_IFDIR)
+#endif
 
 #include <yaz/yaz-util.h>
 
@@ -42,6 +57,8 @@
 
 #define C_PROMPT "Z> "
 
+static char *codeset = 0;               /* character set for output */
+
 static ODR out, in, print;              /* encoding and decoding streams */
 static FILE *apdu_file = 0;
 static COMSTACK conn = 0;               /* our z-association */
@@ -49,7 +66,7 @@ static Z_IdAuthentication *auth = 0;    /* our current auth definition */
 char *databaseNames[128];
 int num_databaseNames = 0;
 static Z_External *record_last = 0;
-static int setnumber = -1;               /* current result set number */
+static int setnumber = -1;              /* current result set number */
 static int smallSetUpperBound = 0;
 static int largeSetLowerBound = 1;
 static int mediumSetPresentNumber = 0;
@@ -59,7 +76,7 @@ static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
 static enum oid_value recordsyntax = VAL_USMARC;
 static enum oid_value schema = VAL_NONE;
 static int sent_close = 0;
-static NMEM session_mem = NULL;      /* memory handle for init-response */
+static NMEM session_mem = NULL;         /* memory handle for init-response */
 static Z_InitResponse *session = 0;     /* session parameters */
 static char last_scan_line[512] = "0";
 static char last_scan_query[512] = "0";
@@ -80,7 +97,8 @@ static int auto_reconnect = 0;
 typedef enum {
     QueryType_Prefix,
     QueryType_CCL,
-    QueryType_CCL2RPN
+    QueryType_CCL2RPN,
+    QueryType_CQL
 } QueryType;
 
 static QueryType queryType = QueryType_Prefix;
@@ -106,7 +124,7 @@ int rl_attempted_completion_over = 0;
 #define maxOtherInfosSupported 10
 struct {
     int oidval;
-       char* value;
+    char* value;
 } extraOtherInfos[maxOtherInfosSupported];
        
 
@@ -127,6 +145,7 @@ const char* query_type_as_string(QueryType q)
     case QueryType_Prefix: return "prefix (RPN sent to server)";
     case QueryType_CCL: return "CCL (CCL sent to server) ";
     case QueryType_CCL2RPN: return "CCL -> RPN (RPN sent to server)";
+    case QueryType_CQL: return "CQL (CQL sent to server)";
     default: 
         return "unknown Query type internal yaz-client error";
     }
@@ -149,8 +168,6 @@ void do_hex_dump(char* buf,int len)
 #endif
 }
 
-
-
 void add_otherInfos(Z_APDU *a) 
 {
     Z_OtherInformation **oi;
@@ -357,16 +374,16 @@ static int process_initResponse(Z_InitResponse *res)
                yaz_get_charneg_record(res->otherInfo);
        
        if (p) {
-       
-               char *charset=NULL, *lang=NULL;
-               int selected;
-               
-               yaz_get_response_charneg(session_mem, p, &charset, &lang,
+            
+            char *charset=NULL, *lang=NULL;
+            int selected;
+            
+            yaz_get_response_charneg(session_mem, p, &charset, &lang,
                                      &selected);
-               
-               printf("Accepted character set : %s\n", charset);
-               printf("Accepted code language : %s\n", lang ? lang : "none");
-               printf("Accepted records in ...: %d\n", selected );
+            
+            printf("Accepted character set : %s\n", charset);
+            printf("Accepted code language : %s\n", lang ? lang : "none");
+            printf("Accepted records in ...: %d\n", selected );
        }
     }
     fflush (stdout);
@@ -465,7 +482,11 @@ int cmd_open(char *arg)
     {
         printf ("error = %s\n", cs_strerror(conn));
         if (conn->cerrno == CSYSERR)
-            perror("system");
+       {
+           char msg[256];
+           yaz_strerror(msg, sizeof(msg));
+           printf ("%s\n", msg);
+       }
         cs_close(conn);
         conn = 0;
         return 0;
@@ -546,105 +567,6 @@ int cmd_authentication(char *arg)
 /* SEARCH SERVICE ------------------------------ */
 static void display_record(Z_External *r);
 
-static void display_variant(Z_Variant *v, int level)
-{
-    int i;
-
-    for (i = 0; i < v->num_triples; i++)
-    {
-        printf("%*sclass=%d,type=%d", level * 4, "", *v->triples[i]->zclass,
-            *v->triples[i]->type);
-        if (v->triples[i]->which == Z_Triple_internationalString)
-            printf(",value=%s\n", v->triples[i]->value.internationalString);
-        else
-            printf("\n");
-    }
-}
-
-static void display_grs1(Z_GenericRecord *r, int level)
-{
-    int i;
-
-    if (!r)
-    {
-        return;
-    }
-    for (i = 0; i < r->num_elements; i++)
-    {
-        Z_TaggedElement *t;
-
-        printf("%*s", level * 4, "");
-        t = r->elements[i];
-        printf("(");
-        if (t->tagType)
-            printf("%d,", *t->tagType);
-        else
-            printf("?,");
-        if (t->tagValue->which == Z_StringOrNumeric_numeric)
-            printf("%d) ", *t->tagValue->u.numeric);
-        else
-            printf("%s) ", t->tagValue->u.string);
-        if (t->content->which == Z_ElementData_subtree)
-        {
-            if (!t->content->u.subtree)
-                printf (" (no subtree)\n");
-            else
-            {
-                printf("\n");
-                display_grs1(t->content->u.subtree, level+1);
-            }
-        }
-        else if (t->content->which == Z_ElementData_string)
-            printf("%s\n", t->content->u.string);
-        else if (t->content->which == Z_ElementData_numeric)
-            printf("%d\n", *t->content->u.numeric);
-        else if (t->content->which == Z_ElementData_oid)
-        {
-            int *ip = t->content->u.oid;
-            oident *oent;
-            
-            if ((oent = oid_getentbyoid(t->content->u.oid)))
-                printf("OID: %s\n", oent->desc);
-            else
-            {
-                printf("{");
-                while (ip && *ip >= 0)
-                    printf(" %d", *(ip++));
-                printf(" }\n");
-            }
-        }
-        else if (t->content->which == Z_ElementData_noDataRequested)
-            printf("[No data requested]\n");
-        else if (t->content->which == Z_ElementData_elementEmpty)
-            printf("[Element empty]\n");
-        else if (t->content->which == Z_ElementData_elementNotThere)
-            printf("[Element not there]\n");
-        else if (t->content->which == Z_ElementData_date)
-            printf("Date: %s\n", t->content->u.date);
-        else if (t->content->which == Z_ElementData_ext)
-        {
-            printf ("External\n");
-            display_record (t->content->u.ext);
-        } 
-        else
-            printf("? type = %d\n",t->content->which);
-        if (t->appliedVariant)
-            display_variant(t->appliedVariant, level+1);
-        if (t->metaData && t->metaData->supportedVariants)
-        {
-            int c;
-
-            printf("%*s---- variant list\n", (level+1)*4, "");
-            for (c = 0; c < t->metaData->num_supportedVariants; c++)
-            {
-                printf("%*svariant #%d\n", (level+1)*4, "", c);
-                display_variant(t->metaData->supportedVariants[c], level + 2);
-            }
-        }
-    }
-}
-
-
 static void print_record(const unsigned char *buf, size_t len)
 {
     size_t i = len;
@@ -695,7 +617,7 @@ static void display_record(Z_External *r)
                             r->u.octet_aligned->len);
                 fprintf(stderr, "---------\n");
                 
-                               /* note just ignores the error ant print the bytes form the octet_aligned laiter */
+               /* note just ignores the error ant print the bytes form the octet_aligned later */
             } else {
                 /*
                  * Note: we throw away the original, BER-encoded record here.
@@ -711,7 +633,7 @@ static void display_record(Z_External *r)
     if (ent && ent->value == VAL_SOIF)
         print_record((const unsigned char *) r->u.octet_aligned->buf,
                      r->u.octet_aligned->len);
-    else if (r->which == Z_External_octet && r->u.octet_aligned->len)
+    else if (r->which == Z_External_octet)
     {
         const char *octet_buf = (char*)r->u.octet_aligned->buf;
         if (ent->value == VAL_TEXT_XML || ent->value == VAL_APPLICATION_XML ||
@@ -739,13 +661,64 @@ static void display_record(Z_External *r)
 #endif
                 )
             {
-                if (marc_display_exl (octet_buf, NULL, 0 /* debug */,
-                                      r->u.octet_aligned->len) <= 0)
+                char *result;
+                int rlen;
+                yaz_iconv_t cd = 0;
+                yaz_marc_t mt = yaz_marc_create();
+                    
+                if (yaz_marc_decode_buf(mt, octet_buf,r->u.octet_aligned->len,
+                                        &result, &rlen)> 0)
+                {
+                    char *from = 0;
+                    if (ent->value == VAL_USMARC)
+                    {
+                        if (octet_buf[9] == 'a')
+                            from = "UTF-8";
+                        else
+                            from = "MARC8";
+                    }
+                    else
+                        from = "ISO-8859-1";
+
+                    if (codeset && from)
+                    {   
+                        printf ("convert from %s to %s\n", from, codeset);
+                        cd = yaz_iconv_open(codeset, from);
+                    }
+                    if (!cd)
+                        fwrite (result, 1, rlen, stdout);
+                    else
+                    {
+                        char outbuf[12];
+                        size_t inbytesleft = rlen;
+                        const char *inp = result;
+                        
+                        while (inbytesleft)
+                        {
+                            size_t outbytesleft = sizeof(outbuf);
+                            char *outp = outbuf;
+                            size_t r = yaz_iconv (cd, (char**) &inp,
+                                                  &inbytesleft, 
+                                                  &outp, &outbytesleft);
+                            if (r == (size_t) (-1))
+                            {
+                                int e = yaz_iconv_error(cd);
+                                if (e != YAZ_ICONV_E2BIG)
+                                    break;
+                            }
+                            fwrite (outbuf, outp - outbuf, 1, stdout);
+                        }
+                    }
+                }
+               else
                 {
                     printf ("bad MARC. Dumping as it is:\n");
                     print_record((const unsigned char*) octet_buf,
-                                 r->u.octet_aligned->len);
-                }
+                                  r->u.octet_aligned->len);
+               }       
+                yaz_marc_destroy(mt);
+                if (cd)
+                    yaz_iconv_close(cd);
             }
             else
             {
@@ -767,12 +740,16 @@ static void display_record(Z_External *r)
     }
     else if (ent && ent->value == VAL_GRS1)
     {
+        WRBUF w;
         if (r->which != Z_External_grs1)
         {
             printf("Expecting single GRS type for GRS.\n");
             return;
         }
-        display_grs1(r->u.grs1, 0);
+        w = wrbuf_alloc();
+        yaz_display_grs1(w, r->u.grs1, 0);
+        puts (wrbuf_buf(w));
+        wrbuf_free(w, 1);
     }
     else 
     {
@@ -900,6 +877,7 @@ static int send_searchRequest(char *arg)
     Z_RPNQuery *RPNquery;
     Odr_oct ccl_query;
     YAZ_PQF_Parser pqf_parser;
+    Z_External *ext;
 
     if (queryType == QueryType_CCL2RPN)
     {
@@ -986,6 +964,16 @@ static int send_searchRequest(char *arg)
         query.u.type_1 = RPNquery;
         ccl_rpn_delete (rpn);
         break;
+    case QueryType_CQL:
+        query.which = Z_Query_type_104;
+        ext = odr_malloc(out, sizeof(*ext));
+        ext->direct_reference = odr_getoidbystr(out, "1.2.840.10003.16.2");
+        ext->indirect_reference = 0;
+        ext->descriptor = 0;
+        ext->which = Z_External_CQL;
+        ext->u.cql = odr_strdup(out, arg);
+        query.u.type_104 =  ext;
+        break;
     default:
         printf ("Unsupported query type\n");
         return 0;
@@ -1536,11 +1524,64 @@ static int cmd_update(char *arg)
     Z_IUOriginPartToKeep *toKeep;
     Z_IUSuppliedRecords *notToKeep;
     oident update_oid;
-    printf ("Update request\n");
-    fflush(stdout);
-    
-    if (!record_last)
+    char action[20], recid[20], fname[80];
+    int action_no;
+    Z_External *record_this = 0;
+
+    *action = 0;
+    *recid = 0;
+    *fname = 0;
+    sscanf (arg, "%19s %19s %79s", action, recid, fname);
+
+    if (!strcmp (action, "insert"))
+        action_no = Z_IUOriginPartToKeep_recordInsert;
+    else if (!strcmp (action, "replace"))
+        action_no = Z_IUOriginPartToKeep_recordReplace;
+    else if (!strcmp (action, "delete"))
+        action_no = Z_IUOriginPartToKeep_recordDelete;
+    else if (!strcmp (action, "update"))
+        action_no = Z_IUOriginPartToKeep_specialUpdate;
+    else 
+    {
+        printf ("Bad action: %s\n", action);
+        printf ("Possible values: insert, replace, delete, update\n");
         return 0;
+    }
+
+    if (*fname)
+    {
+        FILE *inf;
+        struct stat status;
+        stat (fname, &status);
+        if (S_ISREG(status.st_mode) && (inf = fopen(fname, "r")))
+        {
+            size_t len = status.st_size;
+            char *buf = (char *) xmalloc (len);
+
+            fread (buf, 1, len, inf);
+
+            fclose (inf);
+            
+            record_this = z_ext_record (out, VAL_TEXT_XML, buf, len);
+            
+            xfree (buf);
+        }
+        else
+        {
+            printf ("File %s doesn't exist\n", fname);
+            return 0;
+        }
+    }
+    else
+    {
+        if (!record_last)
+        {
+            printf ("No last record (update ignored)\n");
+            return 0;
+        }
+        record_this = record_last;
+    }
+
     update_oid.proto = PROTO_Z3950;
     update_oid.oclass = CLASS_EXTSERV;
     update_oid.value = VAL_DBUPDATE;
@@ -1567,7 +1608,7 @@ static int cmd_update(char *arg)
     toKeep->elementSetName = 0;
     toKeep->actionQualifier = 0;
     toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
-    *toKeep->action = Z_IUOriginPartToKeep_recordInsert;
+    *toKeep->action = action_no;
 
     notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
         odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
@@ -1576,10 +1617,20 @@ static int cmd_update(char *arg)
         odr_malloc(out, sizeof(*notToKeep->elements));
     notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
         odr_malloc(out, sizeof(**notToKeep->elements));
-    notToKeep->elements[0]->u.number = 0;
+    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_last;
+    notToKeep->elements[0]->record = record_this;
     
     send_apdu(apdu);
 
@@ -2130,17 +2181,19 @@ int cmd_schema(char *arg)
 
 int cmd_format(char *arg)
 {
+    oid_value nsyntax;
     if (!arg || !*arg)
     {
         printf("Usage: format <recordsyntax>\n");
         return 0;
     }
-    recordsyntax = oid_getvalbyname (arg);
-    if (recordsyntax == VAL_NONE)
+    nsyntax = oid_getvalbyname (arg);
+    if (strcmp(arg, "none") && nsyntax == VAL_NONE)
     {
         printf ("unknown record syntax\n");
         return 0;
     }
+    recordsyntax = nsyntax;
     return 1;
 }
 
@@ -2187,12 +2240,15 @@ int cmd_querytype (char *arg)
         queryType = QueryType_Prefix;
     else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn"))
         queryType = QueryType_CCL2RPN;
+    else if (!strcmp(arg, "cql"))
+        queryType = QueryType_CQL;        
     else
     {
         printf ("Querytype must be one of:\n");
         printf (" prefix         - Prefix query\n");
         printf (" ccl            - CCL query\n");
         printf (" ccl2rpn        - CCL query converted to RPN\n");
+        printf (" cql            - CQL\n");
         return 0;
     }
     return 1;
@@ -2476,7 +2532,7 @@ int cmd_register_oid(char* args) {
         {"schema",CLASS_SCHEMA},
         {"tagset",CLASS_TAGSET},
         {"general",CLASS_GENERAL},
-        {0,0}
+        {0,(enum oid_class) 0}
     };
     char oname_str[101], oclass_str[101], oid_str[101];  
     char* name;
@@ -2798,12 +2854,22 @@ int cmd_list_otherinfo(char* args)
         }
 
         if(extraOtherInfos[i].oidval != -1) 
-            printf("  otherinfo %d %s %s\n",i,yaz_z3950_oid_value_to_str(extraOtherInfos[i].oidval,CLASS_RECSYN), extraOtherInfos[i].value);
+            printf("  otherinfo %d %s %s\n",
+                   i,
+                   yaz_z3950_oid_value_to_str(
+                       (enum oid_value) extraOtherInfos[i].oidval,
+                       CLASS_RECSYN),
+                   extraOtherInfos[i].value);
         
     } else {           
         for(i=0; i<maxOtherInfosSupported; ++i) {
             if(extraOtherInfos[i].oidval != -1) 
-                printf("  otherinfo %d %s %s\n",i,yaz_z3950_oid_value_to_str(extraOtherInfos[i].oidval,CLASS_RECSYN), extraOtherInfos[i].value);
+                printf("  otherinfo %d %s %s\n",
+                       i,
+                       yaz_z3950_oid_value_to_str(
+                           (enum oid_value) extraOtherInfos[i].oidval,
+                           CLASS_RECSYN),
+                       extraOtherInfos[i].value);
         }
         
     }
@@ -2942,7 +3008,7 @@ static struct {
     {"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
     {"refid", cmd_refid, "<id>",NULL,0,NULL},
     {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
-    {"update", cmd_update, "<item>",NULL,0,NULL},
+    {"update", cmd_update, "<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, "<charset_name>",NULL,0,NULL},
@@ -3038,11 +3104,9 @@ int cmd_register_tab(char* arg) {
         return 1;
     }
     
-    
-    
-    if(!cmd[i].local_tabcompletes) {
-        cmd[i].local_tabcompletes = calloc(1,sizeof(char**));
-    }
+        
+    if(!cmd[i].local_tabcompletes)
+        cmd[i].local_tabcompletes = (char **) calloc(1,sizeof(char**));
     
     num_of_tabs=0;             
     
@@ -3051,7 +3115,8 @@ int cmd_register_tab(char* arg) {
         num_of_tabs++;
     }
     
-    cmd[i].local_tabcompletes=realloc(cmd[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
+    cmd[i].local_tabcompletes =  (char **)
+        realloc(cmd[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
     tabslist=cmd[i].local_tabcompletes;
     tabslist[num_of_tabs]=strdup(tabargument);
     tabslist[num_of_tabs+1]=NULL;
@@ -3251,7 +3316,15 @@ int main(int argc, char **argv)
     char *arg;
     int ret;
     
-    while ((ret = options("k:c:a:m:v:p:u:", argv, argc, &arg)) != -2)
+#if HAVE_LOCALE_H
+    if (!setlocale(LC_CTYPE, ""))
+        fprintf (stderr, "setlocale failed\n");
+#endif
+#if HAVE_LANGINFO_H
+    codeset = nl_langinfo(CODESET);
+#endif
+
+    while ((ret = options("k:c:a:m:v:p:u:t:", argv, argc, &arg)) != -2)
     {
         switch (ret)
         {
@@ -3273,19 +3346,22 @@ int main(int argc, char **argv)
                 exit (1);
             }
             break;
-               case 'c':
-                       strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
-                       ccl_fields[sizeof(ccl_fields)-1] = '\0';
-                       break;
+        case 't':
+            codeset = arg;
+            break;
+        case 'c':
+            strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
+            ccl_fields[sizeof(ccl_fields)-1] = '\0';
+            break;
         case 'a':
             if (!strcmp(arg, "-"))
                 apdu_file=stderr;
             else
                 apdu_file=fopen(arg, "a");
             break;
-               case 'p':
-                       yazProxy=strdup(arg);
-                       break;
+        case 'p':
+            yazProxy=strdup(arg);
+            break;
         case 'u':
             if (!auth_command)
             {