/*
- * Copyright (C) 1995-2006, Index Data ApS
+ * Copyright (C) 1995-2007, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: client.c,v 1.307 2006-05-07 19:15:16 adam Exp $
+ * $Id: client.c,v 1.327 2007-01-24 23:10:01 adam Exp $
+ */
+/** \file client.c
+ * \brief yaz-client program
*/
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <ctype.h>
+#ifndef WIN32
+#include <signal.h>
+#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "admin.h"
#include "tabcomplete.h"
+#include "fhistory.h"
#define C_PROMPT "Z> "
+static file_history_t file_history = 0;
+
+static char *sru_method = "soap";
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
+#if YAZ_HAVE_XML2
static ODR srw_sr_odr_out = 0;
static Z_SRW_PDU *srw_sr = 0;
#endif
static char *outputCharset = 0;
static char *marcCharset = 0;
static char* yazLang = 0;
-static char* http_version = "1.1";
static char last_cmd[32] = "?";
static FILE *marc_file = 0;
char **readline_completer(char *text, int start, int end);
#endif
static char *command_generator(const char *text, int state);
-char** curret_global_list=NULL;
int cmd_register_tab(const char* arg);
static void close_session (void);
-ODR getODROutputStream()
+ODR getODROutputStream(void)
{
return out;
}
conn = cs_create_host(arg, 1, &add);
if (!conn)
{
- printf ("Couldn't create comstack\n");
+ printf ("Could not resolve address %s\n", arg);
return 0;
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (conn->protocol == PROTO_HTTP)
queryType = QueryType_CQL;
#else
if (cs_connect(conn, add) < 0)
{
printf ("error = %s\n", cs_strerror(conn));
- if (conn->cerrno == CSYSERR)
- {
- char msg[256];
- yaz_strerror(msg, sizeof(msg));
- printf ("%s\n", msg);
- }
cs_close(conn);
conn = 0;
return 0;
return session_connect(cur_host);
}
-void try_reconnect()
+void try_reconnect(void)
{
char* open_command;
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)
+ const char *from = 0;
+
+ if (marcCharset && !strcmp(marcCharset, "auto"))
{
- char *from = 0;
- if (marcCharset && !strcmp(marcCharset, "auto"))
+ if (ent->value == VAL_USMARC)
{
- if (ent->value == VAL_USMARC)
- {
- if (octet_buf[9] == 'a')
- from = "UTF-8";
- else
- from = "MARC-8";
- }
+ if (octet_buf[9] == 'a')
+ from = "UTF-8";
else
- from = "ISO-8859-1";
- }
- else if (marcCharset)
- from = marcCharset;
- if (outputCharset && from)
- {
- cd = yaz_iconv_open(outputCharset, from);
- printf ("convert from %s to %s", from,
- outputCharset);
- if (!cd)
- printf (" unsupported\n");
- else
- printf ("\n");
+ from = "MARC-8";
}
+ else
+ from = "ISO-8859-1";
+ }
+ else if (marcCharset)
+ from = marcCharset;
+ if (outputCharset && from)
+ {
+ cd = yaz_iconv_open(outputCharset, from);
+ printf ("convert from %s to %s", from,
+ outputCharset);
if (!cd)
- fwrite (result, 1, rlen, stdout);
+ printf (" unsupported\n");
else
{
- char outbuf[6];
- size_t inbytesleft = rlen;
- const char *inp = result;
-
- while (inbytesleft)
- {
- size_t outbytesleft = sizeof(outbuf);
- char *outp = outbuf;
- size_t r;
-
- 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);
- }
+ yaz_marc_iconv(mt, cd);
+ printf ("\n");
}
}
+
+ if (yaz_marc_decode_buf(mt, octet_buf,r->u.octet_aligned->len,
+ &result, &rlen)> 0)
+ {
+ fwrite (result, rlen, 1, stdout);
+ }
else
{
printf ("bad MARC. Dumping as it is:\n");
return 2;
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
static int send_srw(Z_SRW_PDU *sr)
{
const char *charset = negotiationCharset;
const char *host_port = cur_host;
- char *path = 0;
- char ctype[50];
- Z_SOAP_Handler h[2] = {
- {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
- {0, 0, 0}
- };
- ODR o = odr_createmem(ODR_ENCODE);
- int ret;
- Z_SOAP *p = odr_malloc(o, sizeof(*p));
Z_GDU *gdu;
+ char *path = 0;
- path = odr_malloc(out, strlen(databaseNames[0])+2);
+ path = odr_malloc(out, 2+strlen(databaseNames[0]));
*path = '/';
strcpy(path+1, databaseNames[0]);
- gdu = z_get_HTTP_Request(out);
- gdu->u.HTTP_Request->version = http_version;
- gdu->u.HTTP_Request->path = odr_strdup(out, path);
+ gdu = z_get_HTTP_Request_host_path(out, host_port, path);
- if (host_port)
+ if (!strcmp(sru_method, "get"))
{
- const char *cp0 = strstr(host_port, "://");
- const char *cp1 = 0;
- if (cp0)
- cp0 = cp0+3;
- else
- cp0 = host_port;
-
- cp1 = strchr(cp0, '/');
- if (!cp1)
- cp1 = cp0+strlen(cp0);
-
- if (cp0 && cp1)
- {
- char *h = odr_malloc(out, cp1 - cp0 + 1);
- memcpy (h, cp0, cp1 - cp0);
- h[cp1-cp0] = '\0';
- z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
- "Host", h);
- }
+ yaz_sru_get_encode(gdu->u.HTTP_Request, sr, out, charset);
}
-
- strcpy(ctype, "text/xml");
- if (charset && strlen(charset) < 20)
+ else if (!strcmp(sru_method, "post"))
{
- strcat(ctype, "; charset=");
- strcat(ctype, charset);
+ yaz_sru_post_encode(gdu->u.HTTP_Request, sr, out, charset);
+ }
+ else if (!strcmp(sru_method, "soap"))
+ {
+ yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, out, charset);
}
- z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
- "Content-Type", ctype);
- z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
- "SOAPAction", "\"\"");
- p->which = Z_SOAP_generic;
- p->u.generic = odr_malloc(o, sizeof(*p->u.generic));
- p->u.generic->no = 0;
- p->u.generic->ns = 0;
- p->u.generic->p = sr;
- p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
-
- ret = z_soap_codec_enc(o, &p,
- &gdu->u.HTTP_Request->content_buf,
- &gdu->u.HTTP_Request->content_len, h,
- charset);
if (z_GDU(out, &gdu, 0, 0))
{
if (apdu_file)
{
if (!z_GDU(print, &gdu, 0, 0))
- printf ("Failed to print outgoing APDU\n");
+ printf ("Failed to print outgoing SRU package\n");
odr_reset(print);
}
buf_out = odr_getbuf(out, &len_out, 0);
r = cs_put(conn, buf_out, len_out);
- odr_destroy(o);
-
if (r >= 0)
return 2;
}
}
#endif
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
static char *encode_SRW_term(ODR o, const char *q)
{
const char *in_charset = "ISO-8859-1";
if (record_schema)
sr->u.request->recordSchema = record_schema;
if (recordsyntax_size == 1 && recordsyntax_list[0] == VAL_TEXT_XML)
- sr->u.explain_request->recordPacking = "xml";
+ sr->u.request->recordPacking = "xml";
return send_srw(sr);
}
#endif
last_hit_count = *res->resultCount;
if (setnumber >= 0)
printf (", setno %d", setnumber);
- printf ("\n");
+ putchar('\n');
+ if (res->resultSetStatus)
+ {
+ printf("Result Set Status: ");
+ switch(*res->resultSetStatus)
+ {
+ case Z_SearchResponse_subset:
+ printf("subset"); break;
+ case Z_SearchResponse_interim:
+ printf("interim"); break;
+ case Z_SearchResponse_none:
+ printf("none"); break;
+ case Z_SearchResponse_estimate:
+ printf("estimate"); break;
+ default:
+ printf("%d", *res->resultSetStatus);
+ }
+ putchar('\n');
+ }
display_searchResult (res->additionalSearchInfo);
printf("records returned: %d\n",
*res->numberOfRecordsReturned);
return 0;
}
-static Z_External *create_external_itemRequest()
+static Z_External *create_external_itemRequest(void)
{
struct ill_get_ctl ctl;
ILL_ItemRequest *req;
Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
oident ItemOrderRequest;
+
+ req->referenceId = set_refid (out);
+
ItemOrderRequest.proto = PROTO_Z3950;
ItemOrderRequest.oclass = CLASS_EXTSERV;
ItemOrderRequest.value = VAL_ITEMORDER;
return 0;
}
-static int only_z3950()
+static int only_z3950(void)
{
if (!conn)
{
return cmd_update_common(arg, 0);
}
+static int cmd_update_Z3950(int version, int action_no, const char *recid,
+ char *rec_buf, int rec_len);
+
+static int cmd_update_SRW(int action_no, const char *recid,
+ char *rec_buf, int rec_len);
+
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;
char action[20], recid[20];
char *rec_buf;
int rec_len;
int action_no;
int noread = 0;
- Z_External *record_this = 0;
- if (only_z3950())
- return 1;
*action = 0;
*recid = 0;
sscanf (arg, "%19s %19s%n", action, recid, &noread);
if (parse_cmd_doc(&arg, out, &rec_buf, &rec_len, 1) == 0)
return 0;
+#if YAZ_HAVE_XML2
+ if (protocol == PROTO_HTTP)
+ return cmd_update_SRW(action_no, recid, rec_buf, rec_len);
+#endif
+ return cmd_update_Z3950(version, action_no, recid, rec_buf, rec_len);
+}
+
+#if YAZ_HAVE_XML2
+static int cmd_update_SRW(int action_no, const char *recid,
+ char *rec_buf, int rec_len)
+{
+ if (!conn)
+ cmd_open(0);
+ if (!conn)
+ return 0;
+ else
+ {
+ Z_SRW_PDU *srw = yaz_srw_get(out, Z_SRW_update_request);
+ Z_SRW_updateRequest *sr = srw->u.update_request;
+
+ switch(action_no)
+ {
+ case Z_IUOriginPartToKeep_recordInsert:
+ sr->operation = "info:srw/action/1/create";
+ break;
+ case Z_IUOriginPartToKeep_recordReplace:
+ sr->operation = "info:srw/action/1/replace";
+ break;
+ case Z_IUOriginPartToKeep_recordDelete:
+ sr->operation = "info:srw/action/1/delete";
+ break;
+ }
+ if (rec_buf)
+ {
+ sr->record = yaz_srw_get_record(out);
+ sr->record->recordData_buf = rec_buf;
+ sr->record->recordData_len = rec_len;
+ sr->record->recordSchema = record_schema;
+ }
+ if (recid)
+ sr->recordId = odr_strdup(out, recid);
+ return send_srw(srw);
+ }
+}
+#endif
+
+static int cmd_update_Z3950(int version, int action_no, const char *recid,
+ char *rec_buf, int rec_len)
+{
+ Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
+ Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+ Z_External *r;
+ Z_External *record_this = 0;
+
if (rec_buf)
record_this = z_ext_record (out, VAL_TEXT_XML, rec_buf, rec_len);
else
notToKeep->elements[0] = (Z_IU0SuppliedRecords_elem *)
odr_malloc(out, sizeof(**notToKeep->elements));
notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
- if (*recid)
+ if (*recid && strcmp(recid, "none"))
{
notToKeep->elements[0]->u.opaque = (Odr_oct *)
odr_malloc (out, sizeof(Odr_oct));
return 1;
else
{
+ char *asn_buf = 0;
int noread = 0;
char oid_str[51];
int oid_value_xmles = VAL_XMLES;
Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+
Z_External *ext = (Z_External *) odr_malloc(out, sizeof(*ext));
+ req->referenceId = set_refid (out);
req->taskSpecificParameters = ext;
ext->indirect_reference = 0;
ext->descriptor = 0;
printf("Bad OID: %s\n", oid_str);
return 0;
}
-
- if (parse_cmd_doc(&arg, out, (char **) &ext->u.single_ASN1_type->buf,
+
+ if (parse_cmd_doc(&arg, out, &asn_buf,
&ext->u.single_ASN1_type->len, 0) == 0)
return 0;
+
+ ext->u.single_ASN1_type->buf = (unsigned char *) asn_buf;
+
req->packageType = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
oid_value_xmles);
{
if (protocol != PROTO_HTTP)
return 0;
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (conn)
return 2;
}
+static int cmd_sru(const char *arg)
+{
+ if (!*arg)
+ {
+ printf("SRU method is: %s\n", sru_method);
+ }
+ else
+ {
+ if (!yaz_matchstr(arg, "post"))
+ sru_method = "post";
+ else if (!yaz_matchstr(arg, "get"))
+ sru_method = "get";
+ else if (!yaz_matchstr(arg, "soap"))
+ sru_method = "soap";
+ else
+ {
+ printf("Unknown SRU method: %s\n", arg);
+ printf("Specify one of POST, GET, SOAP\n");
+ }
+ }
+ return 0;
+}
+
static int cmd_find(const char *arg)
{
if (!*arg)
}
if (protocol == PROTO_HTTP)
{
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (!conn)
return 2;
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
static int send_SRW_presentRequest(const char *arg)
{
char setstring[100];
{
if (protocol == PROTO_HTTP)
{
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (!conn)
return 2;
}
+void exit_client(int code)
+{
+ file_history_save(file_history);
+ file_history_destroy(&file_history);
+ exit(code);
+}
+
int cmd_quit(const char *arg)
{
printf("See you later, alligator.\n");
xmalloc_trav ("");
- exit(0);
+ exit_client(0);
return 0;
}
{
if (protocol == PROTO_HTTP)
{
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (!conn)
return 1;
}
-void source_rcfile()
+void source_rcfile(void)
{
/* Look for a $HOME/.yazclientrc and source it if it exists */
struct stat statbuf;
- char buffer[1000];
- char* homedir=getenv("HOME");
+ char fname[1000];
+ char* homedir = getenv("HOME");
- if( homedir ) {
-
- sprintf(buffer,"%s/.yazclientrc",homedir);
+ sprintf(fname, "%.500s%s%s", homedir ? homedir : "",
+ homedir ? "/" : "",
+ ".yazclientrc");
- if(stat(buffer,&statbuf)==0) {
- cmd_source(buffer, 0 );
- }
-
- };
-
- if(stat(".yazclientrc",&statbuf)==0) {
- cmd_source(".yazclientrc", 0 );
- }
+ if (stat(fname,&statbuf)==0)
+ cmd_source(fname, 0 );
}
+void add_to_readline_history(void *client_data, const char *line)
+{
+#if HAVE_READLINE_HISTORY_H
+ if (strlen(line))
+ add_history(line);
+#endif
+}
static void initialize(void)
{
}
source_rcfile();
+
+ file_history = file_history_new();
+ file_history_load(file_history);
+ file_history_trav(file_history, 0, add_to_readline_history);
}
struct timeval tv_start;
#endif
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
static void handle_srw_record(Z_SRW_record *rec)
{
if (rec->recordPosition)
{
Z_SOAP *soap_package = 0;
ODR o = odr_createmem(ODR_DECODE);
- Z_SOAP_Handler soap_handlers[2] = {
- {"http://www.loc.gov/zing/srw/", 0,
- (Z_SOAP_fun) yaz_srw_codec},
+ Z_SOAP_Handler soap_handlers[3] = {
+ {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
+ {YAZ_XMLNS_UPDATE_v0_9, 0, (Z_SOAP_fun) yaz_ucp_codec},
{0, 0, 0}
};
ret = z_soap_codec(o, &soap_package,
&hres->content_buf, &hres->content_len,
soap_handlers);
- if (!ret && soap_package->which == Z_SOAP_generic &&
- soap_package->u.generic->no == 0)
+ if (!ret && soap_package->which == Z_SOAP_generic)
{
Z_SRW_PDU *sr = soap_package->u.generic->p;
if (sr->which == Z_SRW_searchRetrieve_response)
handle_srw_explain_response(sr->u.explain_response);
else if (sr->which == Z_SRW_scan_response)
handle_srw_scan_response(sr->u.scan_response);
+ else if (sr->which == Z_SRW_update_response)
+ printf("Got update response. Status: %s\n",
+ sr->u.update_response->operationStatus);
else
ret = -1;
}
else if (soap_package && (soap_package->which == Z_SOAP_fault
- || soap_package->which == Z_SOAP_error))
+ || soap_package->which == Z_SOAP_error))
{
printf ("HTTP Error Status=%d\n", hres->code);
printf ("SOAP Fault code %s\n",
soap_package->u.fault->details);
}
else
+ {
+ printf("z_soap_codec failed. (no SOAP error)\n");
ret = -1;
+ }
odr_destroy(o);
}
if (ret)
close_session ();
}
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
else if (gdu->which == Z_GDU_HTTP_Response)
{
http_response(gdu->u.HTTP_Response);
{"attributeset", cmd_attributeset, "<attrset>",complete_attributeset,0,NULL},
{"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
{"refid", cmd_refid, "<id>",NULL,0,NULL},
- {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
+ {"itemorder", cmd_itemorder, "ill|item|xml <itemno>",NULL,0,NULL},
{"update", cmd_update, "<action> <recid> [<doc>]",NULL,0,NULL},
{"update0", cmd_update0, "<action> <recid> [<doc>]",NULL,0,NULL},
{"xmles", cmd_xmles, "<OID> <doc>",NULL,0,NULL},
{"displaycharset", cmd_displaycharset, "<output_charset>",NULL,0,NULL},
{"marccharset", cmd_marccharset, "<charset_name>",NULL,0,NULL},
{"lang", cmd_lang, "<language_code>",NULL,0,NULL},
+ {"source", cmd_source_echo, "<filename>",NULL,1,NULL},
{".", cmd_source_echo, "<filename>",NULL,1,NULL},
{"!", cmd_subshell, "Subshell command",NULL,1,NULL},
{"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
{"zversion", cmd_zversion, "", NULL, 0, NULL},
{"help", cmd_help, "", NULL,0,NULL},
{"init", cmd_init, "", NULL,0,NULL},
+ {"sru", cmd_sru, "", NULL,0,NULL},
{"exit", cmd_quit, "",NULL,0,NULL},
{0,0,0,0,0,0}
};
}
#if HAVE_READLINE_READLINE_H
+static char** default_completer_list = NULL;
+
+static char* default_completer(const char* text, int state)
+{
+ return complete_from_list(default_completer_list, text, state);
+}
+#endif
+
+#if HAVE_READLINE_READLINE_H
/*
This function only known how to complete on the first word
return NULL;
}
- for (i = 0; cmd_array[i].cmd; i++) {
- if (!strncmp(cmd_array[i].cmd, word, strlen(word))) {
+ for (i = 0; cmd_array[i].cmd; i++)
+ if (!strncmp(cmd_array[i].cmd, word, strlen(word)))
break;
- }
- }
- if(!cmd_array[i].cmd) return NULL;
+ if(!cmd_array[i].cmd)
+ return NULL;
- curret_global_list = cmd_array[i].local_tabcompletes;
+ default_completer_list = cmd_array[i].local_tabcompletes;
completerToUse = cmd_array[i].rl_completerfunction;
- if (completerToUse==NULL)
+ if (!completerToUse)
{ /* if command completer is not defined use the default completer */
completerToUse = default_completer;
}
}
#endif
+#ifndef WIN32
+void ctrl_c_handler(int x)
+{
+ exit_client(0);
+}
+#endif
+
static void client(void)
{
char line[10240];
line[10239] = '\0';
+#ifndef WIN32
+ signal(SIGINT, ctrl_c_handler);
+#endif
+
#if HAVE_GETTIMEOFDAY
gettimeofday (&tv_start, 0);
#endif
if (*line_in)
add_history(line_in);
#endif
- strncpy(line, line_in, 10239);
+ strncpy(line, line_in, sizeof(line)-1);
free(line_in);
}
#endif
char *end_p;
printf (C_PROMPT);
fflush(stdout);
- if (!fgets(line, 10239, stdin))
+ if (!fgets(line, sizeof(line)-1, stdin))
break;
if ((end_p = strchr (line, '\n')))
*end_p = '\0';
}
+ if (isatty(0))
+ file_history_add_line(file_history, line);
process_cmd_line(line);
}
}
#endif
xfree(open_command);
}
- client ();
- exit (0);
+ client();
+ exit_client(0);
+ return 0;
}
/*
* Local variables: