/*
- * Copyright (C) 1995-2005, Index Data ApS
+ * Copyright (C) 1995-2007, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: client.c,v 1.292 2005-06-25 15:46:01 adam Exp $
+ * $Id: client.c,v 1.328 2007-03-14 11:46:37 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 Z_ElementSetNames *elementSetNames = 0;
static int setno = 1; /* current set offset */
static enum oid_proto protocol = PROTO_Z3950; /* current app protocol */
-static enum oid_value recordsyntax = VAL_USMARC;
+#define RECORDSYNTAX_MAX 20
+static enum oid_value recordsyntax_list[RECORDSYNTAX_MAX] = { VAL_USMARC };
+static int recordsyntax_size = 1;
+
static char *record_schema = 0;
static int sent_close = 0;
static NMEM session_mem = NULL; /* memory handle for init-response */
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;
static int scan_position = 1;
static int scan_size = 20;
static char cur_host[200];
+static int last_hit_count = 0;
typedef enum {
QueryType_Prefix,
void process_cmd_line(char* line);
-char ** readline_completer(char *text, int start, int end);
-char *command_generator(const char *text, int state);
-char** curret_global_list=NULL;
+#if HAVE_READLINE_READLINE_H
+char **readline_completer(char *text, int start, int end);
+#endif
+static char *command_generator(const char *text, int state);
int cmd_register_tab(const char* arg);
static void close_session (void);
-ODR getODROutputStream()
+ODR getODROutputStream(void)
{
return out;
}
p0->which = Z_OtherInfo_externallyDefinedInfo;
p0->information.externallyDefinedInfo =
- yaz_set_proposal_charneg(
- out,
- (const char**)&negotiationCharset,
- negotiationCharset ? 1 : 0,
- (const char**)&yazLang, yazLang ? 1 : 0,
- negotiationCharsetRecords);
+ yaz_set_proposal_charneg_list(out, ",",
+ negotiationCharset,
+ yazLang,
+ negotiationCharsetRecords);
}
}
if (oid->value == VAL_OCLCUI) {
Z_OCLC_UserInformation *oclc_ui;
ODR decode = odr_createmem(ODR_DECODE);
- odr_setbuf(decode, sat->buf, sat->len, 0);
+ odr_setbuf(decode, (char *) sat->buf, sat->len, 0);
if (!z_OCLC_UserInformation(decode, &oclc_ui, 0, 0))
printf ("Bad OCLC UserInformation:\n");
else
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;
if (!(*type->fun)(in, &rr, 0, 0))
{
odr_perror(in, "Decoding constructed record.");
- fprintf(stdout, "[Near %d]\n", odr_offset(in));
+ fprintf(stdout, "[Near %ld]\n", (long) odr_offset(in));
fprintf(stdout, "Packet dump:\n---------\n");
odr_dumpBER(stdout, (char*)r->u.octet_aligned->buf,
r->u.octet_aligned->len);
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 == VAL_TEXT_XML)
- sr->u.explain_request->recordPacking = "xml";
+ if (recordsyntax_size == 1 && recordsyntax_list[0] == VAL_TEXT_XML)
+ sr->u.request->recordPacking = "xml";
return send_srw(sr);
}
#endif
if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
mediumSetPresentNumber > 0))
{
- req->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
-
+ if (recordsyntax_size > 0)
+ req->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax_list[0]);
req->smallSetElementSetNames =
req->mediumSetElementSetNames = elementSetNames;
}
const char *pqf_msg;
size_t off;
int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
- printf("%*s^\n", off+4, "");
+ int ioff = off;
+ printf("%*s^\n", ioff+4, "");
printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
yaz_pqf_destroy (pqf_parser);
}
/* display Query Expression as part of searchResult-1 */
-static void display_queryExpression (Z_QueryExpression *qe)
+static void display_queryExpression (const char *lead, Z_QueryExpression *qe)
{
if (!qe)
return;
+ printf(" %s=", lead);
if (qe->which == Z_QueryExpression_term)
{
if (qe->u.term->queryTerm)
switch (term->which)
{
case Z_Term_general:
- printf (" %.*s", term->u.general->len, term->u.general->buf);
+ printf ("%.*s", term->u.general->len, term->u.general->buf);
break;
case Z_Term_characterString:
- printf (" %s", term->u.characterString);
+ printf ("%s", term->u.characterString);
break;
case Z_Term_numeric:
- printf (" %d", *term->u.numeric);
+ printf ("%d", *term->u.numeric);
break;
case Z_Term_null:
- printf (" null");
+ printf ("null");
break;
}
}
printf ("SearchResult-1:");
for (j = 0; j < sr->num; j++)
{
+ if (j)
+ printf(",");
if (!sr->elements[j]->subqueryExpression)
- printf (" %d", j);
- display_queryExpression (
+ printf("%d", j);
+ display_queryExpression("term",
sr->elements[j]->subqueryExpression);
- display_queryExpression (
+ display_queryExpression("interpretation",
sr->elements[j]->subqueryInterpretation);
- display_queryExpression (
+ display_queryExpression("recommendation",
sr->elements[j]->subqueryRecommendation);
if (sr->elements[j]->subqueryCount)
- printf ("(%d)", *sr->elements[j]->subqueryCount);
+ printf(" cnt=%d", *sr->elements[j]->subqueryCount);
+ if (sr->elements[j]->subqueryId)
+ printf(" id=%s ", sr->elements[j]->subqueryId);
}
printf ("\n");
}
else
printf("Search was a bloomin' failure.\n");
printf("Number of hits: %d", *res->resultCount);
+ 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)
+ {
+ printf ("Not connected yet\n");
+ return 1;
+ }
if (protocol == PROTO_HTTP)
{
printf ("Not supported by SRW\n");
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 action[20], recid_buf[20];
+ const char *recid = 0;
char *rec_buf;
int rec_len;
int action_no;
int noread = 0;
- Z_External *record_this = 0;
- if (only_z3950())
- return 0;
*action = 0;
- *recid = 0;
- sscanf (arg, "%19s %19s%n", action, recid, &noread);
+ *recid_buf = 0;
+ sscanf (arg, "%19s %19s%n", action, recid_buf, &noread);
if (noread == 0)
{
- printf("Update must be followed by action and recid\n");
+ printf("Use: update action recid [fname]\n");
printf(" where action is one of insert,replace,delete.update\n");
- printf(" recid is some record ID (any string)\n");
+ printf(" recid is some record ID. Use none for no ID\n");
+ printf(" fname is file of record to be updated\n");
return 0;
}
return 0;
}
+ if (strcmp(recid_buf, "none")) /* none means no record ID */
+ recid = recid_buf;
+
arg += 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)
{
notToKeep->elements[0]->u.opaque = (Odr_oct *)
odr_malloc (out, sizeof(Odr_oct));
notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
odr_malloc(out, sizeof(**notToKeep->elements));
notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
- if (*recid)
+ if (recid)
{
notToKeep->elements[0]->u.opaque = (Odr_oct *)
odr_malloc (out, sizeof(Odr_oct));
static int cmd_xmles(const char *arg)
{
- 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->taskSpecificParameters = ext;
- ext->descriptor = 0;
- ext->which = Z_External_octet;
- ext->u.single_ASN1_type = (Odr_oct *) odr_malloc (out, sizeof(Odr_oct));
-
- sscanf(arg, "%50s%n", oid_str, &noread);
- if (noread == 0)
- {
- printf("Missing OID for xmles\n");
- return 0;
- }
- arg += noread;
- oid_value_xmles = oid_getvalbyname(oid_str);
- if (oid_value_xmles == VAL_NONE)
+ if (only_z3950())
+ return 1;
+ else
{
- printf("Bad OID: %s\n", oid_str);
- return 0;
- }
+ 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;
+
- if (parse_cmd_doc(&arg, out, (char **) &ext->u.single_ASN1_type->buf,
- &ext->u.single_ASN1_type->len, 0) == 0)
- return 0;
- req->packageType = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
- oid_value_xmles);
+ 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;
+ ext->which = Z_External_octet;
+ ext->u.single_ASN1_type = (Odr_oct *) odr_malloc (out, sizeof(Odr_oct));
+ sscanf(arg, "%50s%n", oid_str, &noread);
+ if (noread == 0)
+ {
+ printf("Missing OID for xmles\n");
+ return 0;
+ }
+ arg += noread;
+ oid_value_xmles = oid_getvalbyname(oid_str);
+ if (oid_value_xmles == VAL_NONE)
+ {
+ printf("Bad OID: %s\n", oid_str);
+ return 0;
+ }
- ext->direct_reference = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
- oid_value_xmles);
- send_apdu(apdu);
+ if (parse_cmd_doc(&arg, out, &asn_buf,
+ &ext->u.single_ASN1_type->len, 0) == 0)
+ return 0;
- return 2;
+ ext->u.single_ASN1_type->buf = (unsigned char *) asn_buf;
+
+ req->packageType = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
+ oid_value_xmles);
+
+ ext->direct_reference = yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
+ oid_value_xmles);
+ send_apdu(apdu);
+
+ return 2;
+ }
}
static int cmd_itemorder(const char *arg)
int itemno;
if (only_z3950())
- return 0;
+ return 1;
if (sscanf (arg, "%10s %d", type, &itemno) != 2)
return 0;
{
if (protocol != PROTO_HTTP)
return 0;
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (conn)
/* save this for later .. when fetching individual records */
sr = yaz_srw_get(out, Z_SRW_explain_request);
- if (recordsyntax == VAL_TEXT_XML)
+ if (recordsyntax_size > 0 && recordsyntax_list[0] == VAL_TEXT_XML)
sr->u.explain_request->recordPacking = "xml";
send_srw(sr);
return 2;
strncpy (cur_host, arg, sizeof(cur_host)-1);
cur_host[sizeof(cur_host)-1] = 0;
}
- if (!conn || protocol != PROTO_Z3950)
- return 0;
+ if (only_z3950())
+ return 1;
send_initRequest(cur_host);
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)
static int cmd_delete(const char *arg)
{
- if (!conn)
- {
- printf("Not connected yet\n");
- return 0;
- }
if (only_z3950())
return 0;
if (!send_deleteResultSetRequest(arg))
static int cmd_lslb(const char *arg)
{
- if (only_z3950())
- return 0;
if (!(largeSetLowerBound = atoi(arg)))
return 0;
return 1;
static int cmd_mspn(const char *arg)
{
- if (only_z3950())
- return 0;
if (!(mediumSetPresentNumber = atoi(arg)))
return 0;
return 1;
*p = '\0';
}
if (*arg)
- *start = atoi(arg);
+ {
+ if (!strcmp(arg, "all"))
+ {
+ *number = last_hit_count;
+ *start = 1;
+ }
+ else
+ *start = atoi(arg);
+ }
if (p && (p=strchr(p+1, '+')))
strcpy (setstring, p+1);
else if (setnumber >= 0)
req->resultSetStartPoint = &setno;
req->numberOfRecordsRequested = &nos;
- req->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
+ if (recordsyntax_size == 1)
+ req->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax_list[0]);
- if (record_schema)
+ if (record_schema || recordsyntax_size >= 2)
{
req->recordComposition = &compo;
compo.which = Z_RecordComp_complex;
compo.u.complex->generic = (Z_Specification *)
odr_malloc(out, sizeof(*compo.u.complex->generic));
+
compo.u.complex->generic->which = Z_Schema_oid;
-
- compo.u.complex->generic->schema.oid =
- yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
-
- if (!compo.u.complex->generic->schema.oid)
+ if (!record_schema)
+ compo.u.complex->generic->schema.oid = 0;
+ else
{
- /* OID wasn't a schema! Try record syntax instead. */
- compo.u.complex->generic->schema.oid = (Odr_oid *)
- yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+ compo.u.complex->generic->schema.oid =
+ yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
+
+ if (!compo.u.complex->generic->schema.oid)
+ {
+ /* OID wasn't a schema! Try record syntax instead. */
+ compo.u.complex->generic->schema.oid = (Odr_oid *)
+ yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+ }
}
if (!elementSetNames)
compo.u.complex->generic->elementSpec = 0;
}
compo.u.complex->num_dbSpecific = 0;
compo.u.complex->dbSpecific = 0;
- compo.u.complex->num_recordSyntax = 0;
- compo.u.complex->recordSyntax = 0;
+ if (recordsyntax_size >= 2)
+ {
+ int i;
+ compo.u.complex->num_recordSyntax = recordsyntax_size;
+ compo.u.complex->recordSyntax = (Odr_oid **)
+ odr_malloc(out, recordsyntax_size * sizeof(Odr_oid*));
+ for (i = 0; i < recordsyntax_size; i++)
+ compo.u.complex->recordSyntax[i] =
+ yaz_oidval_to_z3950oid(out, CLASS_RECSYN,
+ recordsyntax_list[i]);
+ }
+ else
+ {
+ compo.u.complex->num_recordSyntax = 0;
+ compo.u.complex->recordSyntax = 0;
+ }
}
else if (elementSetNames)
{
return 2;
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
static int send_SRW_presentRequest(const char *arg)
{
char setstring[100];
sr->u.request->maximumRecords = odr_intdup(out, nos);
if (record_schema)
sr->u.request->recordSchema = record_schema;
- if (recordsyntax == VAL_TEXT_XML)
+ if (recordsyntax_size == 1 && recordsyntax_list[0] == VAL_TEXT_XML)
sr->u.request->recordPacking = "xml";
return send_srw(sr);
}
odr_reset(out);
odr_reset(in);
odr_reset(print);
+ last_hit_count = 0;
}
void process_close(Z_Close *req)
{
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;
}
Z_TriggerResourceControlRequest *req =
apdu->u.triggerResourceControlRequest;
bool_t rfalse = 0;
-
- if (!conn)
- {
- printf("Session not initialized yet\n");
- return 0;
- }
+ char command[16];
+
+ *command = '\0';
+ sscanf(arg, "%15s", command);
+
if (only_z3950())
return 0;
if (session_initResponse &&
send_apdu(apdu);
printf("Sent cancel request\n");
- return 2;
+ if (!strcmp(command, "wait"))
+ return 2;
+ return 1;
}
const char *pqf_msg;
size_t off;
int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
- printf("%*s^\n", off+7, "");
+ int ioff = off;
+ printf("%*s^\n", ioff+7, "");
printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
yaz_pqf_destroy (pqf_parser);
return -1;
int cmd_sort_generic(const char *arg, int newset)
{
- if (!conn)
- {
- printf("Session not initialized yet\n");
- return 0;
- }
if (only_z3950())
return 0;
if (session_initResponse &&
{
if (protocol == PROTO_HTTP)
{
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
if (!conn)
cmd_open(0);
if (!conn)
int cmd_format(const char *arg)
{
- oid_value nsyntax;
+ const char *cp = arg;
+ int nor;
+ int idx = 0;
+ oid_value nsyntax[RECORDSYNTAX_MAX];
+ char form_str[41];
if (!arg || !*arg)
{
printf("Usage: format <recordsyntax>\n");
return 0;
}
- nsyntax = oid_getvalbyname (arg);
- if (strcmp(arg, "none") && nsyntax == VAL_NONE)
+ while (sscanf(cp, "%40s%n", form_str, &nor) >= 1 && nor > 0
+ && idx < RECORDSYNTAX_MAX)
{
- printf ("unknown record syntax\n");
- return 0;
+ nsyntax[idx] = oid_getvalbyname(form_str);
+ if (!strcmp(form_str, "none"))
+ break;
+ if (nsyntax[idx] == VAL_NONE)
+ {
+ printf ("unknown record syntax: %s\n", form_str);
+ return 0;
+ }
+ cp += nor;
+ idx++;
}
- recordsyntax = nsyntax;
+ recordsyntax_size = idx;
+ memcpy(recordsyntax_list, nsyntax, idx * sizeof(*nsyntax));
return 1;
}
{
Z_APDU *apdu;
Z_Close *req;
- if (!conn)
- return 0;
if (only_z3950())
return 0;
-
apdu = zget_APDU(out, Z_APDU_close);
req = apdu->u.close;
*req->closeReason = Z_Close_finished;
int cmd_proxy(const char* arg)
{
- xfree (yazProxy);
- yazProxy = NULL;
+ xfree(yazProxy);
+ yazProxy = 0;
if (*arg)
yazProxy = xstrdup (arg);
return 1;
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)
{
#if HAVE_READLINE_READLINE_H
rl_attempted_completion_function = (CPPFunction*)readline_completer;
#endif
-
-
- for(i=0; i<maxOtherInfosSupported; ++i) {
+ for(i = 0; i < maxOtherInfosSupported; ++i) {
extraOtherInfos[i].oidval = -1;
}
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)
{
FILE *f = ber_file ? ber_file : stdout;
odr_perror(in, "Decoding incoming APDU");
- fprintf(f, "[Near %d]\n", odr_offset(in));
+ fprintf(f, "[Near %ld]\n", (long) odr_offset(in));
fprintf(f, "Packet dump:\n---------\n");
odr_dumpBER(f, netbuffer, res);
fprintf(f, "---------\n");
close_session ();
}
}
-#if HAVE_XML2
+#if YAZ_HAVE_XML2
else if (gdu->which == Z_GDU_HTTP_Response)
{
http_response(gdu->u.HTTP_Response);
rpn = ccl_find_str (bibset, arg, &error, &pos);
if (error) {
- printf ("%*s^ - ", 3+strlen(last_cmd)+1+pos, " ");
+ int ioff = 3+strlen(last_cmd)+1+pos;
+ printf ("%*s^ - ", ioff, " ");
printf ("%s\n", ccl_err_msg (error));
}
else
int sscan_res;
int oidval;
- sscan_res = sscanf (args, "%d %100[^ ] %100s", &otherinfoNo, oidstr, otherinfoString);
+ sscan_res = sscanf (args, "%d %100[^ ] %100s",
+ &otherinfoNo, oidstr, otherinfoString);
if (sscan_res==1) {
/* reset this otherinfo */
if(otherinfoNo>=maxOtherInfosSupported) {
}
extraOtherInfos[otherinfoNo].oidval = -1;
if (extraOtherInfos[otherinfoNo].value)
- free(extraOtherInfos[otherinfoNo].value);
+ xfree(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].value = 0;
return 0;
}
if (sscan_res<3) {
}
if (otherinfoNo>=maxOtherInfosSupported) {
- printf("Error otherinfo index to large (%d>%d)\n",
+ printf("Error otherinfo index too large (%d>=%d)\n",
otherinfoNo,maxOtherInfosSupported);
}
oidval = oid_getvalbyname (oidstr);
- if (oidval == -1 ) {
+ if (oidval == VAL_NONE)
+ {
printf("Error in set_otherinfo command unknown oid %s \n",oidstr);
return 0;
}
extraOtherInfos[otherinfoNo].oidval = oidval;
- if(extraOtherInfos[otherinfoNo].value) free(extraOtherInfos[otherinfoNo].value);
- extraOtherInfos[otherinfoNo].value = strdup(otherinfoString);
+ if (extraOtherInfos[otherinfoNo].value)
+ xfree(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].value = xstrdup(otherinfoString);
return 0;
}
printf("ssub/lslb/mspn : %d/%d/%d\n",smallSetUpperBound,largeSetLowerBound,mediumSetPresentNumber);
/* print present related options */
- printf("Format : %s\n",yaz_z3950_oid_value_to_str(recordsyntax,CLASS_RECSYN));
+ printf("Format : %s\n",
+ (recordsyntax_size > 0) ?
+ yaz_z3950_oid_value_to_str(recordsyntax_list[0], CLASS_RECSYN) :
+ "none");
printf("Schema : %s\n",record_schema ? record_schema : "not set");
printf("Elements : %s\n",elementSetNames?elementSetNames->u.generic:"");
int cmd_clear_otherinfo(const char* args)
{
if(strlen(args)>0) {
- int otherinfoNo;
- otherinfoNo = atoi(args);
- if( otherinfoNo >= maxOtherInfosSupported ) {
- printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
+ int otherinfoNo = atoi(args);
+ if (otherinfoNo >= maxOtherInfosSupported) {
+ printf("Error otherinfo index too large (%d>=%d)\n",
+ otherinfoNo, maxOtherInfosSupported);
return 0;
}
-
- if(extraOtherInfos[otherinfoNo].oidval != -1) {
+ if (extraOtherInfos[otherinfoNo].oidval != -1)
+ {
/* only clear if set. */
- extraOtherInfos[otherinfoNo].oidval=-1;
- free(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].oidval = -1;
+ xfree(extraOtherInfos[otherinfoNo].value);
}
} else {
int i;
-
- for(i=0; i<maxOtherInfosSupported; ++i) {
- if (extraOtherInfos[i].oidval!=-1 ) {
- extraOtherInfos[i].oidval=-1;
- free(extraOtherInfos[i].value);
+ for(i = 0; i < maxOtherInfosSupported; ++i)
+ {
+ if (extraOtherInfos[i].oidval != -1)
+ {
+ extraOtherInfos[i].oidval = -1;
+ xfree(extraOtherInfos[i].value);
}
}
}
{"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}
};
return 1;
}
-int cmd_register_tab(const char* arg) {
-
+int cmd_register_tab(const char* arg)
+{
+#if HAVE_READLINE_READLINE_H
char command[101], tabargument[101];
int i;
int num_of_tabs;
}
}
- if(!cmd_array[i].cmd) {
+ if (!cmd_array[i].cmd) {
fprintf(stderr,"Unknown command %s\n",command);
return 1;
}
- if(!cmd_array[i].local_tabcompletes)
+ if (!cmd_array[i].local_tabcompletes)
cmd_array[i].local_tabcompletes = (char **) calloc(1,sizeof(char**));
num_of_tabs=0;
tabslist = cmd_array[i].local_tabcompletes;
- for(;tabslist && *tabslist;tabslist++) {
+ for(; tabslist && *tabslist; tabslist++) {
num_of_tabs++;
}
- cmd_array[i].local_tabcompletes = (char **)
- realloc(cmd_array[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
- tabslist=cmd_array[i].local_tabcompletes;
- tabslist[num_of_tabs]=strdup(tabargument);
- tabslist[num_of_tabs+1]=NULL;
+ cmd_array[i].local_tabcompletes = (char **)
+ realloc(cmd_array[i].local_tabcompletes,
+ (num_of_tabs+2)*sizeof(char**));
+ tabslist = cmd_array[i].local_tabcompletes;
+ tabslist[num_of_tabs] = strdup(tabargument);
+ tabslist[num_of_tabs+1] = NULL;
+#endif
return 1;
}
void process_cmd_line(char* line)
{
- int i,res;
+ int i, res;
char word[32], arg[10240];
#if HAVE_GETTIMEOFDAY
fflush(marc_file);
}
-
-char *command_generator(const char *text, int state)
+static char *command_generator(const char *text, int state)
{
+#if HAVE_READLINE_READLINE_H
static int idx;
if (state==0) {
idx = 0;
}
for( ; cmd_array[idx].cmd; ++idx) {
- if (!strncmp(cmd_array[idx].cmd,text,strlen(text))) {
+ if (!strncmp(cmd_array[idx].cmd, text, strlen(text))) {
++idx; /* skip this entry on the next run */
return strdup(cmd_array[idx-1].cmd);
}
}
+#endif
return NULL;
}
+#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
*/
-char ** readline_completer(char *text, int start, int end) {
-#if HAVE_READLINE_READLINE_H
-
- completerFunctionType completerToUse;
-
+char **readline_completer(char *text, int start, int end)
+{
+ completerFunctionType completerToUse;
+
if(start == 0) {
#if HAVE_READLINE_RL_COMPLETION_MATCHES
- char** res=rl_completion_matches(text,
- command_generator);
+ char** res = rl_completion_matches(text, command_generator);
#else
- char** res=completion_matches(text,
- (CPFunction*)command_generator);
+ char** res = completion_matches(text,
+ (CPFunction*)command_generator);
#endif
rl_attempted_completion_over = 1;
return res;
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 no pr. command completer is defined use the default completer */
+ if (!completerToUse)
+ { /* if command completer is not defined use the default completer */
completerToUse = default_completer;
-
- if(completerToUse) {
+ }
+ if (completerToUse) {
#ifdef HAVE_READLINE_RL_COMPLETION_MATCHES
char** res=
- rl_completion_matches(text,
- completerToUse);
+ rl_completion_matches(text, completerToUse);
#else
char** res=
- completion_matches(text,
- (CPFunction*)completerToUse);
+ completion_matches(text, (CPFunction*)completerToUse);
#endif
- if(!cmd_array[i].complete_filenames)
+ if (!cmd_array[i].complete_filenames)
rl_attempted_completion_over = 1;
return res;
} else {
- if(!cmd_array[i].complete_filenames)
+ if (!cmd_array[i].complete_filenames)
rl_attempted_completion_over = 1;
return 0;
}
}
-#else
- return 0;
-#endif
}
+#endif
+#ifndef WIN32
+void ctrl_c_handler(int x)
+{
+ exit_client(0);
+}
+#endif
static void client(void)
{
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);
- free (line_in);
+ strncpy(line, line_in, sizeof(line)-1);
+ free(line_in);
}
#endif
if (!line_in)
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);
}
}
hex_dump = 1;
break;
case 'p':
- yazProxy=strdup(arg);
+ yazProxy = xstrdup(arg);
break;
case 'u':
if (!auth_command)
#endif
xfree(open_command);
}
- client ();
- exit (0);
+ client();
+ exit_client(0);
+ return 0;
}
/*
* Local variables: