CCL: split-list deals with use attr YAZ-844
[yaz-moved-to-github.git] / client / client.c
index 46b6450..e6fcada 100644 (file)
@@ -44,7 +44,7 @@
 #endif
 
 #include <yaz/yaz-util.h>
-
+#include <yaz/backtrace.h>
 #include <yaz/comstack.h>
 
 #include <yaz/oid_db.h>
@@ -64,6 +64,7 @@
 #include <yaz/cql.h>
 #include <yaz/log.h>
 #include <yaz/facet.h>
+#include <yaz/cookie.h>
 
 #if HAVE_READLINE_READLINE_H
 #include <readline/readline.h>
@@ -126,6 +127,7 @@ static char ccl_fields[512] = "default.bib";
 static char cql_fields[512] = "/usr/local/share/yaz/etc/pqf.properties";
 static char *esPackageName = 0;
 static char *yazProxy = 0;
+static int proxy_mode = 0;
 static int kilobytes = 64 * 1024;
 static char *negotiationCharset = 0;
 static int  negotiationCharsetRecords = 1;
@@ -145,10 +147,11 @@ static int z3950_version = 3;
 static int scan_stepSize = 0;
 static char scan_position[64];
 static int scan_size = 20;
-static char cur_host[200];
+static WRBUF cur_host = 0;
 static Odr_int last_hit_count = 0;
 static int pretty_xml = 0;
 static Odr_int sru_maximumRecords = 0;
+static yaz_cookies_t yaz_cookies = 0;
 
 typedef enum {
     QueryType_Prefix,
@@ -347,7 +350,7 @@ static void send_Z3950_initRequest(const char* type_and_host)
 
     req->referenceId = set_refid(out);
 
-    if (yazProxy && type_and_host)
+    if (proxy_mode && type_and_host)
     {
         yaz_oi_set_string_oid(&req->otherInfo, out, yaz_oid_userinfo_proxy,
                               1, type_and_host);
@@ -543,7 +546,7 @@ static void render_diag(Z_DiagnosticFormat *diag)
             Z_DefaultDiagFormat *dd = ds->u.defaultDiagRec;
             /* ### should check `dd->diagnosticSetId' */
             printf("code=" ODR_INT_PRINTF " (%s)", *dd->condition,
-                   diagbib1_str(*dd->condition));
+                   diagbib1_str((int) *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);
@@ -701,7 +704,7 @@ static int session_connect_base(const char *arg, const char **basep)
     strncpy(type_and_host, arg, sizeof(type_and_host)-1);
     type_and_host[sizeof(type_and_host)-1] = '\0';
 
-    conn = cs_create_host_proxy(arg, 1, &add, yazProxy);
+    conn = cs_create_host2(arg, 1, &add, yazProxy, &proxy_mode);
     if (!conn)
     {
         printf("Could not resolve address %s\n", arg);
@@ -737,12 +740,15 @@ static int session_connect_base(const char *arg, const char **basep)
     return 0;
 }
 
-static int session_connect(const char *arg)
+static int session_connect(void)
 {
     int r;
     const char *basep = 0;
 
-    r = session_connect_base(arg, &basep);
+    yaz_cookies_destroy(yaz_cookies);
+    yaz_cookies = yaz_cookies_create();
+
+    r = session_connect_base(wrbuf_cstr(cur_host), &basep);
     if (basep && *basep)
         set_base(basep);
     else if (protocol == PROTO_Z3950)
@@ -755,15 +761,16 @@ static int cmd_open(const char *arg)
     int r;
     if (arg)
     {
-        strncpy(cur_host, arg, sizeof(cur_host)-1);
-        cur_host[sizeof(cur_host)-1] = 0;
+        wrbuf_rewind(cur_host);
+        if (!strstr(arg, "://") && strcmp(sru_method, "soap"))
+            wrbuf_puts(cur_host, "http://");
+        wrbuf_puts(cur_host, arg);
     }
     set_base("");
-    r = session_connect(cur_host);
+    r = session_connect();
     if (conn && conn->protocol == PROTO_HTTP)
         queryType = QueryType_CQL;
 
-
     return r;
 }
 
@@ -1197,7 +1204,7 @@ static void display_diagrecs(Z_DiagRec **pp, int num)
                 printf("Unknown diagset: %s\n", diag_name);
         }
         printf("    [" ODR_INT_PRINTF "] %s",
-               *r->condition, diagbib1_str(*r->condition));
+               *r->condition, diagbib1_str((int) *r->condition));
         switch (r->which)
         {
         case Z_DefaultDiagFormat_v2Addinfo:
@@ -1314,7 +1321,7 @@ static int send_srw_host_path(Z_SRW_PDU *sr, const char *host_port,
     const char *charset = negotiationCharset;
     Z_GDU *gdu;
 
-    gdu = z_get_HTTP_Request_host_path(out, host_port, path);
+    gdu = z_get_HTTP_Request_uri(out, host_port, path, proxy_mode);
 
     if (auth)
     {
@@ -1357,47 +1364,20 @@ static int send_srw_host_path(Z_SRW_PDU *sr, const char *host_port,
 
 static int send_srw(Z_SRW_PDU *sr)
 {
-    char *path = yaz_encode_sru_dbpath_odr(out, databaseNames[0]);
-    return send_srw_host_path(sr, cur_host, path);
+    return send_srw_host_path(sr, wrbuf_cstr(cur_host), databaseNames[0]);
 }
 
-static int send_SRW_redirect(const char *uri, Z_HTTP_Response *cookie_hres)
+static int send_SRW_redirect(const char *uri)
 {
     const char *username = 0;
     const char *password = 0;
-    struct Z_HTTP_Header *h;
-    char *combined_cookies = 0;
-    int combined_cookies_len = 0;
     Z_GDU *gdu = get_HTTP_Request_url(out, uri);
 
     gdu->u.HTTP_Request->method = odr_strdup(out, "GET");
     z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers, "Accept",
                       "text/xml");
 
-    for (h = cookie_hres->headers; h; h = h->next)
-    {
-        if (!strcmp(h->name, "Set-Cookie"))
-        {
-            char *cp;
-
-            if (!(cp = strchr(h->value, ';')))
-                cp = h->value + strlen(h->value);
-            if (cp - h->value >= 1)
-            {
-                combined_cookies = xrealloc(combined_cookies, combined_cookies_len + cp - h->value + 3);
-                memcpy(combined_cookies+combined_cookies_len, h->value, cp - h->value);
-                combined_cookies[combined_cookies_len + cp - h->value] = '\0';
-                strcat(combined_cookies,"; ");
-                combined_cookies_len = strlen(combined_cookies);
-            }
-        }
-    }
-    if (combined_cookies_len)
-    {
-        z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers, "Cookie", combined_cookies);
-        xfree(combined_cookies);
-    }
-
+    yaz_cookies_request(yaz_cookies, out, gdu->u.HTTP_Request);
     if (auth)
     {
         if (auth->which == Z_IdAuthentication_open)
@@ -2408,7 +2388,7 @@ static int send_SRW_update(int action_no, const char *recid,
                            char *rec_buf, int rec_len)
 {
     if (!conn)
-        session_connect(cur_host);
+        session_connect();
     if (!conn)
         return 0;
     else
@@ -2670,7 +2650,7 @@ static int cmd_explain(const char *arg)
         return 0;
 #if YAZ_HAVE_XML2
     if (!conn)
-        session_connect(cur_host);
+        session_connect();
     if (conn)
     {
         Z_SRW_PDU *sr = 0;
@@ -2693,12 +2673,14 @@ static int cmd_init(const char *arg)
 {
     if (*arg)
     {
-        strncpy(cur_host, arg, sizeof(cur_host)-1);
-        cur_host[sizeof(cur_host)-1] = 0;
+        wrbuf_rewind(cur_host);
+        if (!strstr(arg, "://") && strcmp(sru_method, "soap"))
+            wrbuf_puts(cur_host, "http://");
+        wrbuf_puts(cur_host, arg);
     }
     if (only_z3950())
         return 1;
-    send_Z3950_initRequest(cur_host);
+    send_Z3950_initRequest(wrbuf_cstr(cur_host));
     return 2;
 }
 
@@ -2869,7 +2851,7 @@ static int cmd_find(const char *arg)
     {
 #if YAZ_HAVE_XML2
         if (!conn)
-            session_connect(cur_host);
+            session_connect();
         if (!conn)
             return 0;
         if (!send_SRW_searchRequest(arg))
@@ -2880,7 +2862,7 @@ static int cmd_find(const char *arg)
     }
     else
     {
-        if (*cur_host && auto_reconnect)
+        if (wrbuf_len(cur_host) && auto_reconnect)
         {
             int i = 0;
             for (;;)
@@ -2898,7 +2880,7 @@ static int cmd_find(const char *arg)
                     printf("Unable to reconnect\n");
                     break;
                 }
-                session_connect(cur_host);
+                session_connect();
                 wait_and_handle_response(0);
             }
             return 0;
@@ -3241,7 +3223,7 @@ static int cmd_show(const char *arg)
     {
 #if YAZ_HAVE_XML2
         if (!conn)
-            session_connect(cur_host);
+            session_connect();
         if (!conn)
             return 0;
         if (!send_SRW_presentRequest(arg))
@@ -3265,9 +3247,15 @@ static int cmd_show(const char *arg)
 
 static void exit_client(int code)
 {
+    odr_destroy(in);
+    odr_destroy(out);
+    odr_destroy(print);
+    ccl_qual_rm(&bibset);
+    yaz_cookies_destroy(yaz_cookies);
     file_history_save(file_history);
     file_history_destroy(&file_history);
     nmem_destroy(nmem_auth);
+    wrbuf_destroy(cur_host);
     exit(code);
 }
 
@@ -3490,7 +3478,7 @@ static void process_Z3950_scanResponse(Z_ScanResponse *res)
         num_entries = res->entries->num_entries;
     for (i = 0; i < num_entries; i++)
     {
-        int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
+        Odr_int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
         if (entries[i]->which == Z_Entry_termInfo)
         {
             printf("%c ", i + 1 == pos_term ? '*' : ' ');
@@ -3629,7 +3617,7 @@ static int cmd_scan_common(const char *set, const char *arg)
     {
 #if YAZ_HAVE_XML2
         if (!conn)
-            session_connect(cur_host);
+            session_connect();
         if (!conn)
             return 0;
         if (send_SRW_scanRequest(scan_query, pos_p, scan_size) < 0)
@@ -3641,9 +3629,9 @@ static int cmd_scan_common(const char *set, const char *arg)
     }
     else
     {
-        if (*cur_host && !conn && auto_reconnect)
+        if (wrbuf_len(cur_host) && !conn && auto_reconnect)
         {
-            session_connect(cur_host);
+            session_connect();
             wait_and_handle_response(0);
         }
         if (!conn)
@@ -3732,18 +3720,19 @@ static int cmd_format(const char *arg)
 
 static int cmd_elements(const char *arg)
 {
-    static Z_ElementSetNames esn;
-    static char what[100];
-
-    if (!arg || !*arg)
+    if (elementSetNames)
     {
-        elementSetNames = 0;
-        return 1;
+        xfree(elementSetNames->u.generic);
+        xfree(elementSetNames);
+    }
+    elementSetNames = 0;
+    if (arg && *arg)
+    {
+        elementSetNames = (Z_ElementSetNames *)
+            xmalloc(sizeof(*elementSetNames));
+        elementSetNames->which = Z_ElementSetNames_generic;
+        elementSetNames->u.generic = xstrdup(arg);
     }
-    strcpy(what, arg);
-    esn.which = Z_ElementSetNames_generic;
-    esn.u.generic = what;
-    elementSetNames = &esn;
     return 1;
 }
 
@@ -4274,6 +4263,8 @@ static void initialize(const char *rc_file)
     FILE *inf;
     int i;
 
+    cur_host = wrbuf_alloc();
+
     if (!(out = odr_createmem(ODR_ENCODE)) ||
         !(in = odr_createmem(ODR_DECODE)) ||
         !(print = odr_createmem(ODR_PRINT)))
@@ -4529,7 +4520,7 @@ static void http_response(Z_HTTP_Response *hres)
 }
 #endif
 
-#define max_HTTP_redirects 2
+#define max_HTTP_redirects 3
 
 static void wait_and_handle_response(int one_response_only)
 {
@@ -4547,39 +4538,37 @@ static void wait_and_handle_response(int one_response_only)
     while(conn)
     {
         res = cs_get(conn, &netbuffer, &netbufferlen);
-        if (reconnect_ok && res <= 0 && protocol == PROTO_HTTP)
+        if (res <= 0)
         {
-            cs_close(conn);
-            conn = 0;
-            session_connect(cur_host);
-            reconnect_ok = 0;
-            if (conn)
+            if (reconnect_ok && protocol == PROTO_HTTP)
             {
-                char *buf_out;
-                int len_out;
-
-                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);
-                continue;
+                cs_close(conn);
+                conn = 0;
+                session_connect();
+                reconnect_ok = 0;
+                if (conn)
+                {
+                    char *buf_out;
+                    int len_out;
+                    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);
+                    continue;
+                }
+            }
+            else
+            {
+                printf("Target closed connection\n");
+                close_session();
+                break;
             }
-        }
-        else if (res <= 0)
-        {
-            printf("Target closed connection\n");
-            close_session();
-            break;
         }
 #if HAVE_GETTIMEOFDAY
         if (got_tv_end == 0)
             gettimeofday(&tv_end, 0); /* count first one only */
         got_tv_end++;
 #endif
-        odr_reset(out);
         odr_reset(in); /* release APDU from last round */
         record_last = 0;
         do_hex_dump(netbuffer, res);
@@ -4587,21 +4576,43 @@ static void wait_and_handle_response(int one_response_only)
 
         if (!z_GDU(in, &gdu, 0, 0))
         {
-            FILE *f = ber_file ? ber_file : stdout;
-            odr_perror(in, "Decoding incoming APDU");
-            fprintf(f, "[Near %ld]\n", (long) odr_offset(in));
-            fprintf(f, "Packet dump:\n---------\n");
-            odr_dumpBER(f, netbuffer, res);
-            fprintf(f, "---------\n");
-            if (apdu_file)
+            if (reconnect_ok && protocol == PROTO_HTTP)
             {
-                z_GDU(print, &gdu, 0, 0);
-                odr_reset(print);
+                fprintf(stderr, "Decoding error. Reconnecting\n");
+                cs_close(conn);
+                conn = 0;
+                session_connect();
+                reconnect_ok = 0;
+                if (conn)
+                {
+                    char *buf_out;
+                    int len_out;
+                    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);
+                    continue;
+                }
+            }
+            else
+            {
+                FILE *f = ber_file ? ber_file : stdout;
+                odr_perror(in, "Decoding incoming APDU");
+                fprintf(f, "[Near %ld]\n", (long) odr_offset(in));
+                fprintf(f, "Packet dump:\n---------\n");
+                odr_dumpBER(f, netbuffer, res);
+                fprintf(f, "---------\n");
+                if (apdu_file)
+                {
+                    z_GDU(print, &gdu, 0, 0);
+                    odr_reset(print);
+                }
+                if (conn && cs_more(conn))
+                    continue;
+                break;
             }
-            if (conn && cs_more(conn))
-                continue;
-            break;
         }
+        odr_reset(out);
         if (ber_file)
             odr_dumpBER(ber_file, netbuffer, res);
         if (apdu_file && !z_GDU(print, &gdu, 0, 0))
@@ -4666,17 +4677,23 @@ static void wait_and_handle_response(int one_response_only)
             Z_HTTP_Response *hres = gdu->u.HTTP_Response;
             int code = hres->code;
             const char *location = 0;
+
+            yaz_cookies_response(yaz_cookies, hres);
             if ((code == 301 || code == 302)
                 && no_redirects < max_HTTP_redirects
                 && !yaz_matchstr(sru_method, "get")
                 && (location = z_HTTP_header_lookup(hres->headers, "Location")))
             {
                 const char *base_tmp;
-                session_connect_base(location, &base_tmp);
+                int host_change = 0;
+                location = yaz_check_location(in, wrbuf_cstr(cur_host),
+                                              location, &host_change);
+                if (host_change)
+                    session_connect_base(location, &base_tmp);
                 no_redirects++;
                 if (conn)
                 {
-                    if (send_SRW_redirect(location, hres) == 2)
+                    if (send_SRW_redirect(location) == 2)
                         continue;
                 }
                 printf("Redirect failed\n");
@@ -4850,9 +4867,9 @@ static int cmd_list_all(const char* args)
 
     /* connection options */
     if (conn)
-        printf("Connected to         : %s\n", cur_host);
-    else if (*cur_host)
-        printf("Not connected to     : %s\n", cur_host);
+        printf("Connected to         : %s\n", wrbuf_cstr(cur_host));
+    else if (cur_host && wrbuf_len(cur_host))
+        printf("Not connected to     : %s\n", wrbuf_cstr(cur_host));
     else
         printf("Not connected        : \n");
     if (yazProxy) printf("using proxy          : %s\n",yazProxy);
@@ -5405,6 +5422,8 @@ int main(int argc, char **argv)
     if (codeset)
         outputCharset = xstrdup(codeset);
 
+    yaz_enable_panic_backtrace(prog);
+
     ODR_MASK_SET(&z3950_options, Z_Options_search);
     ODR_MASK_SET(&z3950_options, Z_Options_present);
     ODR_MASK_SET(&z3950_options, Z_Options_namedResultSets);