+ return 1;
+}
+
+void source_rcfile()
+{
+ /* Look for a $HOME/.yazclientrc and source it if it exists */
+ struct stat statbuf;
+ char buffer[1000];
+ char* homedir=getenv("HOME");
+
+ if(!homedir) return;
+
+ sprintf(buffer,"%s/.yazclientrc",homedir);
+
+ if(stat(buffer,&statbuf)==0) {
+ cmd_source(buffer);
+ }
+
+ if(stat(".yazclientrc",&statbuf)==0) {
+ cmd_source(".yazclientrc");
+ }
+}
+
+
+static void initialize(void)
+{
+ FILE *inf;
+ int i;
+
+ if (!(out = odr_createmem(ODR_ENCODE)) ||
+ !(in = odr_createmem(ODR_DECODE)) ||
+ !(print = odr_createmem(ODR_PRINT)))
+ {
+ fprintf(stderr, "failed to allocate ODR streams\n");
+ exit(1);
+ }
+ oid_init();
+
+ setvbuf(stdout, 0, _IONBF, 0);
+ if (apdu_file)
+ odr_setprint(print, apdu_file);
+
+ bibset = ccl_qual_mk ();
+ inf = fopen (ccl_fields, "r");
+ if (inf)
+ {
+ ccl_qual_file (bibset, inf);
+ fclose (inf);
+ }
+
+ cqltrans = cql_transform_open_fname(cql_fields);
+ /* If this fails, no problem: we detect cqltrans == 0 later */
+
+#if HAVE_READLINE_READLINE_H
+ rl_attempted_completion_function = (CPPFunction*)readline_completer;
+#endif
+
+
+ for(i=0; i<maxOtherInfosSupported; ++i) {
+ extraOtherInfos[i].oidval = -1;
+ }
+
+ source_rcfile();
+}
+
+
+#if HAVE_GETTIMEOFDAY
+struct timeval tv_start, tv_end;
+#endif
+
+#if HAVE_XML2
+static void handle_srw_response(Z_SRW_searchRetrieveResponse *res)
+{
+ int i;
+
+ printf ("Received SRW SearchRetrieve Response\n");
+
+ for (i = 0; i<res->num_diagnostics; i++)
+ {
+ printf ("SRW diagnostic %d %s\n",
+ *res->diagnostics[i].code,
+ yaz_diag_srw_str(*res->diagnostics[i].code));
+
+ if (res->diagnostics[i].details)
+ printf ("Details: %s\n", res->diagnostics[i].details);
+ }
+ if (res->numberOfRecords)
+ printf ("Number of hits: %d\n", *res->numberOfRecords);
+ for (i = 0; i<res->num_records; i++)
+ {
+ Z_SRW_record *rec = res->records + i;
+
+ if (rec->recordPosition)
+ {
+ printf ("pos=%d", *rec->recordPosition);
+ setno = *rec->recordPosition + 1;
+ }
+ if (rec->recordSchema)
+ printf (" schema=%s", rec->recordSchema);
+ printf ("\n");
+ if (rec->recordData_buf && rec->recordData_len)
+ {
+ fwrite(rec->recordData_buf, 1, rec->recordData_len, stdout);
+ printf ("\n");
+ }
+ }
+}
+
+static void http_response(Z_HTTP_Response *hres)
+{
+ int ret = -1;
+ const char *content_type = z_HTTP_header_lookup(hres->headers,
+ "Content-Type");
+ const char *connection_head = z_HTTP_header_lookup(hres->headers,
+ "Connection");
+ if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
+ {
+ Z_SOAP *soap_package = 0;
+ ODR o = odr_createmem(ODR_DECODE);
+ Z_SOAP_Handler soap_handlers[2] = {
+ {"http://www.loc.gov/zing/srw/v1.0/", 0,
+ (Z_SOAP_fun) yaz_srw_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)
+ {
+ Z_SRW_PDU *sr = soap_package->u.generic->p;
+ if (sr->which == Z_SRW_searchRetrieve_response)
+ handle_srw_response(sr->u.response);
+ else
+ ret = -1;
+ }
+ else if (!ret && (soap_package->which == Z_SOAP_fault
+ || soap_package->which == Z_SOAP_error))
+ {
+ printf ("HTTP Error Status=%d\n", hres->code);
+ printf ("SOAP Fault code %s\n",
+ soap_package->u.fault->fault_code);
+ printf ("SOAP Fault string %s\n",
+ soap_package->u.fault->fault_string);
+ }
+ else
+ ret = -1;
+ odr_destroy(o);
+ }
+ if (ret)
+ {
+ if (hres->code != 200)
+ {
+ printf ("HTTP Error Status=%d\n", hres->code);
+ }
+ else
+ {
+ printf ("Decoding of SRW package failed\n");
+ }
+ close_session();
+ }
+ if (!strcmp(hres->version, "1.0"))
+ {
+ /* HTTP 1.0: only if Keep-Alive we stay alive.. */
+ if (!connection_head || strcmp(connection_head, "Keep-Alive"))
+ close_session();
+ }
+ else
+ {
+ /* HTTP 1.1: only if no close we stay alive .. */
+ if (connection_head && !strcmp(connection_head, "close"))
+ close_session();
+ }
+}
+#endif
+
+void wait_and_handle_response()
+{
+ int reconnect_ok = 1;
+ int res;
+ char *netbuffer= 0;
+ int netbufferlen = 0;
+ Z_GDU *gdu;
+
+ while(conn)
+ {
+ res = cs_get(conn, &netbuffer, &netbufferlen);
+ if (reconnect_ok && res <= 0 && protocol == PROTO_HTTP)
+ {
+ cs_close(conn);
+ conn = 0;
+ cmd_open(0);
+ reconnect_ok = 0;
+ if (conn)
+ {
+ char *buf_out;
+ int len_out;
+
+ buf_out = odr_getbuf(out, &len_out, 0);
+
+ cs_put(conn, buf_out, len_out);
+
+ odr_reset(out);
+ continue;
+ }
+ }
+ else if (res <= 0)
+ {
+ printf("Target closed connection\n");
+ close_session();
+ break;
+ }
+ odr_reset(out);
+ odr_reset(in); /* release APDU from last round */
+ record_last = 0;
+ do_hex_dump(netbuffer, res);
+ odr_setbuf(in, netbuffer, res, 0);
+
+ if (!z_GDU(in, &gdu, 0, 0))
+ {
+ FILE *f = ber_file ? ber_file : stdout;
+ odr_perror(in, "Decoding incoming APDU");
+ fprintf(f, "[Near %d]\n", 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);
+ if (conn && cs_more(conn))
+ continue;
+ break;
+ }
+ if (ber_file)
+ odr_dumpBER(ber_file, netbuffer, res);
+ if (apdu_file && !z_GDU(print, &gdu, 0, 0))
+ {
+ odr_perror(print, "Failed to print incoming APDU");
+ odr_reset(print);
+ continue;
+ }
+ if (gdu->which == Z_GDU_Z3950)
+ {
+ Z_APDU *apdu = gdu->u.z3950;
+ switch(apdu->which)
+ {
+ case Z_APDU_initResponse:
+ process_initResponse(apdu->u.initResponse);
+ break;
+ case Z_APDU_searchResponse:
+ process_searchResponse(apdu->u.searchResponse);
+ break;
+ case Z_APDU_scanResponse:
+ process_scanResponse(apdu->u.scanResponse);
+ break;
+ case Z_APDU_presentResponse:
+ print_refid (apdu->u.presentResponse->referenceId);
+ setno +=
+ *apdu->u.presentResponse->numberOfRecordsReturned;
+ if (apdu->u.presentResponse->records)
+ display_records(apdu->u.presentResponse->records);
+ else
+ printf("No records.\n");
+ printf ("nextResultSetPosition = %d\n",
+ *apdu->u.presentResponse->nextResultSetPosition);
+ break;
+ case Z_APDU_sortResponse:
+ process_sortResponse(apdu->u.sortResponse);
+ break;
+ case Z_APDU_extendedServicesResponse:
+ printf("Got extended services response\n");
+ process_ESResponse(apdu->u.extendedServicesResponse);
+ break;
+ case Z_APDU_close:
+ printf("Target has closed the association.\n");
+ process_close(apdu->u.close);
+ break;
+ case Z_APDU_resourceControlRequest:
+ process_resourceControlRequest
+ (apdu->u.resourceControlRequest);
+ break;
+ case Z_APDU_deleteResultSetResponse:
+ process_deleteResultSetResponse(apdu->u.
+ deleteResultSetResponse);
+ break;
+ default:
+ printf("Received unknown APDU type (%d).\n",
+ apdu->which);
+ close_session ();
+ }
+ }
+#if HAVE_XML2
+ else if (gdu->which == Z_GDU_HTTP_Response)
+ {
+ http_response(gdu->u.HTTP_Response);
+ }
+#endif
+ if (conn && !cs_more(conn))
+ break;
+ }
+ if (conn)
+ {
+#if HAVE_GETTIMEOFDAY
+ gettimeofday (&tv_end, 0);
+#if 0
+ printf ("S/U S/U=%ld/%ld %ld/%ld",
+ (long) tv_start.tv_sec,
+ (long) tv_start.tv_usec,
+ (long) tv_end.tv_sec,
+ (long) tv_end.tv_usec);
+#endif
+ printf ("Elapsed: %.6f\n",
+ (double) tv_end.tv_usec / 1e6 + tv_end.tv_sec -
+ ((double) tv_start.tv_usec / 1e6 + tv_start.tv_sec));
+#endif
+ }
+ xfree (netbuffer);
+}
+
+
+int cmd_cclparse(const char* arg)
+{
+ int error, pos;
+ struct ccl_rpn_node *rpn=NULL;
+
+
+ rpn = ccl_find_str (bibset, arg, &error, &pos);
+
+ if (error) {
+ printf ("%*s^ - ", 3+strlen(last_cmd)+1+pos, " ");
+ printf ("%s\n", ccl_err_msg (error));
+ }
+ else
+ {
+ if (rpn)
+ {
+ ccl_pr_tree(rpn, stdout);
+ }
+ }
+ if (rpn)
+ ccl_rpn_delete(rpn);
+
+ printf ("\n");
+
+ return 0;
+}
+
+
+int cmd_set_otherinfo(const char* args)
+{
+ char oid[101], otherinfoString[101];
+ int otherinfoNo;
+ int sscan_res;
+ int oidval;
+
+ sscan_res = sscanf (args, "%d %100[^ ] %100s", &otherinfoNo, oid, otherinfoString);
+ if(sscan_res==1) {
+ /* reset this otherinfo */
+ if(otherinfoNo>=maxOtherInfosSupported) {
+ printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
+ }
+ extraOtherInfos[otherinfoNo].oidval = -1;
+ if(extraOtherInfos[otherinfoNo].value) free(extraOtherInfos[otherinfoNo].value);
+ return 0;
+ }
+ if (sscan_res<3) {
+ printf("Error in set_otherinfo command \n");
+ return 0;
+ }
+
+ if(otherinfoNo>=maxOtherInfosSupported) {
+ printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
+ }
+
+
+ oidval = oid_getvalbyname (oid);
+ if(oidval == -1 ) {
+ printf("Error in set_otherinfo command unknown oid %s \n",oid);
+ return 0;
+ }
+ extraOtherInfos[otherinfoNo].oidval = oidval;
+ if(extraOtherInfos[otherinfoNo].value) free(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].value = strdup(otherinfoString);
+
+ return 0;
+}
+
+int cmd_list_otherinfo(const char* args)
+{
+ int i;
+
+ if(strlen(args)>0) {
+ i = atoi(args);
+ if( i >= maxOtherInfosSupported ) {
+ printf("Error otherinfo index to large (%d>%d)\n",i,maxOtherInfosSupported);
+ return 0;
+ }
+
+ if(extraOtherInfos[i].oidval != -1)
+ 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(
+ (enum oid_value) extraOtherInfos[i].oidval,
+ CLASS_RECSYN),
+ extraOtherInfos[i].value);
+ }
+
+ }
+ return 0;
+}
+
+
+int cmd_list_all(const char* args) {
+ int i;
+
+ /* connection options */
+ if(conn) {
+ printf("Connected to : %s\n",last_open_command);
+ } else {
+ if(last_open_command)
+ printf("Not connected to : %s\n",last_open_command);
+ else
+ printf("Not connected : \n");
+
+ }
+ if(yazProxy) printf("using proxy : %s\n",yazProxy);
+
+ printf("auto_reconnect : %s\n",auto_reconnect?"on":"off");
+
+ if (!auth) {
+ printf("Authentication : none\n");
+ } else {
+ switch(auth->which) {
+ case Z_IdAuthentication_idPass:
+ printf("Authentication : IdPass\n");
+ printf(" Login User : %s\n",auth->u.idPass->userId?auth->u.idPass->userId:"");
+ printf(" Login Group : %s\n",auth->u.idPass->groupId?auth->u.idPass->groupId:"");
+ printf(" Password : %s\n",auth->u.idPass->password?auth->u.idPass->password:"");
+ break;
+ case Z_IdAuthentication_open:
+ printf("Authentication : psOpen\n");
+ printf(" Open string : %s\n",auth->u.open);
+ break;
+ default:
+ printf("Authentication : Unknown\n");
+ }
+ }
+ if (negotiationCharset)
+ printf("Neg. Character set : `%s'\n", negotiationCharset);
+
+ /* bases */
+ printf("Bases : ");
+ for (i = 0; i<num_databaseNames; i++) printf("%s ",databaseNames[i]);
+ printf("\n");
+
+ /* Query options */
+ printf("CCL file : %s\n",ccl_fields);
+ printf("CQL file : %s\n",cql_fields);
+ printf("Query type : %s\n",query_type_as_string(queryType));
+
+ printf("Named Result Sets : %s\n",setnumber==-1?"off":"on");
+
+ /* piggy back options */
+ 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("Schema : %s\n",schema);
+ printf("Elements : %s\n",elementSetNames?elementSetNames->u.generic:"");
+
+ /* loging options */
+ printf("APDU log : %s\n",apdu_file?"on":"off");
+ printf("Record log : %s\n",marc_file?"on":"off");
+
+ /* other infos */
+ printf("Other Info: \n");
+ cmd_list_otherinfo("");
+
+ return 0;
+}
+
+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);
+ return 0;
+ }
+
+ if(extraOtherInfos[otherinfoNo].oidval != -1) {
+ /* only clear if set. */
+ extraOtherInfos[otherinfoNo].oidval=-1;
+ free(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);
+ }
+ }
+ }
+ return 0;
+}
+
+static int cmd_help (const char *line);
+
+typedef char *(*completerFunctionType)(const char *text, int state);
+
+static struct {
+ char *cmd;
+ int (*fun)(const char *arg);
+ char *ad;
+ completerFunctionType rl_completerfunction;
+ int complete_filenames;
+ char **local_tabcompletes;
+} cmd_array[] = {
+ {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
+ {"quit", cmd_quit, "",NULL,0,NULL},
+ {"find", cmd_find, "<query>",NULL,0,NULL},
+ {"delete", cmd_delete, "<setname>",NULL,0,NULL},
+ {"base", cmd_base, "<base-name>",NULL,0,NULL},
+ {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]",NULL,0,NULL},
+ {"scan", cmd_scan, "<term>",NULL,0,NULL},
+ {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+ {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+ {"authentication", cmd_authentication, "<acctstring>",NULL,0,NULL},
+ {"lslb", cmd_lslb, "<largeSetLowerBound>",NULL,0,NULL},
+ {"ssub", cmd_ssub, "<smallSetUpperBound>",NULL,0,NULL},
+ {"mspn", cmd_mspn, "<mediumSetPresentNumber>",NULL,0,NULL},
+ {"status", cmd_status, "",NULL,0,NULL},
+ {"setnames", cmd_setnames, "",NULL,0,NULL},
+ {"cancel", cmd_cancel, "",NULL,0,NULL},
+ {"format", cmd_format, "<recordsyntax>",complete_format,0,NULL},
+ {"schema", cmd_schema, "<schema>",complete_schema,0,NULL},
+ {"elements", cmd_elements, "<elementSetName>",NULL,0,NULL},
+ {"close", cmd_close, "",NULL,0,NULL},
+ {"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},
+ {"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, "<nego_charset> <output_charset>",NULL,0,NULL},
+ {"marccharset", cmd_marccharset, "<charset_name>",NULL,0,NULL},
+ {"lang", cmd_lang, "<language_code>",NULL,0,NULL},
+ {".", cmd_source, "<filename>",NULL,1,NULL},
+ {"!", cmd_subshell, "Subshell command",NULL,1,NULL},
+ {"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
+ {"set_berfile", cmd_set_berfile, "<filename>",NULL,1,NULL},
+ {"set_marcdump", cmd_set_marcdump," <filename>",NULL,1,NULL},
+ {"set_cclfile", cmd_set_cclfile," <filename>",NULL,1,NULL},
+ {"set_cqlfile", cmd_set_cqlfile," <filename>",NULL,1,NULL},
+ {"set_auto_reconnect", cmd_set_auto_reconnect," on|off",complete_auto_reconnect,1,NULL},
+ {"set_otherinfo", cmd_set_otherinfo,"<otherinfoinddex> <oid> <string>",NULL,0,NULL},
+ {"register_oid", cmd_register_oid,"<name> <class> <oid>",NULL,0,NULL},
+ {"push_command", cmd_push_command,"<command>",command_generator,0,NULL},
+ {"register_tab", cmd_register_tab,"<commandname> <tab>",command_generator,0,NULL},
+ {"cclparse", cmd_cclparse,"<ccl find command>",NULL,0,NULL},
+ {"list_otherinfo",cmd_list_otherinfo,"[otherinfoinddex]",NULL,0,NULL},
+ {"list_all",cmd_list_all,"",NULL,0,NULL},
+ {"clear_otherinfo",cmd_clear_otherinfo,"",NULL,0,NULL},
+ /* Server Admin Functions */
+ {"adm-reindex", cmd_adm_reindex, "<database-name>",NULL,0,NULL},
+ {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>",NULL,0,NULL},
+ {"adm-create", cmd_adm_create, "",NULL,0,NULL},
+ {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>",NULL,0,NULL},
+ {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>",NULL,0,NULL},
+ {"adm-refresh", cmd_adm_refresh, "",NULL,0,NULL},
+ {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
+ {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
+ {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},
+ {"help", cmd_help, "", NULL,0,NULL},
+ {0,0,0,0,0,0}
+};
+
+static int cmd_help (const char *line)
+{
+ int i;
+ char topic[21];
+
+ *topic = 0;
+ sscanf (line, "%20s", topic);
+
+ if (*topic == 0)
+ printf("Commands:\n");
+ for (i = 0; cmd_array[i].cmd; i++)
+ if (*topic == 0 || strcmp (topic, cmd_array[i].cmd) == 0)
+ printf(" %s %s\n", cmd_array[i].cmd, cmd_array[i].ad);
+ if (strcmp (topic, "find") == 0)
+ {
+ printf ("RPN:\n");
+ printf (" \"term\" Simple Term\n");
+ printf (" @attr [attset] type=value op Attribute\n");
+ printf (" @and opl opr And\n");
+ printf (" @or opl opr Or\n");
+ printf (" @not opl opr And-Not\n");
+ printf (" @set set Result set\n");
+ printf ("\n");
+ printf ("Bib-1 attribute types\n");
+ printf ("1=Use: ");
+ printf ("4=Title 7=ISBN 8=ISSN 30=Date 62=Abstract 1003=Author 1016=Any\n");
+ printf ("2=Relation: ");
+ printf ("1< 2<= 3= 4>= 5> 6!= 102=Relevance\n");
+ printf ("3=Position: ");
+ printf ("1=First in Field 2=First in subfield 3=Any position\n");
+ printf ("4=Structure: ");
+ printf ("1=Phrase 2=Word 3=Key 4=Year 5=Date 6=WordList\n");
+ printf ("5=Truncation: ");
+ printf ("1=Right 2=Left 3=L&R 100=No 101=# 102=Re-1 103=Re-2\n");
+ printf ("6=Completeness:");
+ printf ("1=Incomplete subfield 2=Complete subfield 3=Complete field\n");
+ }
+ return 1;
+}
+
+int cmd_register_tab(const char* arg) {