+ req->attributeSet =
+ yaz_string_to_oid_odr(yaz_oid_std(),
+ CLASS_ATTSET, "Bib-1", out);
+ if (!(req->termListAndStartPoint = ccl_scan_query(out, rpn)))
+ {
+ printf("Couldn't convert CCL to Scan term\n");
+ return -1;
+ }
+ ccl_rpn_delete(rpn);
+ }
+ else
+ {
+ YAZ_PQF_Parser pqf_parser = yaz_pqf_create();
+
+
+ if (!(req->termListAndStartPoint =
+ yaz_pqf_scan(pqf_parser, out, &req->attributeSet, query)))
+ {
+ const char *pqf_msg;
+ size_t off;
+ int code = yaz_pqf_error(pqf_parser, &pqf_msg, &off);
+ 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;
+ }
+ yaz_pqf_destroy(pqf_parser);
+ }
+ if (queryCharset && outputCharset)
+ {
+ yaz_iconv_t cd = yaz_iconv_open(queryCharset, outputCharset);
+ if (!cd)
+ {
+ printf("Conversion from %s to %s unsupported\n",
+ outputCharset, queryCharset);
+ return -1;
+ }
+ yaz_query_charset_convert_apt(req->termListAndStartPoint, out, cd);
+ yaz_iconv_close(cd);
+ }
+ if (term && *term)
+ {
+ if (req->termListAndStartPoint->term &&
+ req->termListAndStartPoint->term->which == Z_Term_general &&
+ req->termListAndStartPoint->term->u.general)
+ {
+ req->termListAndStartPoint->term->u.general->buf =
+ (unsigned char *) odr_strdup(out, term);
+ req->termListAndStartPoint->term->u.general->len =
+ req->termListAndStartPoint->term->u.general->size =
+ strlen(term);
+ }
+ }
+ req->referenceId = set_refid(out);
+ req->num_databaseNames = num_databaseNames;
+ req->databaseNames = databaseNames;
+ req->numberOfTermsRequested = #
+ req->preferredPositionInResponse = pos;
+ req->stepSize = odr_intdup(out, scan_stepSize);
+
+ if (set)
+ yaz_oi_set_string_oid(&req->otherInfo, out,
+ yaz_oid_userinfo_scan_set, 1, set);
+
+ send_apdu(apdu);
+ return 2;
+}
+
+static int send_sortrequest(const char *arg, int newset)
+{
+ Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
+ Z_SortRequest *req = apdu->u.sortRequest;
+ Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
+ odr_malloc(out, sizeof(*sksl));
+ char setstring[32];
+
+ if (only_z3950())
+ return 0;
+ if (setnumber >= 0)
+ sprintf(setstring, "%d", setnumber);
+ else
+ sprintf(setstring, "default");
+
+ req->referenceId = set_refid(out);
+
+ req->num_inputResultSetNames = 1;
+ req->inputResultSetNames = (Z_InternationalString **)
+ odr_malloc(out, sizeof(*req->inputResultSetNames));
+ req->inputResultSetNames[0] = odr_strdup(out, setstring);
+
+ if (newset && setnumber >= 0)
+ sprintf(setstring, "%d", ++setnumber);
+
+ req->sortedResultSetName = odr_strdup(out, setstring);
+
+ req->sortSequence = yaz_sort_spec(out, arg);
+ if (!req->sortSequence)
+ {
+ printf("Missing sort specifications\n");
+ return -1;
+ }
+ send_apdu(apdu);
+ return 2;
+}
+
+static void display_term_info(Z_TermInfo *t)
+{
+ if (t->displayTerm)
+ printf("%s", t->displayTerm);
+ else if (t->term->which == Z_Term_general)
+ printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
+ else
+ printf("Term (not general)");
+ if (t->term->which == Z_Term_general)
+ sprintf(last_scan_line, "%.*s", t->term->u.general->len,
+ t->term->u.general->buf);
+
+ if (t->globalOccurrences)
+ printf(" (" ODR_INT_PRINTF ")\n", *t->globalOccurrences);
+ else
+ printf("\n");
+}
+
+static void process_Z3950_scanResponse(Z_ScanResponse *res)
+{
+ int i;
+ Z_Entry **entries = NULL;
+ int num_entries = 0;
+
+ printf("Received ScanResponse\n");
+ print_refid(res->referenceId);
+ printf(ODR_INT_PRINTF " entries", *res->numberOfEntriesReturned);
+ if (res->positionOfTerm)
+ printf(", position=" ODR_INT_PRINTF, *res->positionOfTerm);
+ printf("\n");
+ if (*res->scanStatus != Z_Scan_success)
+ printf("Scan returned code " ODR_INT_PRINTF "\n", *res->scanStatus);
+ if (!res->entries)
+ return;
+ if ((entries = res->entries->entries))
+ num_entries = res->entries->num_entries;
+ for (i = 0; i < num_entries; i++)
+ {
+ int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
+ if (entries[i]->which == Z_Entry_termInfo)
+ {
+ printf("%c ", i + 1 == pos_term ? '*' : ' ');
+ display_term_info(entries[i]->u.termInfo);
+ }
+ else
+ display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
+ }
+ if (res->entries->nonsurrogateDiagnostics)
+ display_diagrecs(res->entries->nonsurrogateDiagnostics,
+ res->entries->num_nonsurrogateDiagnostics);
+}
+
+static void process_Z3950_sortResponse(Z_SortResponse *res)
+{
+ printf("Received SortResponse: status=");
+ switch (*res->sortStatus)
+ {
+ case Z_SortResponse_success:
+ printf("success"); break;
+ case Z_SortResponse_partial_1:
+ printf("partial"); break;
+ case Z_SortResponse_failure:
+ printf("failure"); break;
+ default:
+ printf("unknown (" ODR_INT_PRINTF ")", *res->sortStatus);
+ }
+ printf("\n");
+ print_refid (res->referenceId);
+ if (res->diagnostics)
+ display_diagrecs(res->diagnostics,
+ res->num_diagnostics);
+}
+
+static void process_Z3950_deleteResultSetResponse(
+ Z_DeleteResultSetResponse *res)
+{
+ printf("Got deleteResultSetResponse status=" ODR_INT_PRINTF "\n",
+ *res->deleteOperationStatus);
+ if (res->deleteListStatuses)
+ {
+ int i;
+ for (i = 0; i < res->deleteListStatuses->num; i++)
+ {
+ printf("%s status=" ODR_INT_PRINTF "\n",
+ res->deleteListStatuses->elements[i]->id,
+ *res->deleteListStatuses->elements[i]->status);
+ }
+ }
+}
+
+static int cmd_sort_generic(const char *arg, int newset)
+{
+ if (only_z3950())
+ return 0;
+ if (session_initResponse &&
+ !ODR_MASK_GET(session_initResponse->options, Z_Options_sort))
+ {
+ printf("Target doesn't support sort\n");
+ return 0;
+ }
+ if (*arg)
+ {
+ if (send_sortrequest(arg, newset) < 0)
+ return 0;
+ return 2;
+ }
+ return 0;
+}
+
+static int cmd_sort(const char *arg)
+{
+ return cmd_sort_generic(arg, 0);
+}
+
+static int cmd_sort_newset(const char *arg)
+{
+ return cmd_sort_generic(arg, 1);
+}
+
+static int cmd_scanstep(const char *arg)
+{
+ scan_stepSize = atoi(arg);
+ return 0;
+}
+
+static int cmd_scanpos(const char *arg)
+{
+ if (!strcmp(arg, "none"))
+ strcpy(scan_position, "none");
+ else
+ {
+ int dummy;
+ int r = sscanf(arg, "%d", &dummy);
+ if (r == 1 && strlen(arg) < sizeof(scan_position)-1)
+ strcpy(scan_position, arg);
+ else
+ printf("specify number of none for scanpos\n");
+ }
+ return 0;
+}
+
+static int cmd_scansize(const char *arg)
+{
+ int r = sscanf(arg, "%d", &scan_size);
+ if (r == 0)
+ scan_size = 20;
+ return 0;
+}
+
+static int cmd_scan_common(const char *set, const char *arg)
+{
+ Odr_int pos, *pos_p = 0;
+ const char *scan_term = 0;
+ const char *scan_query = 0;
+
+ if (!*arg)
+ {
+ pos = 1;
+ pos_p = &pos;
+ scan_query = last_scan_query;
+ scan_term = last_scan_line;
+ }
+ else
+ {
+ strcpy(last_scan_query, arg);
+ scan_query = arg;
+ if (strcmp(scan_position, "none"))
+ {
+ pos = odr_atoi(scan_position);
+ pos_p = &pos;
+ }
+ }
+
+ if (protocol == PROTO_HTTP)
+ {
+#if YAZ_HAVE_XML2
+ if (!conn)
+ session_connect(cur_host);
+ if (!conn)
+ return 0;
+ if (send_SRW_scanRequest(scan_query, pos_p, scan_size) < 0)
+ return 0;
+ return 2;
+#else
+ return 0;
+#endif
+ }
+ else
+ {
+ if (*cur_host && !conn && auto_reconnect)
+ {
+ session_connect(cur_host);
+ wait_and_handle_response(0);
+ }
+ if (!conn)
+ return 0;
+ if (session_initResponse &&
+ !ODR_MASK_GET(session_initResponse->options, Z_Options_scan))
+ {
+ printf("Target doesn't support scan\n");
+ return 0;
+ }
+ if (send_Z3950_scanrequest(set, scan_query, pos_p,
+ scan_size, scan_term) < 0)
+ return 0;
+ return 2;
+ }
+}
+
+static int cmd_scan(const char *arg)
+{
+ return cmd_scan_common(0, arg);
+}
+
+static int cmd_setscan(const char *arg)
+{
+ char setstring[100];
+ int nor;
+ if (sscanf(arg, "%99s%n", setstring, &nor) < 1)
+ {
+ printf("missing set for setscan\n");
+ return 0;
+ }
+ return cmd_scan_common(setstring, arg + nor);
+}
+
+static int cmd_schema(const char *arg)
+{
+ xfree(record_schema);
+ record_schema = 0;
+ if (arg && *arg)
+ record_schema = xstrdup(arg);
+ return 1;
+}
+
+static int cmd_format(const char *arg)
+{
+ const char *cp = arg;
+ int nor;
+ int idx = 0;
+ int i;
+ char form_str[41];
+ if (!arg || !*arg)
+ {
+ printf("Usage: format <recordsyntax>\n");
+ return 0;
+ }
+ while (sscanf(cp, "%40s%n", form_str, &nor) >= 1 && nor > 0
+ && idx < RECORDSYNTAX_MAX)
+ {
+ if (strcmp(form_str, "none") &&
+ !yaz_string_to_oid_odr(yaz_oid_std(), CLASS_RECSYN, form_str, out))
+ {
+ printf("Bad format: %s\n", form_str);
+ return 0;
+ }
+ cp += nor;
+ }
+ for (i = 0; i < recordsyntax_size; i++)
+ {
+ xfree(recordsyntax_list[i]);
+ recordsyntax_list[i] = 0;
+ }
+
+ cp = arg;
+ while (sscanf(cp, "%40s%n", form_str, &nor) >= 1 && nor > 0
+ && idx < RECORDSYNTAX_MAX)
+ {
+ if (!strcmp(form_str, "none"))
+ break;
+ recordsyntax_list[idx] = xstrdup(form_str);
+ cp += nor;
+ idx++;
+ }
+ recordsyntax_size = idx;
+ return 1;
+}
+
+static int cmd_elements(const char *arg)
+{
+ static Z_ElementSetNames esn;
+ static char what[100];
+
+ if (!arg || !*arg)
+ {
+ elementSetNames = 0;
+ return 1;
+ }
+ strcpy(what, arg);
+ esn.which = Z_ElementSetNames_generic;
+ esn.u.generic = what;
+ elementSetNames = &esn;
+ return 1;
+}
+
+static int cmd_querytype(const char *arg)
+{
+ if (!strcmp(arg, "ccl"))
+ queryType = QueryType_CCL;
+ else if (!strcmp(arg, "prefix") || !strcmp(arg, "rpn"))
+ queryType = QueryType_Prefix;
+ else if (!strcmp(arg, "ccl2rpn") || !strcmp(arg, "cclrpn"))
+ queryType = QueryType_CCL2RPN;
+ else if (!strcmp(arg, "cql"))
+ queryType = QueryType_CQL;
+ else if (!strcmp(arg, "cql2rpn") || !strcmp(arg, "cqlrpn"))
+ queryType = QueryType_CQL2RPN;
+ 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");
+ printf(" cql2rpn - CQL query converted to RPN\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int cmd_refid(const char *arg)
+{
+ xfree(refid);
+ refid = NULL;
+ if (*arg)
+ refid = xstrdup(arg);
+ return 1;
+}
+
+static int cmd_close(const char *arg)
+{
+ Z_APDU *apdu;
+ Z_Close *req;
+ if (only_z3950())
+ return 0;
+ apdu = zget_APDU(out, Z_APDU_close);
+ req = apdu->u.close;
+ *req->closeReason = Z_Close_finished;
+ send_apdu(apdu);
+ printf("Sent close request.\n");
+ sent_close = 1;
+ return 2;
+}
+
+int cmd_packagename(const char* arg)
+{
+ xfree(esPackageName);
+ esPackageName = NULL;
+ if (*arg)
+ esPackageName = xstrdup(arg);
+ return 1;
+}
+
+static int cmd_proxy(const char* arg)
+{
+ xfree(yazProxy);
+ yazProxy = 0;
+ if (*arg)
+ yazProxy = xstrdup(arg);
+ return 1;
+}
+
+static int cmd_marccharset(const char *arg)
+{
+ char l1[30];
+
+ *l1 = 0;
+ if (sscanf(arg, "%29s", l1) < 1)
+ {
+ printf("MARC character set is `%s'\n",
+ marcCharset ? marcCharset: "none");
+ return 1;
+ }
+ xfree(marcCharset);
+ marcCharset = 0;
+ if (strcmp(l1, "-") && strcmp(l1, "none"))
+ marcCharset = xstrdup(l1);
+ return 1;
+}
+
+static int cmd_querycharset(const char *arg)
+{
+ char l1[30];
+
+ *l1 = 0;
+ if (sscanf(arg, "%29s", l1) < 1)
+ {
+ printf("Query character set is `%s'\n",
+ queryCharset ? queryCharset: "none");
+ return 1;
+ }
+ xfree(queryCharset);
+ queryCharset = 0;
+ if (strcmp(l1, "-") && strcmp(l1, "none"))
+ queryCharset = xstrdup(l1);
+ return 1;
+}
+
+static int cmd_displaycharset(const char *arg)
+{
+ char l1[30];
+
+ *l1 = 0;
+ if (sscanf(arg, "%29s", l1) < 1)
+ {
+ printf("Display character set is `%s'\n",
+ outputCharset ? outputCharset: "none");
+ }
+ else
+ {
+ xfree(outputCharset);
+ outputCharset = 0;
+ if (!strcmp(l1, "auto") && codeset)
+ {
+ if (codeset)
+ {
+ printf("Display character set: %s\n", codeset);
+ outputCharset = xstrdup(codeset);
+ }
+ else
+ printf("No codeset found on this system\n");
+ }
+ else if (strcmp(l1, "-") && strcmp(l1, "none"))
+ outputCharset = xstrdup(l1);
+ }
+ return 1;
+}
+
+static int cmd_negcharset(const char *arg)
+{
+ char l1[30];
+
+ *l1 = 0;
+ if (sscanf(arg, "%29s %d %d", l1, &negotiationCharsetRecords,
+ &negotiationCharsetVersion) < 1)
+ {
+ printf("Negotiation character set `%s'\n",
+ negotiationCharset ? negotiationCharset: "none");
+ if (negotiationCharset)
+ {
+ printf("Records in charset %s\n", negotiationCharsetRecords ?
+ "yes" : "no");
+ printf("Charneg version %d\n", negotiationCharsetVersion);
+ }
+ }
+ else
+ {
+ xfree(negotiationCharset);
+ negotiationCharset = NULL;
+ if (*l1 && strcmp(l1, "-") && strcmp(l1, "none"))
+ {
+ negotiationCharset = xstrdup(l1);
+ printf("Character set negotiation : %s\n", negotiationCharset);
+ }
+ }
+ return 1;
+}
+
+static int cmd_charset(const char* arg)
+{
+ char l1[30], l2[30], l3[30], l4[30];
+
+ *l1 = *l2 = *l3 = *l4 = '\0';
+ if (sscanf(arg, "%29s %29s %29s %29s", l1, l2, l3, l4) < 1)
+ {
+ cmd_negcharset("");
+ cmd_displaycharset("");
+ cmd_marccharset("");
+ cmd_querycharset("");
+ }
+ else
+ {
+ cmd_negcharset(l1);
+ if (*l2)
+ cmd_displaycharset(l2);
+ if (*l3)
+ cmd_marccharset(l3);
+ if (*l4)
+ cmd_querycharset(l4);
+ }
+ return 1;
+}
+
+static int cmd_lang(const char* arg)
+{
+ if (*arg == '\0')
+ {
+ printf("Current language is `%s'\n", yazLang ? yazLang : "none");
+ return 1;
+ }
+ xfree(yazLang);
+ yazLang = NULL;
+ if (*arg)
+ yazLang = xstrdup(arg);
+ return 1;
+}
+
+static int cmd_source(const char* arg, int echo )
+{
+ /* first should open the file and read one line at a time.. */
+ FILE* includeFile;
+ char line[102400], *cp;
+
+ if (strlen(arg) < 1)
+ {
+ fprintf(stderr, "Error in source command use a filename\n");
+ return -1;
+ }
+
+ includeFile = fopen(arg, "r");
+
+ if (!includeFile)
+ {
+ fprintf(stderr, "Unable to open file %s for reading\n",arg);
+ return -1;
+ }
+
+ while (fgets(line, sizeof(line), includeFile))
+ {
+ if (strlen(line) < 2)
+ continue;
+ if (line[0] == '#')
+ continue;
+
+ if ((cp = strrchr(line, '\n')))
+ *cp = '\0';
+
+ if (echo)
+ printf("processing line: %s\n", line);
+ process_cmd_line(line);
+ }
+
+ if (fclose(includeFile))
+ {
+ perror("unable to close include file");
+ exit(1);
+ }
+ return 1;
+}
+
+static int cmd_source_echo(const char* arg)
+{
+ cmd_source(arg, 1);
+ return 1;
+}
+
+static int cmd_subshell(const char* args)
+{
+ int ret = system(strlen(args) ? args : getenv("SHELL"));
+ printf("\n");
+ if (ret)
+ {
+ printf("Exit %d\n", ret);
+ }
+ return 1;
+}
+
+static int cmd_set_berfile(const char *arg)
+{
+ if (ber_file && ber_file != stdout && ber_file != stderr)
+ fclose(ber_file);
+ if (!strcmp(arg, ""))
+ ber_file = 0;
+ else if (!strcmp(arg, "-"))
+ ber_file = stdout;
+ else
+ ber_file = fopen(arg, "a");
+ return 1;
+}
+
+static int cmd_set_apdufile(const char *arg)
+{
+ if (apdu_file && apdu_file != stderr && apdu_file != stderr)
+ fclose(apdu_file);
+ if (!strcmp(arg, ""))
+ apdu_file = 0;
+ else if (!strcmp(arg, "-"))
+ apdu_file = stderr;
+ else
+ {
+ apdu_file = fopen(arg, "a");
+ if (!apdu_file)
+ perror("unable to open apdu log file");
+ }
+ if (apdu_file)
+ odr_setprint(print, apdu_file);
+ return 1;
+}
+
+static int cmd_set_cclfile(const char* arg)
+{
+ FILE *inf;
+
+ bibset = ccl_qual_mk();
+ inf = fopen(arg, "r");
+ if (!inf)
+ perror("unable to open CCL file");
+ else
+ {
+ ccl_qual_file(bibset, inf);
+ fclose(inf);
+ }
+ strcpy(ccl_fields,arg);
+ return 0;
+}
+
+static int cmd_set_cqlfile(const char* arg)
+{
+ cql_transform_t newcqltrans;
+
+ if ((newcqltrans = cql_transform_open_fname(arg)) == 0)
+ {
+ perror("unable to open CQL file");
+ return 0;
+ }
+ if (cqltrans != 0)
+ cql_transform_close(cqltrans);
+
+ cqltrans = newcqltrans;
+ strcpy(cql_fields, arg);
+ return 0;
+}
+
+static int cmd_set_auto_reconnect(const char* arg)
+{
+ if (strlen(arg)==0)
+ auto_reconnect = ! auto_reconnect;
+ else if (strcmp(arg,"on")==0)
+ auto_reconnect = 1;
+ else if (strcmp(arg,"off")==0)
+ auto_reconnect = 0;
+ else
+ {
+ printf("Error use on or off\n");
+ return 1;
+ }
+
+ if (auto_reconnect)
+ printf("Set auto reconnect enabled.\n");
+ else
+ printf("Set auto reconnect disabled.\n");
+
+ return 0;
+}
+
+static int cmd_set_auto_wait(const char* arg)
+{
+ if (strlen(arg)==0)
+ auto_wait = ! auto_wait;
+ else if (strcmp(arg,"on")==0)
+ auto_wait = 1;
+ else if (strcmp(arg,"off")==0)
+ auto_wait = 0;
+ else
+ {
+ printf("Error use on or off\n");
+ return 1;
+ }
+
+ if (auto_wait)
+ printf("Set auto wait enabled.\n");
+ else
+ printf("Set auto wait disabled.\n");
+
+ return 0;
+}
+
+static int cmd_set_marcdump(const char* arg)
+{
+ if (marc_file && marc_file != stderr)
+ { /* don't close stdout*/
+ fclose(marc_file);
+ }
+
+ if (!strcmp(arg, ""))
+ marc_file = 0;
+ else if (!strcmp(arg, "-"))
+ marc_file = stderr;
+ else
+ {
+ marc_file = fopen(arg, "a");
+ if (!marc_file)
+ perror("unable to open marc log file");
+ }
+ return 1;
+}
+
+static void marc_file_write(const char *buf, size_t sz)
+{
+ if (marc_file)
+ {
+ if (fwrite(buf, 1, sz, marc_file) != sz)
+ {
+ perror("marcfile write");
+ }
+ }
+}
+/*
+ this command takes 3 arge {name class oid}
+*/
+static int cmd_register_oid(const char* args)
+{
+ static struct {
+ char* className;
+ oid_class oclass;
+ } oid_classes[] = {
+ {"appctx",CLASS_APPCTX},
+ {"absyn",CLASS_ABSYN},
+ {"attset",CLASS_ATTSET},
+ {"transyn",CLASS_TRANSYN},
+ {"diagset",CLASS_DIAGSET},
+ {"recsyn",CLASS_RECSYN},
+ {"resform",CLASS_RESFORM},
+ {"accform",CLASS_ACCFORM},
+ {"extserv",CLASS_EXTSERV},
+ {"userinfo",CLASS_USERINFO},
+ {"elemspec",CLASS_ELEMSPEC},
+ {"varset",CLASS_VARSET},
+ {"schema",CLASS_SCHEMA},
+ {"tagset",CLASS_TAGSET},
+ {"general",CLASS_GENERAL},
+ {0,(enum oid_class) 0}
+ };
+ char oname_str[101], oclass_str[101], oid_str[101];
+ int i;
+ oid_class oidclass = CLASS_GENERAL;
+ Odr_oid oid[OID_SIZE];
+
+ if (sscanf(args, "%100[^ ] %100[^ ] %100s",
+ oname_str,oclass_str, oid_str) < 1)
+ {
+ printf("Error in register command \n");
+ return 0;
+ }
+
+ for (i = 0; oid_classes[i].className; i++)
+ {
+ if (!strcmp(oid_classes[i].className, oclass_str))
+ {
+ oidclass=oid_classes[i].oclass;
+ break;
+ }
+ }
+
+ if (!(oid_classes[i].className))
+ {
+ printf("Unknown oid class %s\n",oclass_str);
+ return 0;
+ }
+
+ oid_dotstring_to_oid(oid_str, oid);
+
+ if (yaz_oid_add(yaz_oid_std(), oidclass, oname_str, oid))
+ {
+ printf("oid %s already exists, registration failed\n",
+ oname_str);
+ }
+ return 1;
+}
+
+static int cmd_push_command(const char* arg)
+{
+#if HAVE_READLINE_HISTORY_H
+ if (strlen(arg) > 1)
+ add_history(arg);
+#else
+ fprintf(stderr,"Not compiled with the readline/history module\n");
+#endif
+ return 1;
+}
+
+void source_rc_file(const char *rc_file)
+{
+ /* If rc_file != NULL, source that. Else
+ Look for .yazclientrc and read it if it exists.
+ If it does not exist, read $HOME/.yazclientrc instead */
+ struct stat statbuf;
+
+ if (rc_file)
+ {
+ if (stat(rc_file, &statbuf) == 0)
+ cmd_source(rc_file, 0);
+ else
+ {
+ fprintf(stderr, "yaz_client: cannot source '%s'\n", rc_file);
+ exit(1);
+ }
+ }
+ else
+ {
+ char fname[1000];
+ strcpy(fname, ".yazclientrc");
+ if (stat(fname, &statbuf)==0)
+ {
+ cmd_source(fname, 0);
+ }
+ else
+ {
+ const char* homedir = getenv("HOME");
+ if (homedir)
+ {
+ sprintf(fname, "%.800s/%s", homedir, ".yazclientrc");
+ if (stat(fname, &statbuf)==0)
+ cmd_source(fname, 0);
+ }
+ }
+ }
+}
+
+static 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(const char *rc_file)
+{
+ 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);
+ }
+
+ strcpy(scan_position, "1");
+
+ 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 =
+ (char **(*)(const char *, int, int)) readline_completer;
+#endif
+ for (i = 0; i < maxOtherInfosSupported; ++i)
+ {
+ extraOtherInfos[i].oid[0] = -1;
+ extraOtherInfos[i].value = 0;
+ }
+
+ cmd_format("usmarc");
+
+ file_history = file_history_new();
+
+ source_rc_file(rc_file);
+
+ file_history_load(file_history);
+ file_history_trav(file_history, 0, add_to_readline_history);
+}
+
+
+#if HAVE_GETTIMEOFDAY
+struct timeval tv_start;
+#endif
+
+#if YAZ_HAVE_XML2
+static void handle_srw_record(Z_SRW_record *rec)
+{
+ if (rec->recordPosition)
+ {
+ printf("pos=" ODR_INT_PRINTF, *rec->recordPosition);
+ setno = *rec->recordPosition + 1;
+ }
+ if (rec->recordSchema)
+ printf(" schema=%s", rec->recordSchema);
+ printf("\n");
+ if (rec->recordData_buf && rec->recordData_len)
+ {
+ print_xml_record(rec->recordData_buf, rec->recordData_len);
+ marc_file_write(rec->recordData_buf, rec->recordData_len);
+ }
+ else
+ printf("No data!");
+ printf("\n");
+}
+
+static void handle_srw_explain_response(Z_SRW_explainResponse *res)
+{
+ handle_srw_record(&res->record);
+}
+
+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++)
+ {
+ if (res->diagnostics[i].uri)
+ printf("SRW diagnostic %s\n",
+ res->diagnostics[i].uri);
+ else
+ printf("SRW diagnostic missing or could not be decoded\n");
+ if (res->diagnostics[i].message)
+ printf("Message: %s\n", res->diagnostics[i].message);
+ if (res->diagnostics[i].details)
+ printf("Details: %s\n", res->diagnostics[i].details);
+ }
+ if (res->numberOfRecords)
+ printf("Number of hits: " ODR_INT_PRINTF "\n", *res->numberOfRecords);
+ if (res->facetList)
+ display_facets(res->facetList);
+ if (res->suggestions)
+ printf("Suggestions:\n%s\n", res->suggestions);
+ for (i = 0; i < res->num_records; i++)
+ {
+ if (i >= sru_maximumRecords)
+ {
+ printf("SRU server returns extra records. Skipping "
+ ODR_INT_PRINTF " records.\n",
+ res->num_records - sru_maximumRecords);
+ break;
+ }
+ handle_srw_record(res->records + i);
+ }
+}
+
+static void handle_srw_scan_term(Z_SRW_scanTerm *term)
+{
+ if (term->displayTerm)
+ printf("%s:", term->displayTerm);
+ else if (term->value)
+ printf("%s:", term->value);
+ else
+ printf("No value:");
+ if (term->numberOfRecords)
+ printf(" " ODR_INT_PRINTF, *term->numberOfRecords);
+ if (term->whereInList)
+ printf(" %s", term->whereInList);
+ if (term->value && term->displayTerm)
+ printf(" %s", term->value);
+
+ strcpy(last_scan_line, term->value);
+ printf("\n");
+}
+
+static void handle_srw_scan_response(Z_SRW_scanResponse *res)
+{
+ int i;
+
+ printf("Received SRW Scan Response\n");
+
+ for (i = 0; i<res->num_diagnostics; i++)
+ {
+ if (res->diagnostics[i].uri)
+ printf("SRW diagnostic %s\n",
+ res->diagnostics[i].uri);
+ else
+ printf("SRW diagnostic missing or could not be decoded\n");
+ if (res->diagnostics[i].message)
+ printf("Message: %s\n", res->diagnostics[i].message);
+ if (res->diagnostics[i].details)
+ printf("Details: %s\n", res->diagnostics[i].details);
+ }
+ if (res->terms)
+ for (i = 0; i<res->num_terms; i++)
+ handle_srw_scan_term(res->terms + i);
+}
+
+static void http_response(Z_HTTP_Response *hres)
+{
+ int ret = -1;
+ const char *connection_head = z_HTTP_header_lookup(hres->headers,
+ "Connection");
+ if (hres->code != 200)
+ {
+ printf("HTTP Error Status=%d\n", hres->code);
+ }
+
+ if (!yaz_srw_check_content_type(hres))
+ printf("Content type does not appear to be XML\n");
+ else
+ {
+ if (!yaz_matchstr(sru_method, "solr"))
+ {
+ Z_SRW_PDU *sr = 0;
+ ODR o = odr_createmem(ODR_DECODE);
+ ret = yaz_solr_decode_response(o, hres, &sr);
+
+ if (ret == 0 && sr->which == Z_SRW_searchRetrieve_response)
+ handle_srw_response(sr->u.response);
+ else
+ {
+ printf("Decoding of SOLR package failed\n");
+ ret = -1;
+ }
+ odr_destroy(o);
+ }
+ else
+ {
+ Z_SOAP *soap_package = 0;
+ ODR o = odr_createmem(ODR_DECODE);
+ Z_SOAP_Handler soap_handlers[] = {
+ {YAZ_XMLNS_SRU_v2_response, 0, (Z_SOAP_fun) yaz_srw_codec},
+ {YAZ_XMLNS_UPDATE_v0_9, 0, (Z_SOAP_fun) yaz_ucp_codec},
+ {YAZ_XMLNS_SRU_v1_response, 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)
+ {
+ Z_SRW_PDU *sr = (Z_SRW_PDU *) soap_package->u.generic->p;
+ if (sr->which == Z_SRW_searchRetrieve_response)
+ handle_srw_response(sr->u.response);
+ else if (sr->which == Z_SRW_explain_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
+ {
+ printf("Decoding of SRW package failed\n");
+ ret = -1;
+ }
+ }
+ else if (soap_package && (soap_package->which == Z_SOAP_fault
+ || soap_package->which == Z_SOAP_error))
+ {
+ printf("SOAP Fault code %s\n",
+ soap_package->u.fault->fault_code);
+ printf("SOAP Fault string %s\n",
+ soap_package->u.fault->fault_string);
+ if (soap_package->u.fault->details)
+ printf("SOAP Details %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(); /* close session on error */
+ else
+ {
+ 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
+
+#define max_HTTP_redirects 2
+
+static void wait_and_handle_response(int one_response_only)
+{
+ int reconnect_ok = 1;
+ int no_redirects = 0;
+ int res;
+ char *netbuffer= 0;
+ int netbufferlen = 0;
+#if HAVE_GETTIMEOFDAY
+ int got_tv_end = 0;
+ struct timeval tv_end;
+#endif
+ Z_GDU *gdu;
+
+ while(conn)
+ {
+ res = cs_get(conn, &netbuffer, &netbufferlen);
+ if (reconnect_ok && res <= 0 && protocol == PROTO_HTTP)
+ {
+ cs_close(conn);
+ conn = 0;
+ session_connect(cur_host);
+ 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 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);
+ 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 %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 (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_Z3950_initResponse(apdu->u.initResponse);
+ break;
+ case Z_APDU_searchResponse:
+ process_Z3950_searchResponse(apdu->u.searchResponse);
+ break;
+ case Z_APDU_scanResponse:
+ process_Z3950_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 = " ODR_INT_PRINTF "\n",
+ *apdu->u.presentResponse->nextResultSetPosition);
+ break;
+ case Z_APDU_sortResponse:
+ process_Z3950_sortResponse(apdu->u.sortResponse);
+ break;
+ case Z_APDU_extendedServicesResponse:
+ printf("Got extended services response\n");
+ process_Z3950_ESResponse(apdu->u.extendedServicesResponse);
+ break;
+ case Z_APDU_close:
+ printf("Target has closed the association.\n");
+ process_Z3950_close(apdu->u.close);
+ break;
+ case Z_APDU_resourceControlRequest:
+ process_Z3950_resourceControlRequest(
+ apdu->u.resourceControlRequest);
+ break;
+ case Z_APDU_deleteResultSetResponse:
+ process_Z3950_deleteResultSetResponse(
+ apdu->u.deleteResultSetResponse);
+ break;
+ default:
+ printf("Received unknown APDU type (%d).\n",
+ apdu->which);
+ close_session();
+ }
+ }
+#if YAZ_HAVE_XML2
+ else if (gdu->which == Z_GDU_HTTP_Response)
+ {
+ Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+ int code = hres->code;
+ const char *location = 0;
+ 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);
+ no_redirects++;
+ if (conn)
+ {
+ if (send_SRW_redirect(location, hres) == 2)
+ continue;
+ }
+ printf("Redirect failed\n");
+ }
+ else
+ http_response(gdu->u.HTTP_Response);
+ }
+#endif
+ if (one_response_only)
+ break;
+ if (conn && !cs_more(conn))
+ break;
+ }
+#if HAVE_GETTIMEOFDAY
+ if (got_tv_end)
+ {
+#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);
+}
+
+static 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)
+ {
+ int ioff = 3+strlen(last_cmd)+1+pos;
+ printf("%*s^ - ", ioff, " ");
+ 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;
+}
+
+static int cmd_set_otherinfo(const char* args)
+{
+ char oidstr[101], otherinfoString[101];
+ int otherinfoNo;
+ int sscan_res;
+
+ sscan_res = sscanf(args, "%d %100[^ ] %100s",
+ &otherinfoNo, oidstr, otherinfoString);
+
+ if (sscan_res > 0 && otherinfoNo >= maxOtherInfosSupported)
+ {
+ printf("Error otherinfo index too large (%d>=%d)\n",
+ otherinfoNo,maxOtherInfosSupported);
+ return 0;
+ }
+
+
+ if (sscan_res==1)
+ {
+ /* reset this otherinfo */
+ extraOtherInfos[otherinfoNo].oid[0] = -1;
+ xfree(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].value = 0;
+ return 0;
+ }
+ if (sscan_res != 3)
+ {
+ printf("Error in set_otherinfo command \n");
+ return 0;
+ }
+ else
+ {
+ NMEM oid_tmp = nmem_create();
+ const Odr_oid *oid =
+ yaz_string_to_oid_nmem(yaz_oid_std(),
+ CLASS_GENERAL, oidstr, oid_tmp);
+ oid_oidcpy(extraOtherInfos[otherinfoNo].oid, oid);
+
+ xfree(extraOtherInfos[otherinfoNo].value);
+ extraOtherInfos[otherinfoNo].value = xstrdup(otherinfoString);
+
+ nmem_destroy(oid_tmp);