source: trunk/gsdl/src/recpt/yaz_zclient.c@ 10361

Last change on this file since 10361 was 10177, checked in by kjdon, 19 years ago

new version of yaz_zclient for yaz2.1.4 - now lives in colservr. replaces the old 1.6 version that used to live in the yaz directory

  • Property svn:keywords set to Author Date Id Revision
File size: 151.4 KB
Line 
1/*
2 * Copyright (C) 1995-2005, Index Data
3 * See the file LICENSE for details.
4 *
5 */
6
7/* Modified for the Greenstone Digital Library project, based on yaz 2's client.c
8 kjdon, copying version 1.6 mods done by johnmcp */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <assert.h>
13#include <time.h>
14#include <ctype.h>
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18#if HAVE_LOCALE_H
19#include <locale.h>
20#endif
21#if HAVE_LANGINFO_H
22#include <langinfo.h>
23#endif
24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#if HAVE_SYS_TIME_H
28#include <sys/time.h>
29#endif
30
31/* this one needs to be there
32#if HAVE_SYS_STAT_H
33#include <sys/stat.h>
34#endif
35*/
36#include <sys/stat.h>
37
38#if HAVE_OPENSSL_SSL_H
39#include <openssl/bio.h>
40#include <openssl/crypto.h>
41#include <openssl/x509.h>
42#include <openssl/pem.h>
43#include <openssl/ssl.h>
44#include <openssl/err.h>
45#endif
46
47#ifdef WIN32
48#include <sys/stat.h>
49#include <io.h>
50#include <windows.h>
51#define S_ISREG(x) (x & _S_IFREG)
52#define S_ISDIR(x) (x & _S_IFDIR)
53#endif
54
55#include <yaz/yaz-util.h>
56
57#include <yaz/comstack.h>
58
59#include <yaz/proto.h>
60#include <yaz/marcdisp.h>
61#include <yaz/diagbib1.h>
62#include <yaz/otherinfo.h>
63#include <yaz/charneg.h>
64
65#include <yaz/pquery.h>
66#include <yaz/sortspec.h>
67
68#include <yaz/ill.h>
69#include <yaz/srw.h>
70#include <yaz/yaz-ccl.h>
71#include <yaz/cql.h>
72#include <yaz/log.h>
73
74#if HAVE_READLINE_READLINE_H
75#include <readline/readline.h>
76#endif
77#if HAVE_READLINE_HISTORY_H
78#include <readline/history.h>
79#endif
80
81/* these files are from the yaz client */
82#include "tabcomplete.h"
83
84#include "yaz_zclient.h"
85
86#define C_PROMPT "Z> "
87
88static char *codeset = 0; /* character set for output */
89static int hex_dump = 0;
90static char *dump_file_prefix = 0;
91static ODR out, in, print; /* encoding and decoding streams */
92#if HAVE_XML2
93static ODR srw_sr_odr_out = 0;
94static Z_SRW_PDU *srw_sr = 0;
95#endif
96static FILE *apdu_file = 0;
97static FILE *ber_file = 0;
98static COMSTACK conn = 0; /* our z-association */
99static Z_IdAuthentication *auth = 0; /* our current auth definition */
100char *databaseNames[128];
101int num_databaseNames = 0;
102static Z_External *record_last = 0;
103static int setnumber = -1; /* current result set number */
104static int smallSetUpperBound = 0;
105static int largeSetLowerBound = 1;
106static int mediumSetPresentNumber = 0;
107static Z_ElementSetNames *elementSetNames = 0;
108static int setno = 1; /* current set offset */
109static enum oid_proto protocol = PROTO_Z3950; /* current app protocol */
110static enum oid_value recordsyntax = VAL_USMARC;
111static char *record_schema = 0;
112static int sent_close = 0;
113static NMEM session_mem = NULL; /* memory handle for init-response */
114static Z_InitResponse *session = 0; /* session parameters */
115static char last_scan_line[512] = "0";
116static char last_scan_query[512] = "0";
117static char ccl_fields[512] = "default.bib";
118/* ### How can I set this path to use wherever YAZ is installed? */
119/* ############## change */
120static char cql_fields[512] = "/research/kjdon/home/z3950/gsdl/packages/yaz2/etc/pqf.properties";
121static char *esPackageName = 0;
122static char *yazProxy = 0;
123static int kilobytes = 1024;
124static char *negotiationCharset = 0;
125static int negotiationCharsetRecords = 1;
126static int negotiationCharsetVersion = 3;
127static char *outputCharset = 0;
128static char *marcCharset = 0;
129static char* yazLang = 0;
130static char* http_version = "1.1";
131
132static char last_cmd[32] = "?";
133static FILE *marc_file = 0;
134static char *refid = NULL;
135static char *last_open_command = NULL;
136static int auto_reconnect = 0;
137static Odr_bitmask z3950_options;
138static int z3950_version = 3;
139static int scan_stepSize = 0;
140static int scan_position = 1;
141static int scan_size = 20;
142static char cur_host[200];
143
144typedef enum {
145 QueryType_Prefix,
146 QueryType_CCL,
147 QueryType_CCL2RPN,
148 QueryType_CQL,
149 QueryType_CQL2RPN
150} QueryType;
151
152static QueryType queryType = QueryType_Prefix;
153
154static CCL_bibset bibset; /* CCL bibset handle */
155static cql_transform_t cqltrans; /* CQL context-set handle */
156
157#if HAVE_READLINE_COMPLETION_OVER
158
159#else
160/* readline doesn't have this var. Define it ourselves. */
161int rl_attempted_completion_over = 0;
162#endif
163
164/* set this one to 1, to avoid decode of unknown MARCs */
165#define AVOID_MARC_DECODE 1
166
167#define maxOtherInfosSupported 10
168struct {
169 int oidval;
170 char* value;
171} extraOtherInfos[maxOtherInfosSupported];
172
173
174void process_cmd_line(char* line);
175char ** readline_completer(char *text, int start, int end);
176char *command_generator(const char *text, int state);
177char** curret_global_list=NULL;
178int cmd_register_tab(const char* arg);
179
180static void close_session (void);
181
182ODR getODROutputStream()
183{
184 return out;
185}
186
187const char* query_type_as_string(QueryType q)
188{
189 switch (q) {
190 case QueryType_Prefix: return "prefix (RPN sent to server)";
191 case QueryType_CCL: return "CCL (CCL sent to server) ";
192 case QueryType_CCL2RPN: return "CCL -> RPN (RPN sent to server)";
193 case QueryType_CQL: return "CQL (CQL sent to server)";
194 case QueryType_CQL2RPN: return "CQL -> RPN (RPN sent to server)";
195 default:
196 return "unknown Query type internal yaz-client error";
197 }
198}
199
200static void do_hex_dump(const char* buf, int len)
201{
202 if (hex_dump)
203 {
204 int i,x;
205 for( i=0; i<len ; i=i+16 )
206 {
207 printf(" %4.4d ",i);
208 for(x=0 ; i+x<len && x<16; ++x)
209 {
210 printf("%2.2X ",(unsigned int)((unsigned char)buf[i+x]));
211 }
212 printf("\n");
213 }
214 }
215 if (dump_file_prefix)
216 {
217 static int no = 0;
218 if (++no < 1000 && strlen(dump_file_prefix) < 500)
219 {
220 char fname[1024];
221 FILE *of;
222 sprintf (fname, "%s.%03d.raw", dump_file_prefix, no);
223 of = fopen(fname, "wb");
224
225 fwrite (buf, 1, len, of);
226
227 fclose(of);
228 }
229 }
230}
231
232void add_otherInfos(Z_APDU *a)
233{
234 Z_OtherInformation **oi;
235 int i;
236
237 yaz_oi_APDU(a, &oi);
238 for(i=0; i<maxOtherInfosSupported; ++i)
239 {
240 if(extraOtherInfos[i].oidval != -1)
241 yaz_oi_set_string_oidval(oi, out, extraOtherInfos[i].oidval,
242 1, extraOtherInfos[i].value);
243 }
244}
245
246int send_apdu(Z_APDU *a)
247{
248 char *buf;
249 int len;
250
251 add_otherInfos(a);
252
253 if (apdu_file)
254 {
255 z_APDU(print, &a, 0, 0);
256 odr_reset(print);
257 }
258 if (!z_APDU(out, &a, 0, 0))
259 {
260 odr_perror(out, "Encoding APDU");
261 close_session();
262 return 0;
263 }
264 buf = odr_getbuf(out, &len, 0);
265 if (ber_file)
266 odr_dumpBER(ber_file, buf, len);
267 /* printf ("sending APDU of size %d\n", len); */
268 do_hex_dump(buf, len);
269 if (cs_put(conn, buf, len) < 0)
270 {
271 fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
272 close_session();
273 return 0;
274 }
275 odr_reset(out); /* release the APDU structure */
276 return 1;
277}
278
279static void print_stringn(const unsigned char *buf, size_t len)
280{
281 size_t i;
282 for (i = 0; i<len; i++)
283 if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
284 printf ("%c", buf[i]);
285 else
286 printf ("\\X%02X", buf[i]);
287}
288
289static void print_refid (Z_ReferenceId *id)
290{
291 if (id)
292 {
293 printf ("Reference Id: ");
294 print_stringn (id->buf, id->len);
295 printf ("\n");
296 }
297}
298
299static Z_ReferenceId *set_refid (ODR out)
300{
301 Z_ReferenceId *id;
302 if (!refid)
303 return 0;
304 id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
305 id->size = id->len = strlen(refid);
306 id->buf = (unsigned char *) odr_malloc (out, id->len);
307 memcpy (id->buf, refid, id->len);
308 return id;
309}
310
311/* INIT SERVICE ------------------------------- */
312
313static void send_initRequest(const char* type_and_host)
314{
315 Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
316 Z_InitRequest *req = apdu->u.initRequest;
317 int i;
318
319 req->options = &z3950_options;
320
321 ODR_MASK_ZERO(req->protocolVersion);
322 for (i = 0; i<z3950_version; i++)
323 ODR_MASK_SET(req->protocolVersion, i);
324
325 *req->maximumRecordSize = 1024*kilobytes;
326 *req->preferredMessageSize = 1024*kilobytes;
327
328 req->idAuthentication = auth;
329
330 req->referenceId = set_refid (out);
331
332 if (yazProxy && type_and_host)
333 yaz_oi_set_string_oidval(&req->otherInfo, out, VAL_PROXY,
334 1, type_and_host);
335
336 if (negotiationCharset || yazLang) {
337 Z_OtherInformation **p;
338 Z_OtherInformationUnit *p0;
339
340 yaz_oi_APDU(apdu, &p);
341
342 if ((p0=yaz_oi_update(p, out, NULL, 0, 0))) {
343 ODR_MASK_SET(req->options, Z_Options_negotiationModel);
344
345 p0->which = Z_OtherInfo_externallyDefinedInfo;
346 p0->information.externallyDefinedInfo =
347 yaz_set_proposal_charneg(
348 out,
349 (const char**)&negotiationCharset,
350 negotiationCharset ? 1 : 0,
351 (const char**)&yazLang, yazLang ? 1 : 0,
352 negotiationCharsetRecords);
353 }
354 }
355
356 send_apdu(apdu);
357 /* (send_apdu(apdu))
358 intf("Sent initrequest.\n");*/
359}
360
361/* in old version, John had got rid of process_initResponse, and added
362 z_get_initResponse. I'll add this in but leave the other one alone
363 this returns the info that is used in the description for the 'collection'*/
364char *z_get_initResponse()
365{
366
367 if (!*session->result)
368 return NULL; /* no init info to return */
369
370 char* buffer; /* we are returning some info in this buffer */
371 char *text_id="ID: ";
372 char *text_name="<br>\nName: ";
373 char *text_ver="<br>\nVersion: ";
374
375 size_t initial_length = strlen(text_id)+strlen(text_name)+strlen(text_ver)+
376 (session->implementationId?strlen(session->implementationId):0) +
377 (session->implementationName?strlen(session->implementationName):0) +
378 (session->implementationVersion?strlen(session->implementationVersion)
379 :0) + 1; /* for null char */
380
381 if ((buffer = malloc((sizeof(char *))*initial_length)) == NULL) {
382 fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
383 return (NULL);
384 }
385 /* can't pass NULL to sprintf as a (char *) */
386 sprintf(buffer,"%s%s%s%s%s%s",
387 session->implementationId?text_id:"",
388 session->implementationId?session->implementationId:"",
389 session->implementationName?text_name:"",
390 session->implementationName?session->implementationName:"",
391 session->implementationVersion?text_ver:"",
392 session->implementationVersion?session->implementationVersion:""
393 );
394 return (buffer);
395
396}
397
398char *z_get_initResponseOld()
399{
400 char *buffer;
401 size_t needed_length;
402 char *text_id="ID: ";
403 char *text_name="<br>\nName: ";
404 char *text_ver="<br>\nVersion: ";
405 int counter;
406
407 buffer=NULL;
408 if (!*session->result)
409 return NULL;
410
411 /* work out total string length needed. Note strlen(NULL) is a bad thing
412 to do. */
413 needed_length=strlen(text_id)+strlen(text_name)+strlen(text_ver)+
414 (session->implementationId?strlen(session->implementationId):0) +
415 (session->implementationName?strlen(session->implementationName):0) +
416 (session->implementationVersion?strlen(session->implementationVersion)
417 :0) +
418 (session->userInformationField?
419 strlen(session->userInformationField->u.octet_aligned->buf):0) +
420 1 /* for null char */ ;
421 if ((buffer=malloc((sizeof(char *)) * needed_length))==NULL) {
422 fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
423 return (NULL);
424 }
425 /* can't pass NULL to sprintf as a (char *) */
426 sprintf(buffer,"%s%s%s%s%s%s",
427 session->implementationId?text_id:"",
428 session->implementationId?session->implementationId:"",
429 session->implementationName?text_name:"",
430 session->implementationName?session->implementationName:"",
431 session->implementationVersion?text_ver:"",
432 session->implementationVersion?session->implementationVersion:""
433 );
434
435 /* if version 3, also check the other-information parameter of the
436 response. (But check version is 3 first) */
437 if (session->otherInfo)
438 /**** From prt-proto.h *********** (comment added by johnmcp)
439 typedef struct Z_OtherInformationUnit
440 . { Z_InfoCategory *category; / * OPTIONAL * /
441 . int which;
442 #define Z_OtherInfo_characterInfo 0
443 #define Z_OtherInfo_binaryInfo 1
444 #define Z_OtherInfo_externallyDefinedInfo 2
445 #define Z_OtherInfo_oid 3
446 . union
447 . {
448 . char *characterInfo;
449 . Odr_oct *binaryInfo;
450 . Z_External *externallyDefinedInfo;
451 . Odr_oid *oid;
452 . } information;
453 . } Z_OtherInformationUnit;
454
455 typedef struct Z_OtherInformation
456 {
457 int num_elements;
458 Z_OtherInformationUnit **list;
459 } Z_OtherInformation;
460 ************/
461 for (counter=0;counter<session->otherInfo->num_elements;counter++) {
462 if (session->otherInfo->list[counter]->which ==
463 Z_OtherInfo_characterInfo) {
464
465 /* add this extra string to our buffer */
466 int where=strlen(buffer);
467 buffer=realloc(buffer,where+
468 strlen(session->otherInfo->list[counter]->
469 information.characterInfo));
470 strcpy(buffer+where,
471 session->otherInfo->list[counter]->
472 information.characterInfo);
473 }
474 }
475 return (buffer);
476}
477
478
479/* These two are used only from process_initResponse() */
480static void render_initUserInfo(Z_OtherInformation *ui1);
481static void render_diag(Z_DiagnosticFormat *diag);
482
483static void pr_opt(const char *opt, void *clientData)
484{
485 printf (" %s", opt);
486}
487
488static int process_initResponse(Z_InitResponse *res)
489{
490 int ver = 0;
491 /* save session parameters for later use */
492 session_mem = odr_extract_mem(in);
493 session = res;
494
495 for (ver = 0; ver < 8; ver++)
496 if (!ODR_MASK_GET(res->protocolVersion, ver))
497 break;
498
499 if (!*res->result)
500 printf("Connection rejected by v%d target.\n", ver);
501 else
502 printf("Connection accepted by v%d target.\n", ver);
503 if (res->implementationId)
504 printf("ID : %s\n", res->implementationId);
505 if (res->implementationName)
506 printf("Name : %s\n", res->implementationName);
507 if (res->implementationVersion)
508 printf("Version: %s\n", res->implementationVersion);
509 if (res->userInformationField)
510 {
511 Z_External *uif = res->userInformationField;
512 if (uif->which == Z_External_userInfo1) {
513 render_initUserInfo(uif->u.userInfo1);
514 } else {
515 printf("UserInformationfield:\n");
516 if (!z_External(print, (Z_External**)&uif, 0, 0))
517 {
518 odr_perror(print, "Printing userinfo\n");
519 odr_reset(print);
520 }
521 if (uif->which == Z_External_octet) {
522 printf("Guessing visiblestring:\n");
523 printf("'%.*s'\n", uif->u.octet_aligned->len,
524 uif->u.octet_aligned->buf);
525 }
526 else if (uif->which == Z_External_single)
527 {
528 Odr_any *sat = uif->u.single_ASN1_type;
529 oident *oid = oid_getentbyoid(uif->direct_reference);
530 if (oid->value == VAL_OCLCUI) {
531 Z_OCLC_UserInformation *oclc_ui;
532 ODR decode = odr_createmem(ODR_DECODE);
533 odr_setbuf(decode, sat->buf, sat->len, 0);
534 if (!z_OCLC_UserInformation(decode, &oclc_ui, 0, 0))
535 printf ("Bad OCLC UserInformation:\n");
536 else
537 printf ("OCLC UserInformation:\n");
538 if (!z_OCLC_UserInformation(print, &oclc_ui, 0, 0))
539 printf ("Bad OCLC UserInformation spec\n");
540 odr_destroy(decode);
541 }
542 else
543 {
544 /* Peek at any private Init-diagnostic APDUs */
545 printf("### NAUGHTY: External is '%.*s'\n",
546 sat->len, sat->buf);
547 }
548 }
549 odr_reset (print);
550 }
551 }
552 printf ("Options:");
553 yaz_init_opt_decode(res->options, pr_opt, 0);
554 printf ("\n");
555
556 if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
557 setnumber = 0;
558
559 if (ODR_MASK_GET(res->options, Z_Options_negotiationModel)) {
560
561 Z_CharSetandLanguageNegotiation *p =
562 yaz_get_charneg_record(res->otherInfo);
563
564 if (p) {
565
566 char *charset=NULL, *lang=NULL;
567
568 int selected;
569
570 yaz_get_response_charneg(session_mem, p, &charset, &lang,
571 &selected);
572
573 if (outputCharset && negotiationCharset) {
574 odr_set_charset (out, charset, outputCharset);
575 odr_set_charset (in, outputCharset, charset);
576 }
577 else {
578 odr_set_charset (out, 0, 0);
579 odr_set_charset (in, 0, 0);
580 }
581
582 printf("Accepted character set : %s\n", charset);
583 printf("Accepted code language : %s\n", lang ? lang : "none");
584 printf("Accepted records in ...: %d\n", selected );
585 }
586 }
587 fflush (stdout);
588 return 0;
589}
590
591
592static void render_initUserInfo(Z_OtherInformation *ui1) {
593 int i;
594 printf("Init response contains %d otherInfo unit%s:\n",
595 ui1->num_elements, ui1->num_elements == 1 ? "" : "s");
596
597 for (i = 0; i < ui1->num_elements; i++) {
598 Z_OtherInformationUnit *unit = ui1->list[i];
599 printf(" %d: otherInfo unit contains ", i+1);
600 if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
601 unit->information.externallyDefinedInfo &&
602 unit->information.externallyDefinedInfo->which ==
603 Z_External_diag1) {
604 render_diag(unit->information.externallyDefinedInfo->u.diag1);
605 }
606 else if (unit->which != Z_OtherInfo_externallyDefinedInfo)
607 {
608 printf("unsupported otherInfo unit->which = %d\n", unit->which);
609 }
610 else
611 {
612 printf("unsupported otherInfo unit external %d\n",
613 unit->information.externallyDefinedInfo ?
614 unit->information.externallyDefinedInfo->which : -2);
615 }
616 }
617}
618
619
620/* ### should this share code with display_diagrecs()? */
621static void render_diag(Z_DiagnosticFormat *diag) {
622 int i;
623
624 printf("%d diagnostic%s:\n", diag->num, diag->num == 1 ? "" : "s");
625 for (i = 0; i < diag->num; i++) {
626 Z_DiagnosticFormat_s *ds = diag->elements[i];
627 printf(" %d: ", i+1);
628 switch (ds->which) {
629 case Z_DiagnosticFormat_s_defaultDiagRec: {
630 Z_DefaultDiagFormat *dd = ds->u.defaultDiagRec;
631 /* ### should check `dd->diagnosticSetId' */
632 printf("code=%d (%s)", *dd->condition,
633 diagbib1_str(*dd->condition));
634 /* Both types of addinfo are the same, so use type-pun */
635 if (dd->u.v2Addinfo != 0)
636 printf(",\n\taddinfo='%s'", dd->u.v2Addinfo);
637 break;
638 }
639 case Z_DiagnosticFormat_s_explicitDiagnostic:
640 printf("Explicit diagnostic (not supported)");
641 break;
642 default:
643 printf("Unrecognised diagnostic type %d", ds->which);
644 break;
645 }
646
647 if (ds->message != 0)
648 printf(", message='%s'", ds->message);
649 printf("\n");
650 }
651}
652
653
654static int set_base(const char *arg)
655{
656 int i;
657 const char *cp;
658
659 for (i = 0; i<num_databaseNames; i++)
660 xfree (databaseNames[i]);
661 num_databaseNames = 0;
662 while (1)
663 {
664 char *cp1;
665 if (!(cp = strchr(arg, ' ')))
666 cp = arg + strlen(arg);
667 if (cp - arg < 1)
668 break;
669 databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
670 memcpy (databaseNames[num_databaseNames], arg, cp - arg);
671 databaseNames[num_databaseNames][cp - arg] = '\0';
672
673 for (cp1 = databaseNames[num_databaseNames]; *cp1 ; cp1++)
674 if (*cp1 == '+')
675 *cp1 = ' ';
676 num_databaseNames++;
677
678 if (!*cp)
679 break;
680 arg = cp+1;
681 }
682 if (num_databaseNames == 0)
683 {
684 num_databaseNames = 1;
685 databaseNames[0] = xstrdup("");
686 }
687 return 1;
688}
689
690static int cmd_base(const char *arg)
691{
692 if (!*arg)
693 {
694 printf("Usage: base <database> <database> ...\n");
695 return 0;
696 }
697 return set_base(arg);
698}
699
700void cmd_open_remember_last_open_command(const char* arg, char* new_open_command)
701{
702 if(last_open_command != arg)
703 {
704 if(last_open_command) xfree(last_open_command);
705 last_open_command = xstrdup(new_open_command);
706 }
707}
708
709int session_connect(const char *arg)
710{
711 void *add;
712 char type_and_host[101];
713 const char *basep = 0;
714#if HAVE_OPENSSL_SSL_H
715 SSL *ssl;
716#endif
717 if (conn)
718 {
719 cs_close (conn);
720 conn = NULL;
721 if (session_mem)
722 {
723 nmem_destroy (session_mem);
724 session_mem = NULL;
725 }
726 }
727 cs_get_host_args(arg, &basep);
728
729 strncpy(type_and_host, arg, sizeof(type_and_host)-1);
730 type_and_host[sizeof(type_and_host)-1] = '\0';
731
732 cmd_open_remember_last_open_command(arg, type_and_host);
733
734 if (yazProxy)
735 conn = cs_create_host(yazProxy, 1, &add);
736 else
737 conn = cs_create_host(arg, 1, &add);
738 if (!conn)
739 {
740 printf ("Couldn't create comstack\n");
741 return 0;
742 }
743#if HAVE_XML2
744 if (conn->protocol == PROTO_HTTP)
745 queryType = QueryType_CQL;
746#else
747 if (conn->protocol == PROTO_HTTP)
748 {
749 printf ("SRW/HTTP not enabled in this YAZ\n");
750 cs_close(conn);
751 conn = 0;
752 return 0;
753 }
754#endif
755 protocol = conn->protocol;
756 if (conn->protocol == PROTO_HTTP)
757 set_base("");
758 else
759 set_base("Default");
760 /*intf("Connecting...");*/
761 fflush(stdout);
762 if (cs_connect(conn, add) < 0)
763 {
764 printf ("error = %s\n", cs_strerror(conn));
765 if (conn->cerrno == CSYSERR)
766 {
767 char msg[256];
768 yaz_strerror(msg, sizeof(msg));
769 printf ("%s\n", msg);
770 }
771 cs_close(conn);
772 conn = 0;
773 return 0;
774 }
775 /*intf("OK.\n");*/
776#if HAVE_OPENSSL_SSL_H
777 if ((ssl = (SSL *) cs_get_ssl(conn)))
778 {
779 X509 *server_cert = SSL_get_peer_certificate (ssl);
780
781 if (server_cert)
782 {
783 char *pem_buf;
784 int pem_len;
785 BIO *bio = BIO_new(BIO_s_mem());
786
787 /* get PEM buffer in memory */
788 PEM_write_bio_X509(bio, server_cert);
789 pem_len = BIO_get_mem_data(bio, &pem_buf);
790 fwrite(pem_buf, pem_len, 1, stdout);
791
792 /* print all info on screen .. */
793 X509_print_fp(stdout, server_cert);
794 BIO_free(bio);
795
796 X509_free (server_cert);
797 }
798 }
799#endif
800 if (basep && *basep)
801 set_base (basep);
802 if (protocol == PROTO_Z3950)
803 {
804 send_initRequest(type_and_host);
805 return 2;
806 }
807 return 0;
808}
809
810int z_cmd_open(char *host_and_port, char *base)
811{
812 char * full_command = (char *) xmalloc (strlen(host_and_port)+strlen(base)+6);
813 strcpy(full_command, "tcp:");
814 strcat(full_command, host_and_port);
815 strcat(full_command, "/");
816 strcat(full_command, base);
817 return cmd_open(full_command);
818}
819
820int cmd_open(const char *arg)
821{
822 if (arg)
823 {
824 strncpy (cur_host, arg, sizeof(cur_host)-1);
825 cur_host[sizeof(cur_host)-1] = 0;
826 }
827 return session_connect(cur_host);
828}
829
830void try_reconnect()
831{
832 char* open_command;
833
834 if(!( auto_reconnect && last_open_command) ) return ;
835
836 open_command = (char *) xmalloc (strlen(last_open_command)+6);
837 strcpy (open_command, "open ");
838
839 strcat (open_command, last_open_command);
840
841 process_cmd_line(open_command);
842
843 xfree(open_command);
844}
845
846int cmd_authentication(const char *arg)
847{
848 static Z_IdAuthentication au;
849 static char user[40], group[40], pass[40];
850 static Z_IdPass idPass;
851 int r;
852
853 if (!*arg)
854 {
855 printf("Auth field set to null\n");
856 auth = 0;
857 return 1;
858 }
859 r = sscanf (arg, "%39s %39s %39s", user, group, pass);
860 if (r == 0)
861 {
862 printf("Authentication set to null\n");
863 auth = 0;
864 }
865 if (r == 1)
866 {
867 auth = &au;
868 if (!strcmp(user, "-")) {
869 au.which = Z_IdAuthentication_anonymous;
870 printf("Authentication set to Anonymous\n");
871 } else {
872 au.which = Z_IdAuthentication_open;
873 au.u.open = user;
874 printf("Authentication set to Open (%s)\n", user);
875 }
876 }
877 if (r == 2)
878 {
879 auth = &au;
880 au.which = Z_IdAuthentication_idPass;
881 au.u.idPass = &idPass;
882 idPass.groupId = NULL;
883 idPass.userId = user;
884 idPass.password = group;
885 printf("Authentication set to User (%s), Pass (%s)\n", user, group);
886 }
887 if (r == 3)
888 {
889 auth = &au;
890 au.which = Z_IdAuthentication_idPass;
891 au.u.idPass = &idPass;
892 idPass.groupId = group;
893 idPass.userId = user;
894 idPass.password = pass;
895 printf("Authentication set to User (%s), Group (%s), Pass (%s)\n",
896 user, group, pass);
897 }
898 return 1;
899}
900
901/* SEARCH SERVICE ------------------------------ */
902static void display_record(Z_External *r);
903
904static void print_record(const unsigned char *buf, size_t len)
905{
906 size_t i = len;
907 print_stringn (buf, len);
908 /* add newline if not already added ... */
909 if (i <= 0 || buf[i-1] != '\n')
910 printf ("\n");
911}
912
913static void display_record(Z_External *r)
914{
915 oident *ent = oid_getentbyoid(r->direct_reference);
916
917 record_last = r;
918 /*
919 * Tell the user what we got.
920 */
921 if (r->direct_reference)
922 {
923 printf("Record type: ");
924 if (ent)
925 printf("%s\n", ent->desc);
926 else if (!odr_oid(print, &r->direct_reference, 0, 0))
927 {
928 odr_perror(print, "print oid");
929 odr_reset(print);
930 }
931 }
932 /* Check if this is a known, ASN.1 type tucked away in an octet string */
933 if (ent && r->which == Z_External_octet)
934 {
935 Z_ext_typeent *type = z_ext_getentbyref(ent->value);
936 char *rr;
937
938 if (type)
939 {
940 /*
941 * Call the given decoder to process the record.
942 */
943 odr_setbuf(in, (char*)r->u.octet_aligned->buf,
944 r->u.octet_aligned->len, 0);
945 if (!(*type->fun)(in, &rr, 0, 0))
946 {
947 odr_perror(in, "Decoding constructed record.");
948 fprintf(stdout, "[Near %d]\n", odr_offset(in));
949 fprintf(stdout, "Packet dump:\n---------\n");
950 odr_dumpBER(stdout, (char*)r->u.octet_aligned->buf,
951 r->u.octet_aligned->len);
952 fprintf(stdout, "---------\n");
953
954 /* note just ignores the error ant print the bytes form the octet_aligned later */
955 } else {
956 /*
957 * Note: we throw away the original, BER-encoded record here.
958 * Do something else with it if you want to keep it.
959 */
960 r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
961 r->which = type->what;
962 }
963 }
964 }
965 if (ent && ent->value == VAL_SOIF)
966 {
967 print_record((const unsigned char *) r->u.octet_aligned->buf,
968 r->u.octet_aligned->len);
969 if (marc_file)
970 fwrite (r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, marc_file);
971 }
972 else if (r->which == Z_External_octet)
973 {
974 const char *octet_buf = (char*)r->u.octet_aligned->buf;
975 if (ent->oclass == CLASS_RECSYN &&
976 (ent->value == VAL_TEXT_XML ||
977 ent->value == VAL_APPLICATION_XML ||
978 ent->value == VAL_HTML))
979 {
980 print_record((const unsigned char *) octet_buf,
981 r->u.octet_aligned->len);
982 }
983 else if (ent->value == VAL_POSTSCRIPT)
984 {
985 int size = r->u.octet_aligned->len;
986 if (size > 100)
987 size = 100;
988 print_record((const unsigned char *) octet_buf, size);
989 }
990 else
991 {
992 if (
993#if AVOID_MARC_DECODE
994 /* primitive check for a marc OID 5.1-29 except 16 */
995 ent->oidsuffix[0] == 5 && ent->oidsuffix[1] < 30 &&
996 ent->oidsuffix[1] != 16
997#else
998 1
999#endif
1000 )
1001 {
1002 char *result;
1003 int rlen;
1004 yaz_iconv_t cd = 0;
1005 yaz_marc_t mt = yaz_marc_create();
1006
1007 if (yaz_marc_decode_buf(mt, octet_buf,r->u.octet_aligned->len,
1008 &result, &rlen)> 0)
1009 {
1010 char *from = 0;
1011 if (marcCharset && !strcmp(marcCharset, "auto"))
1012 {
1013 if (ent->value == VAL_USMARC)
1014 {
1015 if (octet_buf[9] == 'a')
1016 from = "UTF-8";
1017 else
1018 from = "MARC-8";
1019 }
1020 else
1021 from = "ISO-8859-1";
1022 }
1023 else if (marcCharset)
1024 from = marcCharset;
1025 if (outputCharset && from)
1026 {
1027 cd = yaz_iconv_open(outputCharset, from);
1028 printf ("convert from %s to %s", from,
1029 outputCharset);
1030 if (!cd)
1031 printf (" unsupported\n");
1032 else
1033 printf ("\n");
1034 }
1035 if (!cd)
1036 fwrite (result, 1, rlen, stdout);
1037 else
1038 {
1039 char outbuf[6];
1040 size_t inbytesleft = rlen;
1041 const char *inp = result;
1042
1043 while (inbytesleft)
1044 {
1045 size_t outbytesleft = sizeof(outbuf);
1046 char *outp = outbuf;
1047 size_t r;
1048
1049 r = yaz_iconv (cd, (char**) &inp,
1050 &inbytesleft,
1051 &outp, &outbytesleft);
1052 if (r == (size_t) (-1))
1053 {
1054 int e = yaz_iconv_error(cd);
1055 if (e != YAZ_ICONV_E2BIG)
1056 break;
1057 }
1058 fwrite (outbuf, outp - outbuf, 1, stdout);
1059 }
1060 }
1061 }
1062 else
1063 {
1064 printf ("bad MARC. Dumping as it is:\n");
1065 print_record((const unsigned char*) octet_buf,
1066 r->u.octet_aligned->len);
1067 }
1068 yaz_marc_destroy(mt);
1069 if (cd)
1070 yaz_iconv_close(cd);
1071 }
1072 else
1073 {
1074 print_record((const unsigned char*) octet_buf,
1075 r->u.octet_aligned->len);
1076 }
1077 }
1078 if (marc_file)
1079 fwrite (octet_buf, 1, r->u.octet_aligned->len, marc_file);
1080 }
1081 else if (ent && ent->value == VAL_SUTRS)
1082 {
1083 if (r->which != Z_External_sutrs)
1084 {
1085 printf("Expecting single SUTRS type for SUTRS.\n");
1086 return;
1087 }
1088 print_record(r->u.sutrs->buf, r->u.sutrs->len);
1089 if (marc_file)
1090 fwrite (r->u.sutrs->buf, 1, r->u.sutrs->len, marc_file);
1091 }
1092 else if (ent && ent->value == VAL_GRS1)
1093 {
1094 WRBUF w;
1095 if (r->which != Z_External_grs1)
1096 {
1097 printf("Expecting single GRS type for GRS.\n");
1098 return;
1099 }
1100 w = wrbuf_alloc();
1101 yaz_display_grs1(w, r->u.grs1, 0);
1102 puts (wrbuf_buf(w));
1103 wrbuf_free(w, 1);
1104 }
1105 else if (ent && ent->value == VAL_OPAC)
1106 {
1107 int i;
1108 if (r->u.opac->bibliographicRecord)
1109 display_record(r->u.opac->bibliographicRecord);
1110 for (i = 0; i<r->u.opac->num_holdingsData; i++)
1111 {
1112 Z_HoldingsRecord *h = r->u.opac->holdingsData[i];
1113 if (h->which == Z_HoldingsRecord_marcHoldingsRecord)
1114 {
1115 printf ("MARC holdings %d\n", i);
1116 display_record(h->u.marcHoldingsRecord);
1117 }
1118 else if (h->which == Z_HoldingsRecord_holdingsAndCirc)
1119 {
1120 int j;
1121
1122 Z_HoldingsAndCircData *data = h->u.holdingsAndCirc;
1123
1124 printf ("Data holdings %d\n", i);
1125 if (data->typeOfRecord)
1126 printf ("typeOfRecord: %s\n", data->typeOfRecord);
1127 if (data->encodingLevel)
1128 printf ("encodingLevel: %s\n", data->encodingLevel);
1129 if (data->receiptAcqStatus)
1130 printf ("receiptAcqStatus: %s\n", data->receiptAcqStatus);
1131 if (data->generalRetention)
1132 printf ("generalRetention: %s\n", data->generalRetention);
1133 if (data->completeness)
1134 printf ("completeness: %s\n", data->completeness);
1135 if (data->dateOfReport)
1136 printf ("dateOfReport: %s\n", data->dateOfReport);
1137 if (data->nucCode)
1138 printf ("nucCode: %s\n", data->nucCode);
1139 if (data->localLocation)
1140 printf ("localLocation: %s\n", data->localLocation);
1141 if (data->shelvingLocation)
1142 printf ("shelvingLocation: %s\n", data->shelvingLocation);
1143 if (data->callNumber)
1144 printf ("callNumber: %s\n", data->callNumber);
1145 if (data->shelvingData)
1146 printf ("shelvingData: %s\n", data->shelvingData);
1147 if (data->copyNumber)
1148 printf ("copyNumber: %s\n", data->copyNumber);
1149 if (data->publicNote)
1150 printf ("publicNote: %s\n", data->publicNote);
1151 if (data->reproductionNote)
1152 printf ("reproductionNote: %s\n", data->reproductionNote);
1153 if (data->termsUseRepro)
1154 printf ("termsUseRepro: %s\n", data->termsUseRepro);
1155 if (data->enumAndChron)
1156 printf ("enumAndChron: %s\n", data->enumAndChron);
1157 for (j = 0; j<data->num_volumes; j++)
1158 {
1159 printf ("volume %d\n", j);
1160 if (data->volumes[j]->enumeration)
1161 printf (" enumeration: %s\n",
1162 data->volumes[j]->enumeration);
1163 if (data->volumes[j]->chronology)
1164 printf (" chronology: %s\n",
1165 data->volumes[j]->chronology);
1166 if (data->volumes[j]->enumAndChron)
1167 printf (" enumAndChron: %s\n",
1168 data->volumes[j]->enumAndChron);
1169 }
1170 for (j = 0; j<data->num_circulationData; j++)
1171 {
1172 printf ("circulation %d\n", j);
1173 if (data->circulationData[j]->availableNow)
1174 printf (" availableNow: %d\n",
1175 *data->circulationData[j]->availableNow);
1176 if (data->circulationData[j]->availablityDate)
1177 printf (" availabiltyDate: %s\n",
1178 data->circulationData[j]->availablityDate);
1179 if (data->circulationData[j]->availableThru)
1180 printf (" availableThru: %s\n",
1181 data->circulationData[j]->availableThru);
1182 if (data->circulationData[j]->restrictions)
1183 printf (" restrictions: %s\n",
1184 data->circulationData[j]->restrictions);
1185 if (data->circulationData[j]->itemId)
1186 printf (" itemId: %s\n",
1187 data->circulationData[j]->itemId);
1188 if (data->circulationData[j]->renewable)
1189 printf (" renewable: %d\n",
1190 *data->circulationData[j]->renewable);
1191 if (data->circulationData[j]->onHold)
1192 printf (" onHold: %d\n",
1193 *data->circulationData[j]->onHold);
1194 if (data->circulationData[j]->enumAndChron)
1195 printf (" enumAndChron: %s\n",
1196 data->circulationData[j]->enumAndChron);
1197 if (data->circulationData[j]->midspine)
1198 printf (" midspine: %s\n",
1199 data->circulationData[j]->midspine);
1200 if (data->circulationData[j]->temporaryLocation)
1201 printf (" temporaryLocation: %s\n",
1202 data->circulationData[j]->temporaryLocation);
1203 }
1204 }
1205 }
1206 }
1207 else
1208 {
1209 printf("Unknown record representation.\n");
1210 if (!z_External(print, &r, 0, 0))
1211 {
1212 odr_perror(print, "Printing external");
1213 odr_reset(print);
1214 }
1215 }
1216}
1217
1218static void display_diagrecs(Z_DiagRec **pp, int num)
1219{
1220 int i;
1221 oident *ent;
1222 Z_DefaultDiagFormat *r;
1223
1224 printf("Diagnostic message(s) from database:\n");
1225 for (i = 0; i<num; i++)
1226 {
1227 Z_DiagRec *p = pp[i];
1228 if (p->which != Z_DiagRec_defaultFormat)
1229 {
1230 printf("Diagnostic record not in default format.\n");
1231 return;
1232 }
1233 else
1234 r = p->u.defaultFormat;
1235 if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
1236 ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
1237 printf("Missing or unknown diagset\n");
1238 printf(" [%d] %s", *r->condition, diagbib1_str(*r->condition));
1239 switch (r->which)
1240 {
1241 case Z_DefaultDiagFormat_v2Addinfo:
1242 printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
1243 break;
1244 case Z_DefaultDiagFormat_v3Addinfo:
1245 printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
1246 break;
1247 }
1248 }
1249}
1250
1251
1252static void display_nameplusrecord(Z_NamePlusRecord *p)
1253{
1254 if (p->databaseName)
1255 printf("[%s]", p->databaseName);
1256 if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
1257 display_diagrecs(&p->u.surrogateDiagnostic, 1);
1258 else if (p->which == Z_NamePlusRecord_databaseRecord)
1259 display_record(p->u.databaseRecord);
1260}
1261
1262static void display_records(Z_Records *p)
1263{
1264 int i;
1265
1266 if (p->which == Z_Records_NSD)
1267 {
1268 Z_DiagRec dr, *dr_p = &dr;
1269 dr.which = Z_DiagRec_defaultFormat;
1270 dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
1271 display_diagrecs (&dr_p, 1);
1272 }
1273 else if (p->which == Z_Records_multipleNSD)
1274 display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs,
1275 p->u.multipleNonSurDiagnostics->num_diagRecs);
1276 else
1277 {
1278 printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
1279 for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
1280 display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
1281 }
1282}
1283
1284static int send_deleteResultSetRequest(const char *arg)
1285{
1286 char names[8][32];
1287 int i;
1288
1289 Z_APDU *apdu = zget_APDU(out, Z_APDU_deleteResultSetRequest);
1290 Z_DeleteResultSetRequest *req = apdu->u.deleteResultSetRequest;
1291
1292 req->referenceId = set_refid (out);
1293
1294 req->num_resultSetList =
1295 sscanf (arg, "%30s %30s %30s %30s %30s %30s %30s %30s",
1296 names[0], names[1], names[2], names[3],
1297 names[4], names[5], names[6], names[7]);
1298
1299 req->deleteFunction = (int *)
1300 odr_malloc (out, sizeof(*req->deleteFunction));
1301 if (req->num_resultSetList > 0)
1302 {
1303 *req->deleteFunction = Z_DeleteResultSetRequest_list;
1304 req->resultSetList = (char **)
1305 odr_malloc (out, sizeof(*req->resultSetList)*
1306 req->num_resultSetList);
1307 for (i = 0; i<req->num_resultSetList; i++)
1308 req->resultSetList[i] = names[i];
1309 }
1310 else
1311 {
1312 *req->deleteFunction = Z_DeleteResultSetRequest_all;
1313 req->resultSetList = 0;
1314 }
1315
1316 send_apdu(apdu);
1317 printf("Sent deleteResultSetRequest.\n");
1318 return 2;
1319}
1320
1321#if HAVE_XML2
1322static int send_srw(Z_SRW_PDU *sr)
1323{
1324 const char *charset = negotiationCharset;
1325 const char *host_port = cur_host;
1326 char *path = 0;
1327 char ctype[50];
1328 Z_SOAP_Handler h[2] = {
1329 {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
1330 {0, 0, 0}
1331 };
1332 ODR o = odr_createmem(ODR_ENCODE);
1333 int ret;
1334 Z_SOAP *p = odr_malloc(o, sizeof(*p));
1335 Z_GDU *gdu;
1336
1337 path = odr_malloc(out, strlen(databaseNames[0])+2);
1338 *path = '/';
1339 strcpy(path+1, databaseNames[0]);
1340
1341 gdu = z_get_HTTP_Request(out);
1342 gdu->u.HTTP_Request->version = http_version;
1343 gdu->u.HTTP_Request->path = odr_strdup(out, path);
1344
1345 if (host_port)
1346 {
1347 const char *cp0 = strstr(host_port, "://");
1348 const char *cp1 = 0;
1349 if (cp0)
1350 cp0 = cp0+3;
1351 else
1352 cp0 = host_port;
1353
1354 cp1 = strchr(cp0, '/');
1355 if (!cp1)
1356 cp1 = cp0+strlen(cp0);
1357
1358 if (cp0 && cp1)
1359 {
1360 char *h = odr_malloc(out, cp1 - cp0 + 1);
1361 memcpy (h, cp0, cp1 - cp0);
1362 h[cp1-cp0] = '\0';
1363 z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
1364 "Host", h);
1365 }
1366 }
1367
1368 strcpy(ctype, "text/xml");
1369 if (charset && strlen(charset) < 20)
1370 {
1371 strcat(ctype, "; charset=");
1372 strcat(ctype, charset);
1373 }
1374 z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
1375 "Content-Type", ctype);
1376 z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
1377 "SOAPAction", "\"\"");
1378 p->which = Z_SOAP_generic;
1379 p->u.generic = odr_malloc(o, sizeof(*p->u.generic));
1380 p->u.generic->no = 0;
1381 p->u.generic->ns = 0;
1382 p->u.generic->p = sr;
1383 p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
1384
1385 ret = z_soap_codec_enc(o, &p,
1386 &gdu->u.HTTP_Request->content_buf,
1387 &gdu->u.HTTP_Request->content_len, h,
1388 charset);
1389
1390 if (z_GDU(out, &gdu, 0, 0))
1391 {
1392 /* encode OK */
1393 char *buf_out;
1394 int len_out;
1395 int r;
1396 if (apdu_file)
1397 {
1398 if (!z_GDU(print, &gdu, 0, 0))
1399 printf ("Failed to print outgoing APDU\n");
1400 odr_reset(print);
1401 }
1402 buf_out = odr_getbuf(out, &len_out, 0);
1403
1404 /* we don't odr_reset(out), since we may need the buffer again */
1405
1406 do_hex_dump(buf_out, len_out);
1407
1408 r = cs_put(conn, buf_out, len_out);
1409
1410 odr_destroy(o);
1411
1412 if (r >= 0)
1413 return 2;
1414 }
1415 return 0;
1416}
1417#endif
1418
1419#if HAVE_XML2
1420static int send_SRW_scanRequest(const char *arg, int pos, int num)
1421{
1422 Z_SRW_PDU *sr = 0;
1423
1424 /* regular requestse .. */
1425 sr = yaz_srw_get(out, Z_SRW_scan_request);
1426
1427 switch(queryType)
1428 {
1429 case QueryType_CQL:
1430 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
1431 sr->u.scan_request->scanClause.cql = odr_strdup(out, arg);
1432 break;
1433 case QueryType_Prefix:
1434 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
1435 sr->u.scan_request->scanClause.pqf = odr_strdup(out, arg);
1436 break;
1437 default:
1438 printf ("Only CQL and PQF supported in SRW\n");
1439 return 0;
1440 }
1441 sr->u.scan_request->responsePosition = odr_intdup(out, pos);
1442 sr->u.scan_request->maximumTerms = odr_intdup(out, num);
1443 return send_srw(sr);
1444}
1445
1446static int send_SRW_searchRequest(const char *arg)
1447{
1448 Z_SRW_PDU *sr = 0;
1449
1450 if (!srw_sr)
1451 {
1452 assert(srw_sr_odr_out == 0);
1453 srw_sr_odr_out = odr_createmem(ODR_ENCODE);
1454 }
1455 odr_reset(srw_sr_odr_out);
1456
1457 setno = 1;
1458
1459 /* save this for later .. when fetching individual records */
1460 srw_sr = yaz_srw_get(srw_sr_odr_out, Z_SRW_searchRetrieve_request);
1461
1462 /* regular request .. */
1463 sr = yaz_srw_get(out, Z_SRW_searchRetrieve_request);
1464
1465 switch(queryType)
1466 {
1467 case QueryType_CQL:
1468 srw_sr->u.request->query_type = Z_SRW_query_type_cql;
1469 srw_sr->u.request->query.cql = odr_strdup(srw_sr_odr_out, arg);
1470
1471 sr->u.request->query_type = Z_SRW_query_type_cql;
1472 sr->u.request->query.cql = odr_strdup(out, arg);
1473 break;
1474 case QueryType_Prefix:
1475 srw_sr->u.request->query_type = Z_SRW_query_type_pqf;
1476 srw_sr->u.request->query.pqf = odr_strdup(srw_sr_odr_out, arg);
1477
1478 sr->u.request->query_type = Z_SRW_query_type_pqf;
1479 sr->u.request->query.pqf = odr_strdup(out, arg);
1480 break;
1481 default:
1482 printf ("Only CQL and PQF supported in SRW\n");
1483 return 0;
1484 }
1485 sr->u.request->maximumRecords = odr_intdup(out, 0);
1486
1487 if (record_schema)
1488 sr->u.request->recordSchema = record_schema;
1489 if (recordsyntax == VAL_TEXT_XML)
1490 sr->u.explain_request->recordPacking = "xml";
1491 return send_srw(sr);
1492}
1493#endif
1494
1495static int send_searchRequest(const char *arg)
1496{
1497 Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
1498 Z_SearchRequest *req = apdu->u.searchRequest;
1499 Z_Query query;
1500 struct ccl_rpn_node *rpn = NULL;
1501 int error, pos;
1502 char setstring[100];
1503 Z_RPNQuery *RPNquery;
1504 Odr_oct ccl_query;
1505 YAZ_PQF_Parser pqf_parser;
1506 Z_External *ext;
1507 QueryType myQueryType = queryType;
1508 char pqfbuf[512];
1509
1510 if (myQueryType == QueryType_CCL2RPN)
1511 {
1512 rpn = ccl_find_str(bibset, arg, &error, &pos);
1513 if (error)
1514 {
1515 printf("CCL ERROR: %s\n", ccl_err_msg(error));
1516 return 0;
1517 }
1518 } else if (myQueryType == QueryType_CQL2RPN) {
1519 /* ### All this code should be wrapped in a utility function */
1520 CQL_parser parser;
1521 struct cql_node *node;
1522 const char *addinfo;
1523 if (cqltrans == 0) {
1524 printf("Can't use CQL: no translation file. Try set_cqlfile\n");
1525 return 0;
1526 }
1527 parser = cql_parser_create();
1528 if ((error = cql_parser_string(parser, arg)) != 0) {
1529 printf("Can't parse CQL: must be a syntax error\n");
1530 return 0;
1531 }
1532 node = cql_parser_result(parser);
1533 if ((error = cql_transform_buf(cqltrans, node, pqfbuf,
1534 sizeof pqfbuf)) != 0) {
1535 error = cql_transform_error(cqltrans, &addinfo);
1536 printf ("Can't convert CQL to PQF: %s (addinfo=%s)\n",
1537 cql_strerror(error), addinfo);
1538 return 0;
1539 }
1540 arg = pqfbuf;
1541 myQueryType = QueryType_Prefix;
1542 }
1543
1544 req->referenceId = set_refid (out);
1545 if (!strcmp(arg, "@big")) /* strictly for troublemaking */
1546 {
1547 static unsigned char big[2100];
1548 static Odr_oct bigo;
1549
1550 /* send a very big referenceid to test transport stack etc. */
1551 memset(big, 'A', 2100);
1552 bigo.len = bigo.size = 2100;
1553 bigo.buf = big;
1554 req->referenceId = &bigo;
1555 }
1556
1557 if (setnumber >= 0)
1558 {
1559 sprintf(setstring, "%d", ++setnumber);
1560 req->resultSetName = setstring;
1561 }
1562 *req->smallSetUpperBound = smallSetUpperBound;
1563 *req->largeSetLowerBound = largeSetLowerBound;
1564 *req->mediumSetPresentNumber = mediumSetPresentNumber;
1565 if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
1566 mediumSetPresentNumber > 0))
1567 {
1568 req->preferredRecordSyntax =
1569 yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
1570
1571 req->smallSetElementSetNames =
1572 req->mediumSetElementSetNames = elementSetNames;
1573 }
1574 req->num_databaseNames = num_databaseNames;
1575 req->databaseNames = databaseNames;
1576
1577 req->query = &query;
1578
1579 switch (myQueryType)
1580 {
1581 case QueryType_Prefix:
1582 query.which = Z_Query_type_1;
1583 pqf_parser = yaz_pqf_create ();
1584 RPNquery = yaz_pqf_parse (pqf_parser, out, arg);
1585 if (!RPNquery)
1586 {
1587 const char *pqf_msg;
1588 size_t off;
1589 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
1590 printf("%*s^\n", off+4, "");
1591 printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
1592
1593 yaz_pqf_destroy (pqf_parser);
1594 return 0;
1595 }
1596 yaz_pqf_destroy (pqf_parser);
1597 query.u.type_1 = RPNquery;
1598 break;
1599 case QueryType_CCL:
1600 query.which = Z_Query_type_2;
1601 query.u.type_2 = &ccl_query;
1602 ccl_query.buf = (unsigned char*) arg;
1603 ccl_query.len = strlen(arg);
1604 break;
1605 case QueryType_CCL2RPN:
1606 query.which = Z_Query_type_1;
1607 RPNquery = ccl_rpn_query(out, rpn);
1608 if (!RPNquery)
1609 {
1610 printf ("Couldn't convert from CCL to RPN\n");
1611 return 0;
1612 }
1613 query.u.type_1 = RPNquery;
1614 ccl_rpn_delete (rpn);
1615 break;
1616 case QueryType_CQL:
1617 query.which = Z_Query_type_104;
1618 ext = (Z_External *) odr_malloc(out, sizeof(*ext));
1619 ext->direct_reference = odr_getoidbystr(out, "1.2.840.10003.16.2");
1620 ext->indirect_reference = 0;
1621 ext->descriptor = 0;
1622 ext->which = Z_External_CQL;
1623 ext->u.cql = odr_strdup(out, arg);
1624 query.u.type_104 = ext;
1625 break;
1626 default:
1627 printf ("Unsupported query type\n");
1628 return 0;
1629 }
1630 send_apdu(apdu);
1631 /*
1632 if (send_apdu(apdu))
1633 printf("Sent searchRequest.\n");*/
1634 setno = 1;
1635 return 2;
1636}
1637
1638/* display Query Expression as part of searchResult-1 */
1639/*
1640static void display_queryExpression (Z_QueryExpression *qe)
1641{
1642 if (!qe)
1643 return;
1644 if (qe->which == Z_QueryExpression_term)
1645 {
1646 if (qe->u.term->queryTerm)
1647 {
1648 Z_Term *term = qe->u.term->queryTerm;
1649 switch (term->which)
1650 {
1651 case Z_Term_general:
1652 printf (" %.*s", term->u.general->len, term->u.general->buf);
1653 break;
1654 case Z_Term_characterString:
1655 printf (" %s", term->u.characterString);
1656 break;
1657 case Z_Term_numeric:
1658 printf (" %d", *term->u.numeric);
1659 break;
1660 case Z_Term_null:
1661 printf (" null");
1662 break;
1663 }
1664 }
1665 }
1666}
1667*/
1668/* see if we can find USR:SearchResult-1 */
1669/*
1670static void display_searchResult (Z_OtherInformation *o)
1671{
1672 int i;
1673 if (!o)
1674 return ;
1675 for (i = 0; i < o->num_elements; i++)
1676 {
1677 if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo)
1678 {
1679 Z_External *ext = o->list[i]->information.externallyDefinedInfo;
1680
1681 if (ext->which == Z_External_searchResult1)
1682 {
1683 int j;
1684 Z_SearchInfoReport *sr = ext->u.searchResult1;
1685 printf ("SearchResult-1:");
1686 for (j = 0; j < sr->num; j++)
1687 {
1688 if (!sr->elements[j]->subqueryExpression)
1689 printf (" %d", j);
1690 display_queryExpression (
1691 sr->elements[j]->subqueryExpression);
1692 display_queryExpression (
1693 sr->elements[j]->subqueryInterpretation);
1694 display_queryExpression (
1695 sr->elements[j]->subqueryRecommendation);
1696 if (sr->elements[j]->subqueryCount)
1697 printf ("(%d)", *sr->elements[j]->subqueryCount);
1698 }
1699 printf ("\n");
1700 }
1701 }
1702 }
1703}
1704*/
1705/* kjdon: modified to not print the results, and return the number of hits */
1706static int process_searchResponse(Z_SearchResponse *res)
1707{
1708 print_refid (res->referenceId);
1709 if (!(*res->searchStatus)) {
1710 /* this should return an error instead of 0 docs found... one day... */
1711 return 0;
1712 }
1713 setno += *res->numberOfRecordsReturned;
1714 /* what is this for? */
1715 if (res->records)
1716 display_records(res->records);
1717 return *res->resultCount;
1718
1719}
1720
1721static void print_level(int iLevel)
1722{
1723 int i;
1724 for (i = 0; i < iLevel * 4; i++)
1725 printf(" ");
1726}
1727
1728static void print_int(int iLevel, const char *pTag, int *pInt)
1729{
1730 if (pInt != NULL)
1731 {
1732 print_level(iLevel);
1733 printf("%s: %d\n", pTag, *pInt);
1734 }
1735}
1736
1737static void print_string(int iLevel, const char *pTag, const char *pString)
1738{
1739 if (pString != NULL)
1740 {
1741 print_level(iLevel);
1742 printf("%s: %s\n", pTag, pString);
1743 }
1744}
1745
1746static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
1747{
1748 if (pOid != NULL)
1749 {
1750 int *pInt = pOid;
1751
1752 print_level(iLevel);
1753 printf("%s:", pTag);
1754 for (; *pInt != -1; pInt++)
1755 printf(" %d", *pInt);
1756 printf("\n");
1757 }
1758}
1759
1760static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
1761{
1762 if (referenceId != NULL)
1763 {
1764 int i;
1765
1766 print_level(iLevel);
1767 printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
1768 for (i = 0; i < referenceId->len; i++)
1769 printf("%c", referenceId->buf[i]);
1770 printf("\n");
1771 }
1772}
1773
1774static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
1775{
1776 if (pStringNumeric != NULL)
1777 {
1778 switch (pStringNumeric->which)
1779 {
1780 case Z_StringOrNumeric_string:
1781 print_string(iLevel, pTag, pStringNumeric->u.string);
1782 break;
1783
1784 case Z_StringOrNumeric_numeric:
1785 print_int(iLevel, pTag, pStringNumeric->u.numeric);
1786 break;
1787
1788 default:
1789 print_level(iLevel);
1790 printf("%s: valid type for Z_StringOrNumeric\n", pTag);
1791 break;
1792 }
1793 }
1794}
1795
1796static void print_universe_report_duplicate(
1797 int iLevel,
1798 Z_UniverseReportDuplicate *pUniverseReportDuplicate)
1799{
1800 if (pUniverseReportDuplicate != NULL)
1801 {
1802 print_level(iLevel);
1803 printf("Universe Report Duplicate: \n");
1804 iLevel++;
1805 print_string_or_numeric(iLevel, "Hit No",
1806 pUniverseReportDuplicate->hitno);
1807 }
1808}
1809
1810static void print_universe_report_hits(
1811 int iLevel,
1812 Z_UniverseReportHits *pUniverseReportHits)
1813{
1814 if (pUniverseReportHits != NULL)
1815 {
1816 print_level(iLevel);
1817 printf("Universe Report Hits: \n");
1818 iLevel++;
1819 print_string_or_numeric(iLevel, "Database",
1820 pUniverseReportHits->database);
1821 print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
1822 }
1823}
1824
1825static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
1826{
1827 if (pUniverseReport != NULL)
1828 {
1829 print_level(iLevel);
1830 printf("Universe Report: \n");
1831 iLevel++;
1832 print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
1833 switch (pUniverseReport->which)
1834 {
1835 case Z_UniverseReport_databaseHits:
1836 print_universe_report_hits(iLevel,
1837 pUniverseReport->u.databaseHits);
1838 break;
1839
1840 case Z_UniverseReport_duplicate:
1841 print_universe_report_duplicate(iLevel,
1842 pUniverseReport->u.duplicate);
1843 break;
1844
1845 default:
1846 print_level(iLevel);
1847 printf("Type: %d\n", pUniverseReport->which);
1848 break;
1849 }
1850 }
1851}
1852
1853static void print_external(int iLevel, Z_External *pExternal)
1854{
1855 if (pExternal != NULL)
1856 {
1857 print_level(iLevel);
1858 printf("External: \n");
1859 iLevel++;
1860 print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
1861 print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
1862 print_string(iLevel, "Descriptor", pExternal->descriptor);
1863 switch (pExternal->which)
1864 {
1865 case Z_External_universeReport:
1866 print_universe_report(iLevel, pExternal->u.universeReport);
1867 break;
1868
1869 default:
1870 print_level(iLevel);
1871 printf("Type: %d\n", pExternal->which);
1872 break;
1873 }
1874 }
1875}
1876
1877static int process_resourceControlRequest (Z_ResourceControlRequest *req)
1878{
1879 printf ("Received ResourceControlRequest.\n");
1880 print_referenceId(1, req->referenceId);
1881 print_int(1, "Suspended Flag", req->suspendedFlag);
1882 print_int(1, "Partial Results Available", req->partialResultsAvailable);
1883 print_int(1, "Response Required", req->responseRequired);
1884 print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
1885 print_external(1, req->resourceReport);
1886 return 0;
1887}
1888
1889void process_ESResponse(Z_ExtendedServicesResponse *res)
1890{
1891 printf("Status: ");
1892 switch (*res->operationStatus)
1893 {
1894 case Z_ExtendedServicesResponse_done:
1895 printf ("done\n");
1896 break;
1897 case Z_ExtendedServicesResponse_accepted:
1898 printf ("accepted\n");
1899 break;
1900 case Z_ExtendedServicesResponse_failure:
1901 printf ("failure\n");
1902 display_diagrecs(res->diagnostics, res->num_diagnostics);
1903 break;
1904 default:
1905 printf ("unknown\n");
1906 }
1907 if ( (*res->operationStatus != Z_ExtendedServicesResponse_failure) &&
1908 (res->num_diagnostics != 0) ) {
1909 display_diagrecs(res->diagnostics, res->num_diagnostics);
1910 }
1911 print_refid (res->referenceId);
1912 if (res->taskPackage &&
1913 res->taskPackage->which == Z_External_extendedService)
1914 {
1915 Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
1916 Odr_oct *id = taskPackage->targetReference;
1917 Z_External *ext = taskPackage->taskSpecificParameters;
1918
1919 if (id)
1920 {
1921 printf ("Target Reference: ");
1922 print_stringn (id->buf, id->len);
1923 printf ("\n");
1924 }
1925 if (ext->which == Z_External_update)
1926 {
1927 Z_IUUpdateTaskPackage *utp = ext->u.update->u.taskPackage;
1928 if (utp && utp->targetPart)
1929 {
1930 Z_IUTargetPart *targetPart = utp->targetPart;
1931 int i;
1932
1933 for (i = 0; i<targetPart->num_taskPackageRecords; i++)
1934 {
1935
1936 Z_IUTaskPackageRecordStructure *tpr =
1937 targetPart->taskPackageRecords[i];
1938 printf ("task package record %d\n", i+1);
1939 if (tpr->which == Z_IUTaskPackageRecordStructure_record)
1940 {
1941 display_record (tpr->u.record);
1942 }
1943 else
1944 {
1945 printf ("other type\n");
1946 }
1947 }
1948 }
1949 }
1950 }
1951}
1952
1953const char *get_ill_element (void *clientData, const char *element)
1954{
1955 return 0;
1956}
1957
1958static Z_External *create_external_itemRequest()
1959{
1960 struct ill_get_ctl ctl;
1961 ILL_ItemRequest *req;
1962 Z_External *r = 0;
1963 int item_request_size = 0;
1964 char *item_request_buf = 0;
1965
1966 ctl.odr = out;
1967 ctl.clientData = 0;
1968 ctl.f = get_ill_element;
1969
1970 req = ill_get_ItemRequest(&ctl, "ill", 0);
1971 if (!req)
1972 printf ("ill_get_ItemRequest failed\n");
1973
1974 if (!ill_ItemRequest (out, &req, 0, 0))
1975 {
1976 if (apdu_file)
1977 {
1978 ill_ItemRequest(print, &req, 0, 0);
1979 odr_reset(print);
1980 }
1981 item_request_buf = odr_getbuf (out, &item_request_size, 0);
1982 if (item_request_buf)
1983 odr_setbuf (out, item_request_buf, item_request_size, 1);
1984 printf ("Couldn't encode ItemRequest, size %d\n", item_request_size);
1985 return 0;
1986 }
1987 else
1988 {
1989 oident oid;
1990
1991 item_request_buf = odr_getbuf (out, &item_request_size, 0);
1992 oid.proto = PROTO_GENERAL;
1993 oid.oclass = CLASS_GENERAL;
1994 oid.value = VAL_ISO_ILL_1;
1995
1996 r = (Z_External *) odr_malloc (out, sizeof(*r));
1997 r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid));
1998 r->indirect_reference = 0;
1999 r->descriptor = 0;
2000 r->which = Z_External_single;
2001
2002 r->u.single_ASN1_type = (Odr_oct *)
2003 odr_malloc (out, sizeof(*r->u.single_ASN1_type));
2004 r->u.single_ASN1_type->buf = (unsigned char *)
2005 odr_malloc (out, item_request_size);
2006 r->u.single_ASN1_type->len = item_request_size;
2007 r->u.single_ASN1_type->size = item_request_size;
2008 memcpy (r->u.single_ASN1_type->buf, item_request_buf,
2009 item_request_size);
2010
2011 do_hex_dump(item_request_buf,item_request_size);
2012 }
2013 return r;
2014}
2015
2016static Z_External *create_external_ILL_APDU(int which)
2017{
2018 struct ill_get_ctl ctl;
2019 ILL_APDU *ill_apdu;
2020 Z_External *r = 0;
2021 int ill_request_size = 0;
2022 char *ill_request_buf = 0;
2023
2024 ctl.odr = out;
2025 ctl.clientData = 0;
2026 ctl.f = get_ill_element;
2027
2028 ill_apdu = ill_get_APDU(&ctl, "ill", 0);
2029
2030 if (!ill_APDU (out, &ill_apdu, 0, 0))
2031 {
2032 if (apdu_file)
2033 {
2034 printf ("-------------------\n");
2035 ill_APDU(print, &ill_apdu, 0, 0);
2036 odr_reset(print);
2037 printf ("-------------------\n");
2038 }
2039 ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
2040 if (ill_request_buf)
2041 odr_setbuf (out, ill_request_buf, ill_request_size, 1);
2042 printf ("Couldn't encode ILL-Request, size %d\n", ill_request_size);
2043 return 0;
2044 }
2045 else
2046 {
2047 oident oid;
2048 ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
2049
2050 oid.proto = PROTO_GENERAL;
2051 oid.oclass = CLASS_GENERAL;
2052 oid.value = VAL_ISO_ILL_1;
2053
2054 r = (Z_External *) odr_malloc (out, sizeof(*r));
2055 r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid));
2056 r->indirect_reference = 0;
2057 r->descriptor = 0;
2058 r->which = Z_External_single;
2059
2060 r->u.single_ASN1_type = (Odr_oct *)
2061 odr_malloc (out, sizeof(*r->u.single_ASN1_type));
2062 r->u.single_ASN1_type->buf = (unsigned char *)
2063 odr_malloc (out, ill_request_size);
2064 r->u.single_ASN1_type->len = ill_request_size;
2065 r->u.single_ASN1_type->size = ill_request_size;
2066 memcpy (r->u.single_ASN1_type->buf, ill_request_buf, ill_request_size);
2067/* printf ("len = %d\n", ill_request_size); */
2068/* do_hex_dump(ill_request_buf,ill_request_size); */
2069/* printf("--- end of extenal\n"); */
2070
2071 }
2072 return r;
2073}
2074
2075
2076static Z_External *create_ItemOrderExternal(const char *type, int itemno)
2077{
2078 Z_External *r = (Z_External *) odr_malloc(out, sizeof(Z_External));
2079 oident ItemOrderRequest;
2080
2081 ItemOrderRequest.proto = PROTO_Z3950;
2082 ItemOrderRequest.oclass = CLASS_EXTSERV;
2083 ItemOrderRequest.value = VAL_ITEMORDER;
2084
2085 r->direct_reference = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest));
2086 r->indirect_reference = 0;
2087 r->descriptor = 0;
2088
2089 r->which = Z_External_itemOrder;
2090
2091 r->u.itemOrder = (Z_ItemOrder *) odr_malloc(out,sizeof(Z_ItemOrder));
2092 memset(r->u.itemOrder, 0, sizeof(Z_ItemOrder));
2093 r->u.itemOrder->which=Z_IOItemOrder_esRequest;
2094
2095 r->u.itemOrder->u.esRequest = (Z_IORequest *)
2096 odr_malloc(out,sizeof(Z_IORequest));
2097 memset(r->u.itemOrder->u.esRequest, 0, sizeof(Z_IORequest));
2098
2099 r->u.itemOrder->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
2100 odr_malloc(out,sizeof(Z_IOOriginPartToKeep));
2101 memset(r->u.itemOrder->u.esRequest->toKeep, 0, sizeof(Z_IOOriginPartToKeep));
2102 r->u.itemOrder->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
2103 odr_malloc(out,sizeof(Z_IOOriginPartNotToKeep));
2104 memset(r->u.itemOrder->u.esRequest->notToKeep, 0, sizeof(Z_IOOriginPartNotToKeep));
2105
2106 r->u.itemOrder->u.esRequest->toKeep->supplDescription = NULL;
2107 r->u.itemOrder->u.esRequest->toKeep->contact = NULL;
2108 r->u.itemOrder->u.esRequest->toKeep->addlBilling = NULL;
2109
2110 r->u.itemOrder->u.esRequest->notToKeep->resultSetItem =
2111 (Z_IOResultSetItem *) odr_malloc(out, sizeof(Z_IOResultSetItem));
2112 memset(r->u.itemOrder->u.esRequest->notToKeep->resultSetItem, 0, sizeof(Z_IOResultSetItem));
2113 r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->resultSetId = "1";
2114
2115 r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item =
2116 (int *) odr_malloc(out, sizeof(int));
2117 *r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item = itemno;
2118
2119 if (!strcmp (type, "item") || !strcmp(type, "2"))
2120 {
2121 printf ("using item-request\n");
2122 r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
2123 create_external_itemRequest();
2124 }
2125 else if (!strcmp(type, "ill") || !strcmp(type, "1"))
2126 {
2127 printf ("using ILL-request\n");
2128 r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
2129 create_external_ILL_APDU(ILL_APDU_ILL_Request);
2130 }
2131 else if (!strcmp(type, "xml") || !strcmp(type, "3"))
2132 {
2133 const char *xml_buf =
2134 "<itemorder>\n"
2135 " <type>request</type>\n"
2136 " <libraryNo>000200</libraryNo>\n"
2137 " <borrowerTicketNo> 1212 </borrowerTicketNo>\n"
2138 "</itemorder>";
2139 r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
2140 z_ext_record (out, VAL_TEXT_XML, xml_buf, strlen(xml_buf));
2141 }
2142 else
2143 r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
2144
2145 return r;
2146}
2147
2148static int send_itemorder(const char *type, int itemno)
2149{
2150 Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
2151 Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
2152 oident ItemOrderRequest;
2153
2154 ItemOrderRequest.proto = PROTO_Z3950;
2155 ItemOrderRequest.oclass = CLASS_EXTSERV;
2156 ItemOrderRequest.value = VAL_ITEMORDER;
2157 req->packageType = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest));
2158 req->packageName = esPackageName;
2159
2160 req->taskSpecificParameters = create_ItemOrderExternal(type, itemno);
2161
2162 send_apdu(apdu);
2163 return 0;
2164}
2165
2166static int only_z3950()
2167{
2168 if (protocol == PROTO_HTTP)
2169 {
2170 printf ("Not supported by SRW\n");
2171 return 1;
2172 }
2173 return 0;
2174}
2175
2176
2177static int cmd_update_common(const char *arg, int version);
2178
2179static int cmd_update(const char *arg)
2180{
2181 return cmd_update_common(arg, 1);
2182}
2183
2184static int cmd_update0(const char *arg)
2185{
2186 return cmd_update_common(arg, 0);
2187}
2188
2189static int cmd_update_common(const char *arg, int version)
2190{
2191 Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
2192 Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
2193 Z_External *r;
2194 char action[20], recid[20], fname[80];
2195 int action_no;
2196 Z_External *record_this = 0;
2197
2198 if (only_z3950())
2199 return 0;
2200 *action = 0;
2201 *recid = 0;
2202 *fname = 0;
2203 sscanf (arg, "%19s %19s %79s", action, recid, fname);
2204
2205 if (!strcmp (action, "insert"))
2206 action_no = Z_IUOriginPartToKeep_recordInsert;
2207 else if (!strcmp (action, "replace"))
2208 action_no = Z_IUOriginPartToKeep_recordReplace;
2209 else if (!strcmp (action, "delete"))
2210 action_no = Z_IUOriginPartToKeep_recordDelete;
2211 else if (!strcmp (action, "update"))
2212 action_no = Z_IUOriginPartToKeep_specialUpdate;
2213 else
2214 {
2215 printf ("Bad action: %s\n", action);
2216 printf ("Possible values: insert, replace, delete, update\n");
2217 return 0;
2218 }
2219
2220 if (*fname)
2221 {
2222 FILE *inf;
2223 struct stat status;
2224 stat (fname, &status);
2225 if (S_ISREG(status.st_mode) && (inf = fopen(fname, "rb")))
2226 {
2227 size_t len = status.st_size;
2228 char *buf = (char *) xmalloc (len);
2229
2230 fread (buf, 1, len, inf);
2231
2232 fclose (inf);
2233
2234 record_this = z_ext_record (out, VAL_TEXT_XML, buf, len);
2235
2236 xfree (buf);
2237 }
2238 else
2239 {
2240 printf ("File %s doesn't exist\n", fname);
2241 return 0;
2242 }
2243 }
2244 else
2245 {
2246 if (!record_last)
2247 {
2248 printf ("No last record (update ignored)\n");
2249 return 0;
2250 }
2251 record_this = record_last;
2252 }
2253
2254 req->packageType =
2255 yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
2256 version == 0 ? VAL_DBUPDATE0 : VAL_DBUPDATE);
2257
2258 req->packageName = esPackageName;
2259
2260 req->referenceId = set_refid (out);
2261
2262 r = req->taskSpecificParameters = (Z_External *)
2263 odr_malloc (out, sizeof(*r));
2264 r->direct_reference = req->packageType;
2265 r->indirect_reference = 0;
2266 r->descriptor = 0;
2267 if (version == 0)
2268 {
2269 Z_IU0OriginPartToKeep *toKeep;
2270 Z_IU0SuppliedRecords *notToKeep;
2271
2272 r->which = Z_External_update0;
2273 r->u.update0 = (Z_IU0Update *) odr_malloc(out, sizeof(*r->u.update0));
2274 r->u.update0->which = Z_IUUpdate_esRequest;
2275 r->u.update0->u.esRequest = (Z_IU0UpdateEsRequest *)
2276 odr_malloc(out, sizeof(*r->u.update0->u.esRequest));
2277 toKeep = r->u.update0->u.esRequest->toKeep = (Z_IU0OriginPartToKeep *)
2278 odr_malloc(out, sizeof(*r->u.update0->u.esRequest->toKeep));
2279
2280 toKeep->databaseName = databaseNames[0];
2281 toKeep->schema = 0;
2282 toKeep->elementSetName = 0;
2283
2284 toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
2285 *toKeep->action = action_no;
2286
2287 notToKeep = r->u.update0->u.esRequest->notToKeep = (Z_IU0SuppliedRecords *)
2288 odr_malloc(out, sizeof(*r->u.update0->u.esRequest->notToKeep));
2289 notToKeep->num = 1;
2290 notToKeep->elements = (Z_IU0SuppliedRecords_elem **)
2291 odr_malloc(out, sizeof(*notToKeep->elements));
2292 notToKeep->elements[0] = (Z_IU0SuppliedRecords_elem *)
2293 odr_malloc(out, sizeof(**notToKeep->elements));
2294 notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
2295 if (*recid)
2296 {
2297 notToKeep->elements[0]->u.opaque = (Odr_oct *)
2298 odr_malloc (out, sizeof(Odr_oct));
2299 notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
2300 notToKeep->elements[0]->u.opaque->size = strlen(recid);
2301 notToKeep->elements[0]->u.opaque->len = strlen(recid);
2302 }
2303 else
2304 notToKeep->elements[0]->u.opaque = 0;
2305 notToKeep->elements[0]->supplementalId = 0;
2306 notToKeep->elements[0]->correlationInfo = 0;
2307 notToKeep->elements[0]->record = record_this;
2308 }
2309 else
2310 {
2311 Z_IUOriginPartToKeep *toKeep;
2312 Z_IUSuppliedRecords *notToKeep;
2313
2314 r->which = Z_External_update;
2315 r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
2316 r->u.update->which = Z_IUUpdate_esRequest;
2317 r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
2318 odr_malloc(out, sizeof(*r->u.update->u.esRequest));
2319 toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
2320 odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
2321
2322 toKeep->databaseName = databaseNames[0];
2323 toKeep->schema = 0;
2324 toKeep->elementSetName = 0;
2325 toKeep->actionQualifier = 0;
2326 toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
2327 *toKeep->action = action_no;
2328
2329 notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
2330 odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
2331 notToKeep->num = 1;
2332 notToKeep->elements = (Z_IUSuppliedRecords_elem **)
2333 odr_malloc(out, sizeof(*notToKeep->elements));
2334 notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
2335 odr_malloc(out, sizeof(**notToKeep->elements));
2336 notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
2337 if (*recid)
2338 {
2339 notToKeep->elements[0]->u.opaque = (Odr_oct *)
2340 odr_malloc (out, sizeof(Odr_oct));
2341 notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
2342 notToKeep->elements[0]->u.opaque->size = strlen(recid);
2343 notToKeep->elements[0]->u.opaque->len = strlen(recid);
2344 }
2345 else
2346 notToKeep->elements[0]->u.opaque = 0;
2347 notToKeep->elements[0]->supplementalId = 0;
2348 notToKeep->elements[0]->correlationInfo = 0;
2349 notToKeep->elements[0]->record = record_this;
2350 }
2351
2352 send_apdu(apdu);
2353
2354 return 2;
2355}
2356
2357
2358static int cmd_itemorder(const char *arg)
2359{
2360 char type[12];
2361 int itemno;
2362
2363 if (only_z3950())
2364 return 0;
2365 if (sscanf (arg, "%10s %d", type, &itemno) != 2)
2366 return 0;
2367
2368 printf("Item order request\n");
2369 fflush(stdout);
2370 send_itemorder(type, itemno);
2371 return 2;
2372}
2373
2374static void show_opt(const char *arg, void *clientData)
2375{
2376 printf ("%s ", arg);
2377}
2378
2379static int cmd_zversion(const char *arg)
2380{
2381 if (*arg && arg)
2382 z3950_version = atoi(arg);
2383 else
2384 printf ("version is %d\n", z3950_version);
2385 return 0;
2386}
2387
2388static int cmd_options(const char *arg)
2389{
2390 if (*arg)
2391 {
2392 int r;
2393 int pos;
2394 r = yaz_init_opt_encode(&z3950_options, arg, &pos);
2395 }
2396 else
2397 {
2398 yaz_init_opt_decode(&z3950_options, show_opt, 0);
2399 printf ("\n");
2400 }
2401 return 0;
2402}
2403
2404static int cmd_explain(const char *arg)
2405{
2406 if (protocol != PROTO_HTTP)
2407 return 0;
2408#if HAVE_XML2
2409 if (!conn)
2410 cmd_open(0);
2411 if (conn)
2412 {
2413 Z_SRW_PDU *sr = 0;
2414
2415 setno = 1;
2416
2417 /* save this for later .. when fetching individual records */
2418 sr = yaz_srw_get(out, Z_SRW_explain_request);
2419 if (recordsyntax == VAL_TEXT_XML)
2420 sr->u.explain_request->recordPacking = "xml";
2421 send_srw(sr);
2422 return 2;
2423 }
2424#endif
2425 return 0;
2426}
2427
2428static int cmd_init(const char *arg)
2429{
2430 if (*arg)
2431 {
2432 strncpy (cur_host, arg, sizeof(cur_host)-1);
2433 cur_host[sizeof(cur_host)-1] = 0;
2434 }
2435 if (!conn || protocol != PROTO_Z3950)
2436 return 0;
2437 send_initRequest(cur_host);
2438 return 2;
2439
2440}
2441
2442static int cmd_find(const char *arg)
2443{
2444 if (!*arg)
2445 {
2446 printf("Find what?\n");
2447 return 0;
2448 }
2449 if (protocol == PROTO_HTTP)
2450 {
2451#if HAVE_XML2
2452 if (!conn)
2453 cmd_open(0);
2454 if (!conn)
2455 return 0;
2456 if (!send_SRW_searchRequest(arg))
2457 return 0;
2458#else
2459 return 0;
2460#endif
2461 }
2462 else
2463 {
2464 if (!conn)
2465 {
2466 try_reconnect();
2467
2468 if (!conn) {
2469 printf("Not connected yet\n");
2470 return 0;
2471 }
2472 }
2473 if (!send_searchRequest(arg))
2474 return 0;
2475 }
2476 return 2;
2477}
2478
2479static int cmd_delete(const char *arg)
2480{
2481 if (!conn)
2482 {
2483 printf("Not connected yet\n");
2484 return 0;
2485 }
2486 if (only_z3950())
2487 return 0;
2488 if (!send_deleteResultSetRequest(arg))
2489 return 0;
2490 return 2;
2491}
2492
2493static int cmd_ssub(const char *arg)
2494{
2495 if (!(smallSetUpperBound = atoi(arg)))
2496 return 0;
2497 return 1;
2498}
2499
2500static int cmd_lslb(const char *arg)
2501{
2502 if (only_z3950())
2503 return 0;
2504 if (!(largeSetLowerBound = atoi(arg)))
2505 return 0;
2506 return 1;
2507}
2508
2509static int cmd_mspn(const char *arg)
2510{
2511 if (only_z3950())
2512 return 0;
2513 if (!(mediumSetPresentNumber = atoi(arg)))
2514 return 0;
2515 return 1;
2516}
2517
2518static int cmd_status(const char *arg)
2519{
2520 printf("smallSetUpperBound: %d\n", smallSetUpperBound);
2521 printf("largeSetLowerBound: %d\n", largeSetLowerBound);
2522 printf("mediumSetPresentNumber: %d\n", mediumSetPresentNumber);
2523 return 1;
2524}
2525
2526static int cmd_setnames(const char *arg)
2527{
2528 if (*arg == '1') /* enable ? */
2529 setnumber = 0;
2530 else if (*arg == '0') /* disable ? */
2531 setnumber = -1;
2532 else if (setnumber < 0) /* no args, toggle .. */
2533 setnumber = 0;
2534 else
2535 setnumber = -1;
2536
2537 if (setnumber >= 0)
2538 printf("Set numbering enabled.\n");
2539 else
2540 printf("Set numbering disabled.\n");
2541 return 1;
2542}
2543
2544/* PRESENT SERVICE ----------------------------- */
2545/* this one is based on johnmcps version - pretty much a copy of
2546 send_presentRequest, but passing in separate args, not an arg string */
2547int z_send_getbriefrecords(int starting, int set, int howmany) {
2548
2549 Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
2550 Z_PresentRequest *req = apdu->u.presentRequest;
2551 Z_RecordComposition compo;
2552 int nos = 1;
2553 char setstring[100];
2554
2555 req->referenceId = set_refid (out);
2556 nos = howmany;
2557 setno = starting;
2558 sprintf(setstring, "%d", setnumber);
2559 req->resultSetId = setstring;
2560 req->resultSetStartPoint = &setno;
2561 req->numberOfRecordsRequested = &nos;
2562
2563 req->preferredRecordSyntax =
2564 yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
2565
2566 if (record_schema)
2567 {
2568 req->recordComposition = &compo;
2569 compo.which = Z_RecordComp_complex;
2570 compo.u.complex = (Z_CompSpec *)
2571 odr_malloc(out, sizeof(*compo.u.complex));
2572 compo.u.complex->selectAlternativeSyntax = (bool_t *)
2573 odr_malloc(out, sizeof(bool_t));
2574 *compo.u.complex->selectAlternativeSyntax = 0;
2575
2576 compo.u.complex->generic = (Z_Specification *)
2577 odr_malloc(out, sizeof(*compo.u.complex->generic));
2578 compo.u.complex->generic->which = Z_Schema_oid;
2579
2580 compo.u.complex->generic->schema.oid =
2581 yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
2582
2583 if (!compo.u.complex->generic->schema.oid)
2584 {
2585 /* OID wasn't a schema! Try record syntax instead. */
2586 compo.u.complex->generic->schema.oid = (Odr_oid *)
2587 yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
2588 }
2589 if (!elementSetNames)
2590 compo.u.complex->generic->elementSpec = 0;
2591 else
2592 {
2593 compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
2594 odr_malloc(out, sizeof(Z_ElementSpec));
2595 compo.u.complex->generic->elementSpec->which =
2596 Z_ElementSpec_elementSetName;
2597 compo.u.complex->generic->elementSpec->u.elementSetName =
2598 elementSetNames->u.generic;
2599 }
2600 compo.u.complex->num_dbSpecific = 0;
2601 compo.u.complex->dbSpecific = 0;
2602 compo.u.complex->num_recordSyntax = 0;
2603 compo.u.complex->recordSyntax = 0;
2604 }
2605 else if (elementSetNames)
2606 {
2607 req->recordComposition = &compo;
2608 compo.which = Z_RecordComp_simple;
2609 compo.u.simple = elementSetNames;
2610 }
2611 send_apdu(apdu);
2612 return 0;
2613}
2614
2615static void parse_show_args(const char *arg_c, char *setstring,
2616 int *start, int *number)
2617{
2618 char arg[40];
2619 char *p;
2620
2621 strncpy(arg, arg_c, sizeof(arg)-1);
2622 arg[sizeof(arg)-1] = '\0';
2623
2624 if ((p = strchr(arg, '+')))
2625 {
2626 *number = atoi(p + 1);
2627 *p = '\0';
2628 }
2629 if (*arg)
2630 *start = atoi(arg);
2631 if (p && (p=strchr(p+1, '+')))
2632 strcpy (setstring, p+1);
2633 else if (setnumber >= 0)
2634 sprintf(setstring, "%d", setnumber);
2635 else
2636 *setstring = '\0';
2637}
2638
2639static int send_presentRequest(const char *arg)
2640{
2641 Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
2642 Z_PresentRequest *req = apdu->u.presentRequest;
2643 Z_RecordComposition compo;
2644 int nos = 1;
2645 char setstring[100];
2646
2647 req->referenceId = set_refid (out);
2648
2649 parse_show_args(arg, setstring, &setno, &nos);
2650 if (*setstring)
2651 req->resultSetId = setstring;
2652
2653 req->resultSetStartPoint = &setno;
2654 req->numberOfRecordsRequested = &nos;
2655
2656 req->preferredRecordSyntax =
2657 yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
2658
2659 if (record_schema)
2660 {
2661 req->recordComposition = &compo;
2662 compo.which = Z_RecordComp_complex;
2663 compo.u.complex = (Z_CompSpec *)
2664 odr_malloc(out, sizeof(*compo.u.complex));
2665 compo.u.complex->selectAlternativeSyntax = (bool_t *)
2666 odr_malloc(out, sizeof(bool_t));
2667 *compo.u.complex->selectAlternativeSyntax = 0;
2668
2669 compo.u.complex->generic = (Z_Specification *)
2670 odr_malloc(out, sizeof(*compo.u.complex->generic));
2671 compo.u.complex->generic->which = Z_Schema_oid;
2672
2673 compo.u.complex->generic->schema.oid =
2674 yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
2675
2676 if (!compo.u.complex->generic->schema.oid)
2677 {
2678 /* OID wasn't a schema! Try record syntax instead. */
2679 compo.u.complex->generic->schema.oid = (Odr_oid *)
2680 yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
2681 }
2682 if (!elementSetNames)
2683 compo.u.complex->generic->elementSpec = 0;
2684 else
2685 {
2686 compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
2687 odr_malloc(out, sizeof(Z_ElementSpec));
2688 compo.u.complex->generic->elementSpec->which =
2689 Z_ElementSpec_elementSetName;
2690 compo.u.complex->generic->elementSpec->u.elementSetName =
2691 elementSetNames->u.generic;
2692 }
2693 compo.u.complex->num_dbSpecific = 0;
2694 compo.u.complex->dbSpecific = 0;
2695 compo.u.complex->num_recordSyntax = 0;
2696 compo.u.complex->recordSyntax = 0;
2697 }
2698 else if (elementSetNames)
2699 {
2700 req->recordComposition = &compo;
2701 compo.which = Z_RecordComp_simple;
2702 compo.u.simple = elementSetNames;
2703 }
2704 send_apdu(apdu);
2705 printf("Sent presentRequest (%d+%d).\n", setno, nos);
2706 return 2;
2707}
2708
2709#if HAVE_XML2
2710static int send_SRW_presentRequest(const char *arg)
2711{
2712 char setstring[100];
2713 int nos = 1;
2714 Z_SRW_PDU *sr = srw_sr;
2715
2716 if (!sr)
2717 return 0;
2718 parse_show_args(arg, setstring, &setno, &nos);
2719 sr->u.request->startRecord = odr_intdup(out, setno);
2720 sr->u.request->maximumRecords = odr_intdup(out, nos);
2721 if (record_schema)
2722 sr->u.request->recordSchema = record_schema;
2723 if (recordsyntax == VAL_TEXT_XML)
2724 sr->u.request->recordPacking = "xml";
2725 return send_srw(sr);
2726}
2727#endif
2728
2729static void close_session (void)
2730{
2731 if (conn)
2732 cs_close (conn);
2733 conn = 0;
2734 if (session_mem)
2735 {
2736 nmem_destroy (session_mem);
2737 session_mem = NULL;
2738 }
2739 sent_close = 0;
2740 odr_reset(out);
2741 odr_reset(in);
2742 odr_reset(print);
2743}
2744
2745void process_close(Z_Close *req)
2746{
2747 Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
2748 Z_Close *res = apdu->u.close;
2749
2750 static char *reasons[] =
2751 {
2752 "finished",
2753 "shutdown",
2754 "system problem",
2755 "cost limit reached",
2756 "resources",
2757 "security violation",
2758 "protocolError",
2759 "lack of activity",
2760 "peer abort",
2761 "unspecified"
2762 };
2763
2764 printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
2765 req->diagnosticInformation ? req->diagnosticInformation : "NULL");
2766 if (sent_close)
2767 close_session ();
2768 else
2769 {
2770 *res->closeReason = Z_Close_finished;
2771 send_apdu(apdu);
2772 printf("Sent response.\n");
2773 sent_close = 1;
2774 }
2775}
2776
2777static int cmd_show(const char *arg)
2778{
2779 if (protocol == PROTO_HTTP)
2780 {
2781#if HAVE_XML2
2782 if (!conn)
2783 cmd_open(0);
2784 if (!conn)
2785 return 0;
2786 if (!send_SRW_presentRequest(arg))
2787 return 0;
2788#else
2789 return 0;
2790#endif
2791 }
2792 else
2793 {
2794 if (!conn)
2795 {
2796 printf("Not connected yet\n");
2797 return 0;
2798 }
2799 if (!send_presentRequest(arg))
2800 return 0;
2801 }
2802 return 2;
2803}
2804
2805int cmd_quit(const char *arg)
2806{
2807 printf("See you later, alligator.\n");
2808 xmalloc_trav ("");
2809 exit(0);
2810 return 0;
2811}
2812
2813int cmd_cancel(const char *arg)
2814{
2815 Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
2816 Z_TriggerResourceControlRequest *req =
2817 apdu->u.triggerResourceControlRequest;
2818 bool_t rfalse = 0;
2819
2820 if (!conn)
2821 {
2822 printf("Session not initialized yet\n");
2823 return 0;
2824 }
2825 if (only_z3950())
2826 return 0;
2827 if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
2828 {
2829 printf("Target doesn't support cancel (trigger resource ctrl)\n");
2830 return 0;
2831 }
2832 *req->requestedAction = Z_TriggerResourceControlRequest_cancel;
2833 req->resultSetWanted = &rfalse;
2834 req->referenceId = set_refid (out);
2835
2836 send_apdu(apdu);
2837 printf("Sent cancel request\n");
2838 return 2;
2839}
2840
2841
2842int cmd_cancel_find(const char *arg) {
2843 int fres;
2844 fres=cmd_find(arg);
2845 if( fres > 0 ) {
2846 return cmd_cancel("");
2847 };
2848 return fres;
2849}
2850
2851int send_scanrequest(const char *query, int pp, int num, const char *term)
2852{
2853 Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
2854 Z_ScanRequest *req = apdu->u.scanRequest;
2855
2856 if (only_z3950())
2857 return 0;
2858 if (queryType == QueryType_CCL2RPN)
2859 {
2860 int error, pos;
2861 struct ccl_rpn_node *rpn;
2862
2863 rpn = ccl_find_str (bibset, query, &error, &pos);
2864 if (error)
2865 {
2866 printf("CCL ERROR: %s\n", ccl_err_msg(error));
2867 return -1;
2868 }
2869 req->attributeSet =
2870 yaz_oidval_to_z3950oid(out, CLASS_ATTSET, VAL_BIB1);
2871 if (!(req->termListAndStartPoint = ccl_scan_query (out, rpn)))
2872 {
2873 printf("Couldn't convert CCL to Scan term\n");
2874 return -1;
2875 }
2876 ccl_rpn_delete (rpn);
2877 }
2878 else
2879 {
2880 YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
2881
2882 if (!(req->termListAndStartPoint =
2883 yaz_pqf_scan(pqf_parser, out, &req->attributeSet, query)))
2884 {
2885 const char *pqf_msg;
2886 size_t off;
2887 int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
2888 printf("%*s^\n", off+7, "");
2889 printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
2890 yaz_pqf_destroy (pqf_parser);
2891 return -1;
2892 }
2893 yaz_pqf_destroy (pqf_parser);
2894 }
2895 if (term && *term)
2896 {
2897 if (req->termListAndStartPoint->term &&
2898 req->termListAndStartPoint->term->which == Z_Term_general &&
2899 req->termListAndStartPoint->term->u.general)
2900 {
2901 req->termListAndStartPoint->term->u.general->buf =
2902 (unsigned char *) odr_strdup(out, term);
2903 req->termListAndStartPoint->term->u.general->len =
2904 req->termListAndStartPoint->term->u.general->size =
2905 strlen(term);
2906 }
2907 }
2908 req->referenceId = set_refid (out);
2909 req->num_databaseNames = num_databaseNames;
2910 req->databaseNames = databaseNames;
2911 req->numberOfTermsRequested = &num;
2912 req->preferredPositionInResponse = &pp;
2913 req->stepSize = odr_intdup(out, scan_stepSize);
2914 send_apdu(apdu);
2915 return 2;
2916}
2917
2918int send_sortrequest(const char *arg, int newset)
2919{
2920 Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
2921 Z_SortRequest *req = apdu->u.sortRequest;
2922 Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
2923 odr_malloc (out, sizeof(*sksl));
2924 char setstring[32];
2925
2926 if (only_z3950())
2927 return 0;
2928 if (setnumber >= 0)
2929 sprintf (setstring, "%d", setnumber);
2930 else
2931 sprintf (setstring, "default");
2932
2933 req->referenceId = set_refid (out);
2934
2935 req->num_inputResultSetNames = 1;
2936 req->inputResultSetNames = (Z_InternationalString **)
2937 odr_malloc (out, sizeof(*req->inputResultSetNames));
2938 req->inputResultSetNames[0] = odr_strdup (out, setstring);
2939
2940 if (newset && setnumber >= 0)
2941 sprintf (setstring, "%d", ++setnumber);
2942
2943 req->sortedResultSetName = odr_strdup (out, setstring);
2944
2945 req->sortSequence = yaz_sort_spec (out, arg);
2946 if (!req->sortSequence)
2947 {
2948 printf ("Missing sort specifications\n");
2949 return -1;
2950 }
2951 send_apdu(apdu);
2952 return 2;
2953}
2954
2955void display_term(Z_TermInfo *t)
2956{
2957 if (t->displayTerm)
2958 printf("%s", t->displayTerm);
2959 else if (t->term->which == Z_Term_general)
2960 {
2961 printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
2962 sprintf(last_scan_line, "%.*s", t->term->u.general->len,
2963 t->term->u.general->buf);
2964 }
2965 else
2966 printf("Term (not general)");
2967 if (t->globalOccurrences)
2968 printf (" (%d)\n", *t->globalOccurrences);
2969 else
2970 printf ("\n");
2971}
2972
2973void process_scanResponse(Z_ScanResponse *res)
2974{
2975 int i;
2976 Z_Entry **entries = NULL;
2977 int num_entries = 0;
2978
2979 printf("Received ScanResponse\n");
2980 print_refid (res->referenceId);
2981 printf("%d entries", *res->numberOfEntriesReturned);
2982 if (res->positionOfTerm)
2983 printf (", position=%d", *res->positionOfTerm);
2984 printf ("\n");
2985 if (*res->scanStatus != Z_Scan_success)
2986 printf("Scan returned code %d\n", *res->scanStatus);
2987 if (!res->entries)
2988 return;
2989 if ((entries = res->entries->entries))
2990 num_entries = res->entries->num_entries;
2991 for (i = 0; i < num_entries; i++)
2992 {
2993 int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
2994 if (entries[i]->which == Z_Entry_termInfo)
2995 {
2996 printf("%c ", i + 1 == pos_term ? '*' : ' ');
2997 display_term(entries[i]->u.termInfo);
2998 }
2999 else
3000 display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
3001 }
3002 if (res->entries->nonsurrogateDiagnostics)
3003 display_diagrecs (res->entries->nonsurrogateDiagnostics,
3004 res->entries->num_nonsurrogateDiagnostics);
3005}
3006
3007void process_sortResponse(Z_SortResponse *res)
3008{
3009 printf("Received SortResponse: status=");
3010 switch (*res->sortStatus)
3011 {
3012 case Z_SortResponse_success:
3013 printf ("success"); break;
3014 case Z_SortResponse_partial_1:
3015 printf ("partial"); break;
3016 case Z_SortResponse_failure:
3017 printf ("failure"); break;
3018 default:
3019 printf ("unknown (%d)", *res->sortStatus);
3020 }
3021 printf ("\n");
3022 print_refid (res->referenceId);
3023 if (res->diagnostics)
3024 display_diagrecs(res->diagnostics,
3025 res->num_diagnostics);
3026}
3027
3028void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
3029{
3030 printf("Got deleteResultSetResponse status=%d\n",
3031 *res->deleteOperationStatus);
3032 if (res->deleteListStatuses)
3033 {
3034 int i;
3035 for (i = 0; i < res->deleteListStatuses->num; i++)
3036 {
3037 printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
3038 *res->deleteListStatuses->elements[i]->status);
3039 }
3040 }
3041}
3042
3043int cmd_sort_generic(const char *arg, int newset)
3044{
3045 if (!conn)
3046 {
3047 printf("Session not initialized yet\n");
3048 return 0;
3049 }
3050 if (only_z3950())
3051 return 0;
3052 if (!ODR_MASK_GET(session->options, Z_Options_sort))
3053 {
3054 printf("Target doesn't support sort\n");
3055 return 0;
3056 }
3057 if (*arg)
3058 {
3059 if (send_sortrequest(arg, newset) < 0)
3060 return 0;
3061 return 2;
3062 }
3063 return 0;
3064}
3065
3066int cmd_sort(const char *arg)
3067{
3068 return cmd_sort_generic (arg, 0);
3069}
3070
3071int cmd_sort_newset (const char *arg)
3072{
3073 return cmd_sort_generic (arg, 1);
3074}
3075
3076int cmd_scanstep(const char *arg)
3077{
3078 scan_stepSize = atoi(arg);
3079 return 0;
3080}
3081
3082int cmd_scanpos(const char *arg)
3083{
3084 int r = sscanf(arg, "%d", &scan_position);
3085 if (r == 0)
3086 scan_position = 1;
3087 return 0;
3088}
3089
3090int cmd_scansize(const char *arg)
3091{
3092 int r = sscanf(arg, "%d", &scan_size);
3093 if (r == 0)
3094 scan_size = 20;
3095 return 0;
3096}
3097
3098int cmd_scan(const char *arg)
3099{
3100 if (protocol == PROTO_HTTP)
3101 {
3102#if HAVE_XML2
3103 if (!conn)
3104 cmd_open(0);
3105 if (!conn)
3106 return 0;
3107 if (*arg)
3108 {
3109 if (send_SRW_scanRequest(arg, scan_position, scan_size) < 0)
3110 return 0;
3111 }
3112 else
3113 {
3114 if (send_SRW_scanRequest(last_scan_line, 1, scan_size) < 0)
3115 return 0;
3116 }
3117 return 2;
3118#else
3119 return 0;
3120#endif
3121 }
3122 else
3123 {
3124 if (!conn)
3125 {
3126 try_reconnect();
3127
3128 if (!conn) {
3129 printf("Session not initialized yet\n");
3130 return 0;
3131 }
3132 }
3133 if (!ODR_MASK_GET(session->options, Z_Options_scan))
3134 {
3135 printf("Target doesn't support scan\n");
3136 return 0;
3137 }
3138 if (*arg)
3139 {
3140 strcpy (last_scan_query, arg);
3141 if (send_scanrequest(arg, scan_position, scan_size, 0) < 0)
3142 return 0;
3143 }
3144 else
3145 {
3146 if (send_scanrequest(last_scan_query, 1, scan_size, last_scan_line) < 0)
3147 return 0;
3148 }
3149 return 2;
3150 }
3151}
3152
3153int cmd_schema(const char *arg)
3154{
3155 xfree(record_schema);
3156 record_schema = 0;
3157 if (arg && *arg)
3158 record_schema = xstrdup(arg);
3159 return 1;
3160}
3161
3162int cmd_format(const char *arg)
3163{
3164 oid_value nsyntax;
3165 if (!arg || !*arg)
3166 {
3167 printf("Usage: format <recordsyntax>\n");
3168 return 0;
3169 }
3170 nsyntax = oid_getvalbyname (arg);
3171 if (strcmp(arg, "none") && nsyntax == VAL_NONE)
3172 {
3173 printf ("unknown record syntax\n");
3174 return 0;
3175 }
3176 recordsyntax = nsyntax;
3177 return 1;
3178}
3179
3180int cmd_elements(const char *arg)
3181{
3182 static Z_ElementSetNames esn;
3183 static char what[100];
3184
3185 if (!arg || !*arg)
3186 {
3187 elementSetNames = 0;
3188 return 1;
3189 }
3190 strcpy(what, arg);
3191 esn.which = Z_ElementSetNames_generic;
3192 esn.u.generic = what;
3193 elementSetNames = &esn;
3194 return 1;
3195}
3196
3197int cmd_attributeset(const char *arg)
3198{
3199 char what[100];
3200
3201 if (!arg || !*arg)
3202 {
3203 printf("Usage: attributeset <setname>\n");
3204 return 0;
3205 }
3206 sscanf(arg, "%s", what);
3207 if (p_query_attset (what))
3208 {
3209 printf("Unknown attribute set name\n");
3210 return 0;
3211 }
3212 return 1;
3213}
3214
3215int cmd_querytype (const char *arg)
3216{
3217 if (!strcmp (arg, "ccl"))
3218 queryType = QueryType_CCL;
3219 else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
3220 queryType = QueryType_Prefix;
3221 else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn"))
3222 queryType = QueryType_CCL2RPN;
3223 else if (!strcmp(arg, "cql"))
3224 queryType = QueryType_CQL;
3225 else if (!strcmp (arg, "cql2rpn") || !strcmp (arg, "cqlrpn"))
3226 queryType = QueryType_CQL2RPN;
3227 else
3228 {
3229 printf ("Querytype must be one of:\n");
3230 printf (" prefix - Prefix query\n");
3231 printf (" ccl - CCL query\n");
3232 printf (" ccl2rpn - CCL query converted to RPN\n");
3233 printf (" cql - CQL\n");
3234 printf (" cql2rpn - CQL query converted to RPN\n");
3235 return 0;
3236 }
3237 return 1;
3238}
3239
3240int cmd_refid (const char *arg)
3241{
3242 xfree (refid);
3243 refid = NULL;
3244 if (*arg)
3245 refid = xstrdup (arg);
3246 return 1;
3247}
3248
3249int z_cmd_close(const char *arg)
3250{
3251 Z_APDU *apdu;
3252 Z_Close *req;
3253 if (!conn)
3254 return 0;
3255 if (only_z3950())
3256 return 0;
3257
3258 apdu = zget_APDU(out, Z_APDU_close);
3259 req = apdu->u.close;
3260 *req->closeReason = Z_Close_finished;
3261 send_apdu(apdu);
3262 printf("Sent close request.\n");
3263 sent_close = 1;
3264 return 2;
3265}
3266
3267int cmd_packagename(const char* arg)
3268{
3269 xfree (esPackageName);
3270 esPackageName = NULL;
3271 if (*arg)
3272 esPackageName = xstrdup(arg);
3273 return 1;
3274}
3275
3276int cmd_proxy(const char* arg)
3277{
3278 xfree (yazProxy);
3279 yazProxy = NULL;
3280 if (*arg)
3281 yazProxy = xstrdup (arg);
3282 return 1;
3283}
3284
3285int cmd_marccharset(const char *arg)
3286{
3287 char l1[30];
3288
3289 *l1 = 0;
3290 if (sscanf(arg, "%29s", l1) < 1)
3291 {
3292 printf("MARC character set is `%s'\n",
3293 marcCharset ? marcCharset: "none");
3294 return 1;
3295 }
3296 xfree (marcCharset);
3297 marcCharset = 0;
3298 if (strcmp(l1, "-"))
3299 marcCharset = xstrdup(l1);
3300 return 1;
3301}
3302
3303int cmd_displaycharset(const char *arg)
3304{
3305 char l1[30];
3306
3307 *l1 = 0;
3308 if (sscanf(arg, "%29s", l1) < 1)
3309 {
3310 printf("Display character set is `%s'\n",
3311 outputCharset ? outputCharset: "none");
3312 }
3313 else
3314 {
3315 xfree (outputCharset);
3316 outputCharset = 0;
3317 if (!strcmp(l1, "auto") && codeset)
3318 {
3319 if (codeset)
3320 {
3321 printf ("Display character set: %s\n", codeset);
3322 outputCharset = xstrdup(codeset);
3323 }
3324 else
3325 printf ("No codeset found on this system\n");
3326 }
3327 else if (strcmp(l1, "-") && strcmp(l1, "none"))
3328 outputCharset = xstrdup(l1);
3329 }
3330 return 1;
3331}
3332
3333int cmd_negcharset(const char *arg)
3334{
3335 char l1[30];
3336
3337 *l1 = 0;
3338 if (sscanf(arg, "%29s %d %d", l1, &negotiationCharsetRecords,
3339 &negotiationCharsetVersion) < 1)
3340 {
3341 printf("Current negotiation character set is `%s'\n",
3342 negotiationCharset ? negotiationCharset: "none");
3343 printf("Records in charset %s\n", negotiationCharsetRecords ?
3344 "yes" : "no");
3345 printf("Charneg version %d\n", negotiationCharsetVersion);
3346 }
3347 else
3348 {
3349 xfree (negotiationCharset);
3350 negotiationCharset = NULL;
3351 if (*l1 && strcmp(l1, "-") && strcmp(l1, "none"))
3352 {
3353 negotiationCharset = xstrdup(l1);
3354 printf ("Character set negotiation : %s\n", negotiationCharset);
3355 }
3356 }
3357 return 1;
3358}
3359
3360int cmd_charset(const char* arg)
3361{
3362 char l1[30], l2[30], l3[30];
3363
3364 *l1 = *l2 = *l3 = 0;
3365 if (sscanf(arg, "%29s %29s %29s", l1, l2, l3) < 1)
3366 {
3367 cmd_negcharset("");
3368 cmd_displaycharset("");
3369 cmd_marccharset("");
3370 }
3371 else
3372 {
3373 cmd_negcharset(l1);
3374 if (*l2)
3375 cmd_displaycharset(l2);
3376 if (*l3)
3377 cmd_marccharset(l3);
3378 }
3379 return 1;
3380}
3381
3382int cmd_lang(const char* arg)
3383{
3384 if (*arg == '\0') {
3385 printf("Current language is `%s'\n", (yazLang)?yazLang:NULL);
3386 return 1;
3387 }
3388 xfree (yazLang);
3389 yazLang = NULL;
3390 if (*arg)
3391 yazLang = xstrdup(arg);
3392 return 1;
3393}
3394
3395int cmd_source(const char* arg, int echo )
3396{
3397 /* first should open the file and read one line at a time.. */
3398 FILE* includeFile;
3399 char line[102400], *cp;
3400
3401 if(strlen(arg)<1) {
3402 fprintf(stderr,"Error in source command use a filename\n");
3403 return -1;
3404 }
3405
3406 includeFile = fopen (arg, "r");
3407
3408 if(!includeFile) {
3409 fprintf(stderr,"Unable to open file %s for reading\n",arg);
3410 return -1;
3411 }
3412
3413 while(!feof(includeFile)) {
3414 memset(line,0,sizeof(line));
3415 fgets(line,sizeof(line),includeFile);
3416
3417 if(strlen(line) < 2) continue;
3418 if(line[0] == '#') continue;
3419
3420 if ((cp = strrchr (line, '\n')))
3421 *cp = '\0';
3422
3423 if( echo ) {
3424 printf( "processing line: %s\n",line );
3425 };
3426 process_cmd_line(line);
3427 }
3428
3429 if(fclose(includeFile)<0) {
3430 perror("unable to close include file");
3431 exit(1);
3432 }
3433 return 1;
3434}
3435
3436int cmd_source_echo(const char* arg)
3437{
3438 cmd_source(arg, 1);
3439 return 1;
3440}
3441
3442int cmd_source_noecho(const char* arg)
3443{
3444 cmd_source(arg, 0);
3445 return 1;
3446}
3447
3448
3449int cmd_subshell(const char* args)
3450{
3451 if(strlen(args))
3452 system(args);
3453 else
3454 system(getenv("SHELL"));
3455
3456 printf("\n");
3457 return 1;
3458}
3459
3460int cmd_set_berfile(const char *arg)
3461{
3462 if (ber_file && ber_file != stdout && ber_file != stderr)
3463 fclose(ber_file);
3464 if (!strcmp(arg, ""))
3465 ber_file = 0;
3466 else if (!strcmp(arg, "-"))
3467 ber_file = stdout;
3468 else
3469 ber_file = fopen(arg, "a");
3470 return 1;
3471}
3472
3473int cmd_set_apdufile(const char *arg)
3474{
3475 if(apdu_file && apdu_file != stderr && apdu_file != stderr)
3476 fclose(apdu_file);
3477 if (!strcmp(arg, ""))
3478 apdu_file = 0;
3479 else if (!strcmp(arg, "-"))
3480 apdu_file = stderr;
3481 else
3482 {
3483 apdu_file = fopen(arg, "a");
3484 if (!apdu_file)
3485 perror("unable to open apdu log file");
3486 }
3487 if (apdu_file)
3488 odr_setprint(print, apdu_file);
3489 return 1;
3490}
3491
3492int cmd_set_cclfile(const char* arg)
3493{
3494 FILE *inf;
3495
3496 bibset = ccl_qual_mk ();
3497 inf = fopen (arg, "r");
3498 if (!inf)
3499 perror("unable to open CCL file");
3500 else
3501 {
3502 ccl_qual_file (bibset, inf);
3503 fclose (inf);
3504 }
3505 strcpy(ccl_fields,arg);
3506 return 0;
3507}
3508
3509int cmd_set_cqlfile(const char* arg)
3510{
3511 cql_transform_t newcqltrans;
3512
3513 if ((newcqltrans = cql_transform_open_fname(arg)) == 0) {
3514 perror("unable to open CQL file");
3515 return 0;
3516 }
3517 if (cqltrans != 0)
3518 cql_transform_close(cqltrans);
3519
3520 cqltrans = newcqltrans;
3521 strcpy(cql_fields, arg);
3522 return 0;
3523}
3524
3525int cmd_set_auto_reconnect(const char* arg)
3526{
3527 if(strlen(arg)==0) {
3528 auto_reconnect = ! auto_reconnect;
3529 } else if(strcmp(arg,"on")==0) {
3530 auto_reconnect = 1;
3531 } else if(strcmp(arg,"off")==0) {
3532 auto_reconnect = 0;
3533 } else {
3534 printf("Error use on or off\n");
3535 return 1;
3536 }
3537
3538 if (auto_reconnect)
3539 printf("Set auto reconnect enabled.\n");
3540 else
3541 printf("Set auto reconnect disabled.\n");
3542
3543 return 0;
3544}
3545
3546int cmd_set_marcdump(const char* arg)
3547{
3548 if(marc_file && marc_file != stderr) { /* don't close stdout*/
3549 fclose(marc_file);
3550 }
3551
3552 if (!strcmp(arg, ""))
3553 marc_file = 0;
3554 else if (!strcmp(arg, "-"))
3555 marc_file = stderr;
3556 else
3557 {
3558 marc_file = fopen(arg, "a");
3559 if (!marc_file)
3560 perror("unable to open marc log file");
3561 }
3562 return 1;
3563}
3564
3565/*
3566 this command takes 3 arge {name class oid}
3567*/
3568int cmd_register_oid(const char* args) {
3569 static struct {
3570 char* className;
3571 oid_class oclass;
3572 } oid_classes[] = {
3573 {"appctx",CLASS_APPCTX},
3574 {"absyn",CLASS_ABSYN},
3575 {"attset",CLASS_ATTSET},
3576 {"transyn",CLASS_TRANSYN},
3577 {"diagset",CLASS_DIAGSET},
3578 {"recsyn",CLASS_RECSYN},
3579 {"resform",CLASS_RESFORM},
3580 {"accform",CLASS_ACCFORM},
3581 {"extserv",CLASS_EXTSERV},
3582 {"userinfo",CLASS_USERINFO},
3583 {"elemspec",CLASS_ELEMSPEC},
3584 {"varset",CLASS_VARSET},
3585 {"schema",CLASS_SCHEMA},
3586 {"tagset",CLASS_TAGSET},
3587 {"general",CLASS_GENERAL},
3588 {0,(enum oid_class) 0}
3589 };
3590 char oname_str[101], oclass_str[101], oid_str[101];
3591 char* name;
3592 int i;
3593 oid_class oidclass = CLASS_GENERAL;
3594 int val = 0, oid[OID_SIZE];
3595 struct oident * new_oident=NULL;
3596
3597 if (sscanf (args, "%100[^ ] %100[^ ] %100s",
3598 oname_str,oclass_str, oid_str) < 1) {
3599 printf("Error in register command \n");
3600 return 0;
3601 }
3602
3603 for (i = 0; oid_classes[i].className; i++) {
3604 if (!strcmp(oid_classes[i].className, oclass_str))
3605 {
3606 oidclass=oid_classes[i].oclass;
3607 break;
3608 }
3609 }
3610
3611 if(!(oid_classes[i].className)) {
3612 printf("Unknown oid class %s\n",oclass_str);
3613 return 0;
3614 }
3615
3616 i = 0;
3617 name = oid_str;
3618 val = 0;
3619
3620 while (isdigit (*(unsigned char *) name))
3621 {
3622 val = val*10 + (*name - '0');
3623 name++;
3624 if (*name == '.')
3625 {
3626 if (i < OID_SIZE-1)
3627 oid[i++] = val;
3628 val = 0;
3629 name++;
3630 }
3631 }
3632 oid[i] = val;
3633 oid[i+1] = -1;
3634
3635 new_oident = oid_addent (oid, PROTO_GENERAL, oidclass, oname_str,
3636 VAL_DYNAMIC);
3637 if(strcmp(new_oident->desc,oname_str))
3638 {
3639 fprintf(stderr,"oid is already named as %s, registration failed\n",
3640 new_oident->desc);
3641 }
3642 return 1;
3643}
3644
3645int cmd_push_command(const char* arg)
3646{
3647
3648#if HAVE_READLINE_HISTORY_H
3649 if(strlen(arg)>1)
3650 add_history(arg);
3651#else
3652 fprintf(stderr,"Not compiled with the readline/history module\n");
3653#endif
3654 return 1;
3655}
3656
3657void source_rcfile()
3658{
3659 /* Look for a $HOME/.yazclientrc and source it if it exists */
3660 struct stat statbuf;
3661 char buffer[1000];
3662 char* homedir=getenv("HOME");
3663
3664 if( homedir ) {
3665
3666 sprintf(buffer,"%s/.yazclientrc",homedir);
3667
3668 if(stat(buffer,&statbuf)==0) {
3669 cmd_source(buffer, 0 );
3670 }
3671
3672 };
3673
3674 if(stat(".yazclientrc",&statbuf)==0) {
3675 cmd_source(".yazclientrc", 0 );
3676 }
3677}
3678
3679
3680void z_initialize(void)
3681{
3682 FILE *inf;
3683 int i;
3684
3685 if (!(out = odr_createmem(ODR_ENCODE)) ||
3686 !(in = odr_createmem(ODR_DECODE)) ||
3687 !(print = odr_createmem(ODR_PRINT)))
3688 {
3689 fprintf(stderr, "failed to allocate ODR streams\n");
3690 exit(1);
3691 }
3692 oid_init();
3693
3694 setvbuf(stdout, 0, _IONBF, 0);
3695 if (apdu_file)
3696 odr_setprint(print, apdu_file);
3697
3698 bibset = ccl_qual_mk ();
3699 inf = fopen (ccl_fields, "r");
3700 if (inf)
3701 {
3702 ccl_qual_file (bibset, inf);
3703 fclose (inf);
3704 }
3705
3706 cqltrans = cql_transform_open_fname(cql_fields);
3707 /* If this fails, no problem: we detect cqltrans == 0 later */
3708
3709#if HAVE_READLINE_READLINE_H
3710 rl_attempted_completion_function = (CPPFunction*)readline_completer;
3711#endif
3712
3713
3714 for(i=0; i<maxOtherInfosSupported; ++i) {
3715 extraOtherInfos[i].oidval = -1;
3716 }
3717
3718 source_rcfile();
3719}
3720
3721
3722#if HAVE_GETTIMEOFDAY
3723struct timeval tv_start, tv_end;
3724#endif
3725
3726#if HAVE_XML2
3727static void handle_srw_record(Z_SRW_record *rec)
3728{
3729 if (rec->recordPosition)
3730 {
3731 printf ("pos=%d", *rec->recordPosition);
3732 setno = *rec->recordPosition + 1;
3733 }
3734 if (rec->recordSchema)
3735 printf (" schema=%s", rec->recordSchema);
3736 printf ("\n");
3737 if (rec->recordData_buf && rec->recordData_len)
3738 {
3739 fwrite(rec->recordData_buf, 1, rec->recordData_len, stdout);
3740 if (marc_file)
3741 fwrite (rec->recordData_buf, 1, rec->recordData_len, marc_file);
3742 }
3743 else
3744 printf ("No data!");
3745 printf("\n");
3746}
3747
3748static void handle_srw_explain_response(Z_SRW_explainResponse *res)
3749{
3750 handle_srw_record(&res->record);
3751}
3752
3753static void handle_srw_response(Z_SRW_searchRetrieveResponse *res)
3754{
3755 int i;
3756
3757 printf ("Received SRW SearchRetrieve Response\n");
3758
3759 for (i = 0; i<res->num_diagnostics; i++)
3760 {
3761 if (res->diagnostics[i].uri)
3762 printf ("SRW diagnostic %s\n",
3763 res->diagnostics[i].uri);
3764 else
3765 printf ("SRW diagnostic missing or could not be decoded\n");
3766 if (res->diagnostics[i].message)
3767 printf ("Message: %s\n", res->diagnostics[i].message);
3768 if (res->diagnostics[i].details)
3769 printf ("Details: %s\n", res->diagnostics[i].details);
3770 }
3771 if (res->numberOfRecords)
3772 printf ("Number of hits: %d\n", *res->numberOfRecords);
3773 for (i = 0; i<res->num_records; i++)
3774 handle_srw_record(res->records + i);
3775}
3776
3777static void handle_srw_scan_term(Z_SRW_scanTerm *term)
3778{
3779 if (term->displayTerm)
3780 printf("%s:", term->displayTerm);
3781 else if (term->value)
3782 printf("%s:", term->value);
3783 else
3784 printf("No value:");
3785 if (term->numberOfRecords)
3786 printf(" %d", *term->numberOfRecords);
3787 if (term->whereInList)
3788 printf(" %s", term->whereInList);
3789 if (term->value && term->displayTerm)
3790 printf(" %s", term->value);
3791
3792 strcpy(last_scan_line, term->value);
3793 printf("\n");
3794}
3795
3796static void handle_srw_scan_response(Z_SRW_scanResponse *res)
3797{
3798 int i;
3799
3800 printf ("Received SRW Scan Response\n");
3801
3802 for (i = 0; i<res->num_diagnostics; i++)
3803 {
3804 if (res->diagnostics[i].uri)
3805 printf ("SRW diagnostic %s\n",
3806 res->diagnostics[i].uri);
3807 else
3808 printf ("SRW diagnostic missing or could not be decoded\n");
3809 if (res->diagnostics[i].message)
3810 printf ("Message: %s\n", res->diagnostics[i].message);
3811 if (res->diagnostics[i].details)
3812 printf ("Details: %s\n", res->diagnostics[i].details);
3813 }
3814 if (res->terms)
3815 for (i = 0; i<res->num_terms; i++)
3816 handle_srw_scan_term(res->terms + i);
3817}
3818
3819static void http_response(Z_HTTP_Response *hres)
3820{
3821 int ret = -1;
3822 const char *content_type = z_HTTP_header_lookup(hres->headers,
3823 "Content-Type");
3824 const char *connection_head = z_HTTP_header_lookup(hres->headers,
3825 "Connection");
3826 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
3827 {
3828 Z_SOAP *soap_package = 0;
3829 ODR o = odr_createmem(ODR_DECODE);
3830 Z_SOAP_Handler soap_handlers[2] = {
3831 {"http://www.loc.gov/zing/srw/", 0,
3832 (Z_SOAP_fun) yaz_srw_codec},
3833 {0, 0, 0}
3834 };
3835 ret = z_soap_codec(o, &soap_package,
3836 &hres->content_buf, &hres->content_len,
3837 soap_handlers);
3838 if (!ret && soap_package->which == Z_SOAP_generic &&
3839 soap_package->u.generic->no == 0)
3840 {
3841 Z_SRW_PDU *sr = soap_package->u.generic->p;
3842 if (sr->which == Z_SRW_searchRetrieve_response)
3843 handle_srw_response(sr->u.response);
3844 else if (sr->which == Z_SRW_explain_response)
3845 handle_srw_explain_response(sr->u.explain_response);
3846 else if (sr->which == Z_SRW_scan_response)
3847 handle_srw_scan_response(sr->u.scan_response);
3848 else
3849 ret = -1;
3850 }
3851 else if (soap_package && (soap_package->which == Z_SOAP_fault
3852 || soap_package->which == Z_SOAP_error))
3853 {
3854 printf ("HTTP Error Status=%d\n", hres->code);
3855 printf ("SOAP Fault code %s\n",
3856 soap_package->u.fault->fault_code);
3857 printf ("SOAP Fault string %s\n",
3858 soap_package->u.fault->fault_string);
3859 if (soap_package->u.fault->details)
3860 printf ("SOAP Details %s\n",
3861 soap_package->u.fault->details);
3862 }
3863 else
3864 ret = -1;
3865 odr_destroy(o);
3866 }
3867 if (ret)
3868 {
3869 if (hres->code != 200)
3870 {
3871 printf ("HTTP Error Status=%d\n", hres->code);
3872 }
3873 else
3874 {
3875 printf ("Decoding of SRW package failed\n");
3876 }
3877 close_session();
3878 }
3879 else
3880 {
3881 if (!strcmp(hres->version, "1.0"))
3882 {
3883 /* HTTP 1.0: only if Keep-Alive we stay alive.. */
3884 if (!connection_head || strcmp(connection_head, "Keep-Alive"))
3885 close_session();
3886 }
3887 else
3888 {
3889 /* HTTP 1.1: only if no close we stay alive .. */
3890 if (connection_head && !strcmp(connection_head, "close"))
3891 close_session();
3892 }
3893 }
3894}
3895#endif
3896
3897void wait_and_handle_response()
3898{
3899 int reconnect_ok = 1;
3900 int res;
3901 char *netbuffer= 0;
3902 int netbufferlen = 0;
3903 Z_GDU *gdu;
3904
3905 while(conn)
3906 {
3907 res = cs_get(conn, &netbuffer, &netbufferlen);
3908 if (reconnect_ok && res <= 0 && protocol == PROTO_HTTP)
3909 {
3910 cs_close(conn);
3911 conn = 0;
3912 cmd_open(0);
3913 reconnect_ok = 0;
3914 if (conn)
3915 {
3916 char *buf_out;
3917 int len_out;
3918
3919 buf_out = odr_getbuf(out, &len_out, 0);
3920
3921 do_hex_dump(buf_out, len_out);
3922
3923 cs_put(conn, buf_out, len_out);
3924
3925 odr_reset(out);
3926 continue;
3927 }
3928 }
3929 else if (res <= 0)
3930 {
3931 printf("Target closed connection\n");
3932 close_session();
3933 break;
3934 }
3935 odr_reset(out);
3936 odr_reset(in); /* release APDU from last round */
3937 record_last = 0;
3938 do_hex_dump(netbuffer, res);
3939 odr_setbuf(in, netbuffer, res, 0);
3940
3941 if (!z_GDU(in, &gdu, 0, 0))
3942 {
3943 FILE *f = ber_file ? ber_file : stdout;
3944 odr_perror(in, "Decoding incoming APDU");
3945 fprintf(f, "[Near %d]\n", odr_offset(in));
3946 fprintf(f, "Packet dump:\n---------\n");
3947 odr_dumpBER(f, netbuffer, res);
3948 fprintf(f, "---------\n");
3949 if (apdu_file)
3950 {
3951 z_GDU(print, &gdu, 0, 0);
3952 odr_reset(print);
3953 }
3954 if (conn && cs_more(conn))
3955 continue;
3956 break;
3957 }
3958 if (ber_file)
3959 odr_dumpBER(ber_file, netbuffer, res);
3960 if (apdu_file && !z_GDU(print, &gdu, 0, 0))
3961 {
3962 odr_perror(print, "Failed to print incoming APDU");
3963 odr_reset(print);
3964 continue;
3965 }
3966 if (gdu->which == Z_GDU_Z3950)
3967 {
3968 Z_APDU *apdu = gdu->u.z3950;
3969 switch(apdu->which)
3970 {
3971 case Z_APDU_initResponse:
3972 // kjdon copying johnmcp
3973 /* save session parameters for later use */
3974 session_mem = odr_extract_mem(in);
3975 session = apdu->u.initResponse;
3976 // greenstone will call z_get_initResponse to get the info
3977 // about what happened with the connection
3978 //process_initResponse(apdu->u.initResponse);
3979 break;
3980 case Z_APDU_searchResponse:
3981 process_searchResponse(apdu->u.searchResponse);
3982 break;
3983 case Z_APDU_scanResponse:
3984 process_scanResponse(apdu->u.scanResponse);
3985 break;
3986 case Z_APDU_presentResponse:
3987 print_refid (apdu->u.presentResponse->referenceId);
3988 setno +=
3989 *apdu->u.presentResponse->numberOfRecordsReturned;
3990 if (apdu->u.presentResponse->records)
3991 display_records(apdu->u.presentResponse->records);
3992 else
3993 printf("No records.\n");
3994 printf ("nextResultSetPosition = %d\n",
3995 *apdu->u.presentResponse->nextResultSetPosition);
3996 break;
3997 case Z_APDU_sortResponse:
3998 process_sortResponse(apdu->u.sortResponse);
3999 break;
4000 case Z_APDU_extendedServicesResponse:
4001 printf("Got extended services response\n");
4002 process_ESResponse(apdu->u.extendedServicesResponse);
4003 break;
4004 case Z_APDU_close:
4005 printf("Target has closed the association.\n");
4006 process_close(apdu->u.close);
4007 break;
4008 case Z_APDU_resourceControlRequest:
4009 process_resourceControlRequest
4010 (apdu->u.resourceControlRequest);
4011 break;
4012 case Z_APDU_deleteResultSetResponse:
4013 process_deleteResultSetResponse(apdu->u.
4014 deleteResultSetResponse);
4015 break;
4016 default:
4017 printf("Received unknown APDU type (%d).\n",
4018 apdu->which);
4019 close_session ();
4020 }
4021 }
4022#if HAVE_XML2
4023 else if (gdu->which == Z_GDU_HTTP_Response)
4024 {
4025 http_response(gdu->u.HTTP_Response);
4026 }
4027#endif
4028 if (conn && !cs_more(conn))
4029 break;
4030 } // while conn
4031 if (conn)
4032 {
4033#if HAVE_GETTIMEOFDAY
4034 gettimeofday (&tv_end, 0);
4035#if 0
4036 printf ("S/U S/U=%ld/%ld %ld/%ld",
4037 (long) tv_start.tv_sec,
4038 (long) tv_start.tv_usec,
4039 (long) tv_end.tv_sec,
4040 (long) tv_end.tv_usec);
4041#endif
4042 printf ("Elapsed: %.6f\n",
4043 (double) tv_end.tv_usec / 1e6 + tv_end.tv_sec -
4044 ((double) tv_start.tv_usec / 1e6 + tv_start.tv_sec));
4045#endif
4046 }
4047 xfree (netbuffer);
4048}
4049
4050
4051int cmd_cclparse(const char* arg)
4052{
4053 int error, pos;
4054 struct ccl_rpn_node *rpn=NULL;
4055
4056
4057 rpn = ccl_find_str (bibset, arg, &error, &pos);
4058
4059 if (error) {
4060 printf ("%*s^ - ", 3+strlen(last_cmd)+1+pos, " ");
4061 printf ("%s\n", ccl_err_msg (error));
4062 }
4063 else
4064 {
4065 if (rpn)
4066 {
4067 ccl_pr_tree(rpn, stdout);
4068 }
4069 }
4070 if (rpn)
4071 ccl_rpn_delete(rpn);
4072
4073 printf ("\n");
4074
4075 return 0;
4076}
4077
4078
4079int cmd_set_otherinfo(const char* args)
4080{
4081 char oidstr[101], otherinfoString[101];
4082 int otherinfoNo;
4083 int sscan_res;
4084 int oidval;
4085
4086 sscan_res = sscanf (args, "%d %100[^ ] %100s", &otherinfoNo, oidstr, otherinfoString);
4087 if (sscan_res==1) {
4088 /* reset this otherinfo */
4089 if(otherinfoNo>=maxOtherInfosSupported) {
4090 printf("Error otherinfo index to large (%d>%d)\n",
4091 otherinfoNo,maxOtherInfosSupported);
4092 }
4093 extraOtherInfos[otherinfoNo].oidval = -1;
4094 if (extraOtherInfos[otherinfoNo].value)
4095 free(extraOtherInfos[otherinfoNo].value);
4096 return 0;
4097 }
4098 if (sscan_res<3) {
4099 printf("Error in set_otherinfo command \n");
4100 return 0;
4101 }
4102
4103 if (otherinfoNo>=maxOtherInfosSupported) {
4104 printf("Error otherinfo index to large (%d>%d)\n",
4105 otherinfoNo,maxOtherInfosSupported);
4106 }
4107
4108 oidval = oid_getvalbyname (oidstr);
4109 if (oidval == -1 ) {
4110 printf("Error in set_otherinfo command unknown oid %s \n",oidstr);
4111 return 0;
4112 }
4113 extraOtherInfos[otherinfoNo].oidval = oidval;
4114 if(extraOtherInfos[otherinfoNo].value) free(extraOtherInfos[otherinfoNo].value);
4115 extraOtherInfos[otherinfoNo].value = strdup(otherinfoString);
4116
4117 return 0;
4118}
4119
4120int cmd_sleep(const char* args )
4121{
4122 int sec=atoi(args);
4123 if( sec > 0 ) {
4124#ifdef WIN32
4125 Sleep(sec*1000);
4126#else
4127 sleep(sec);
4128#endif
4129 printf("Done sleeping %d seconds\n", sec);
4130 }
4131 return 1;
4132}
4133
4134int cmd_list_otherinfo(const char* args)
4135{
4136 int i;
4137
4138 if(strlen(args)>0) {
4139 i = atoi(args);
4140 if( i >= maxOtherInfosSupported ) {
4141 printf("Error otherinfo index to large (%d>%d)\n",i,maxOtherInfosSupported);
4142 return 0;
4143 }
4144
4145 if(extraOtherInfos[i].oidval != -1)
4146 printf(" otherinfo %d %s %s\n",
4147 i,
4148 yaz_z3950_oid_value_to_str(
4149 (enum oid_value) extraOtherInfos[i].oidval,
4150 CLASS_RECSYN),
4151 extraOtherInfos[i].value);
4152
4153 } else {
4154 for(i=0; i<maxOtherInfosSupported; ++i) {
4155 if(extraOtherInfos[i].oidval != -1)
4156 printf(" otherinfo %d %s %s\n",
4157 i,
4158 yaz_z3950_oid_value_to_str(
4159 (enum oid_value) extraOtherInfos[i].oidval,
4160 CLASS_RECSYN),
4161 extraOtherInfos[i].value);
4162 }
4163
4164 }
4165 return 0;
4166}
4167
4168
4169int cmd_list_all(const char* args) {
4170 int i;
4171
4172 /* connection options */
4173 if(conn) {
4174 printf("Connected to : %s\n",last_open_command);
4175 } else {
4176 if(last_open_command)
4177 printf("Not connected to : %s\n",last_open_command);
4178 else
4179 printf("Not connected : \n");
4180
4181 }
4182 if(yazProxy) printf("using proxy : %s\n",yazProxy);
4183
4184 printf("auto_reconnect : %s\n",auto_reconnect?"on":"off");
4185
4186 if (!auth) {
4187 printf("Authentication : none\n");
4188 } else {
4189 switch(auth->which) {
4190 case Z_IdAuthentication_idPass:
4191 printf("Authentication : IdPass\n");
4192 printf(" Login User : %s\n",auth->u.idPass->userId?auth->u.idPass->userId:"");
4193 printf(" Login Group : %s\n",auth->u.idPass->groupId?auth->u.idPass->groupId:"");
4194 printf(" Password : %s\n",auth->u.idPass->password?auth->u.idPass->password:"");
4195 break;
4196 case Z_IdAuthentication_open:
4197 printf("Authentication : psOpen\n");
4198 printf(" Open string : %s\n",auth->u.open);
4199 break;
4200 default:
4201 printf("Authentication : Unknown\n");
4202 }
4203 }
4204 if (negotiationCharset)
4205 printf("Neg. Character set : `%s'\n", negotiationCharset);
4206
4207 /* bases */
4208 printf("Bases : ");
4209 for (i = 0; i<num_databaseNames; i++) printf("%s ",databaseNames[i]);
4210 printf("\n");
4211
4212 /* Query options */
4213 printf("CCL file : %s\n",ccl_fields);
4214 printf("CQL file : %s\n",cql_fields);
4215 printf("Query type : %s\n",query_type_as_string(queryType));
4216
4217 printf("Named Result Sets : %s\n",setnumber==-1?"off":"on");
4218
4219 /* piggy back options */
4220 printf("ssub/lslb/mspn : %d/%d/%d\n",smallSetUpperBound,largeSetLowerBound,mediumSetPresentNumber);
4221
4222 /* print present related options */
4223 printf("Format : %s\n",yaz_z3950_oid_value_to_str(recordsyntax,CLASS_RECSYN));
4224 printf("Schema : %s\n",record_schema ? record_schema : "not set");
4225 printf("Elements : %s\n",elementSetNames?elementSetNames->u.generic:"");
4226
4227 /* loging options */
4228 printf("APDU log : %s\n",apdu_file?"on":"off");
4229 printf("Record log : %s\n",marc_file?"on":"off");
4230
4231 /* other infos */
4232 printf("Other Info: \n");
4233 cmd_list_otherinfo("");
4234
4235 return 0;
4236}
4237
4238int cmd_clear_otherinfo(const char* args)
4239{
4240 if(strlen(args)>0) {
4241 int otherinfoNo;
4242 otherinfoNo = atoi(args);
4243 if( otherinfoNo >= maxOtherInfosSupported ) {
4244 printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
4245 return 0;
4246 }
4247
4248 if(extraOtherInfos[otherinfoNo].oidval != -1) {
4249 /* only clear if set. */
4250 extraOtherInfos[otherinfoNo].oidval=-1;
4251 free(extraOtherInfos[otherinfoNo].value);
4252 }
4253 } else {
4254 int i;
4255
4256 for(i=0; i<maxOtherInfosSupported; ++i) {
4257 if (extraOtherInfos[i].oidval!=-1 ) {
4258 extraOtherInfos[i].oidval=-1;
4259 free(extraOtherInfos[i].value);
4260 }
4261 }
4262 }
4263 return 0;
4264}
4265
4266static int cmd_help (const char *line);
4267
4268typedef char *(*completerFunctionType)(const char *text, int state);
4269
4270static struct {
4271 char *cmd;
4272 int (*fun)(const char *arg);
4273 char *ad;
4274 completerFunctionType rl_completerfunction;
4275 int complete_filenames;
4276 char **local_tabcompletes;
4277} cmd_array[] = {
4278 {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
4279 {"quit", cmd_quit, "",NULL,0,NULL},
4280 {"find", cmd_find, "<query>",NULL,0,NULL},
4281 {"delete", cmd_delete, "<setname>",NULL,0,NULL},
4282 {"base", cmd_base, "<base-name>",NULL,0,NULL},
4283 {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]",NULL,0,NULL},
4284 {"scan", cmd_scan, "<term>",NULL,0,NULL},
4285 {"scanstep", cmd_scanstep, "<size>",NULL,0,NULL},
4286 {"scanpos", cmd_scanpos, "<size>",NULL,0,NULL},
4287 {"scansize", cmd_scansize, "<size>",NULL,0,NULL},
4288 {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
4289 {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
4290 {"authentication", cmd_authentication, "<acctstring>",NULL,0,NULL},
4291 {"lslb", cmd_lslb, "<largeSetLowerBound>",NULL,0,NULL},
4292 {"ssub", cmd_ssub, "<smallSetUpperBound>",NULL,0,NULL},
4293 {"mspn", cmd_mspn, "<mediumSetPresentNumber>",NULL,0,NULL},
4294 {"status", cmd_status, "",NULL,0,NULL},
4295 {"setnames", cmd_setnames, "",NULL,0,NULL},
4296 {"cancel", cmd_cancel, "",NULL,0,NULL},
4297 {"cancel_find", cmd_cancel_find, "<query>",NULL,0,NULL},
4298 {"format", cmd_format, "<recordsyntax>",complete_format,0,NULL},
4299 {"schema", cmd_schema, "<schema>",complete_schema,0,NULL},
4300 {"elements", cmd_elements, "<elementSetName>",NULL,0,NULL},
4301 {"close", z_cmd_close, "",NULL,0,NULL},
4302 {"attributeset", cmd_attributeset, "<attrset>",complete_attributeset,0,NULL},
4303 {"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
4304 {"refid", cmd_refid, "<id>",NULL,0,NULL},
4305 {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
4306 {"update", cmd_update, "<action> <recid> [<file>]",NULL,0,NULL},
4307 {"update0", cmd_update0, "<action> <recid> [<file>]",NULL,0,NULL},
4308 {"packagename", cmd_packagename, "<packagename>",NULL,0,NULL},
4309 {"proxy", cmd_proxy, "[('tcp'|'ssl')]<host>[':'<port>]",NULL,0,NULL},
4310 {"charset", cmd_charset, "<nego_charset> <output_charset>",NULL,0,NULL},
4311 {"negcharset", cmd_negcharset, "<nego_charset>",NULL,0,NULL},
4312 {"displaycharset", cmd_displaycharset, "<output_charset>",NULL,0,NULL},
4313 {"marccharset", cmd_marccharset, "<charset_name>",NULL,0,NULL},
4314 {"lang", cmd_lang, "<language_code>",NULL,0,NULL},
4315 {".", cmd_source_echo, "<filename>",NULL,1,NULL},
4316 {"!", cmd_subshell, "Subshell command",NULL,1,NULL},
4317 {"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
4318 {"set_berfile", cmd_set_berfile, "<filename>",NULL,1,NULL},
4319 {"set_marcdump", cmd_set_marcdump," <filename>",NULL,1,NULL},
4320 {"set_cclfile", cmd_set_cclfile," <filename>",NULL,1,NULL},
4321 {"set_cqlfile", cmd_set_cqlfile," <filename>",NULL,1,NULL},
4322 {"set_auto_reconnect", cmd_set_auto_reconnect," on|off",complete_auto_reconnect,1,NULL},
4323 {"set_otherinfo", cmd_set_otherinfo,"<otherinfoinddex> <oid> <string>",NULL,0,NULL},
4324 {"sleep", cmd_sleep,"<seconds>",NULL,0,NULL},
4325 {"register_oid", cmd_register_oid,"<name> <class> <oid>",NULL,0,NULL},
4326 {"push_command", cmd_push_command,"<command>",command_generator,0,NULL},
4327 {"register_tab", cmd_register_tab,"<commandname> <tab>",command_generator,0,NULL},
4328 {"cclparse", cmd_cclparse,"<ccl find command>",NULL,0,NULL},
4329 {"list_otherinfo",cmd_list_otherinfo,"[otherinfoinddex]",NULL,0,NULL},
4330 {"list_all",cmd_list_all,"",NULL,0,NULL},
4331 {"clear_otherinfo",cmd_clear_otherinfo,"",NULL,0,NULL},
4332 /* Server Admin Functions */
4333 /* {"adm-reindex", cmd_adm_reindex, "<database-name>",NULL,0,NULL},
4334 {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>",NULL,0,NULL},
4335 {"adm-create", cmd_adm_create, "",NULL,0,NULL},
4336 {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>",NULL,0,NULL},
4337 {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>",NULL,0,NULL},
4338 {"adm-refresh", cmd_adm_refresh, "",NULL,0,NULL},
4339 {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
4340 {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
4341 {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},*/
4342 {"explain", cmd_explain, "", NULL, 0, NULL},
4343 {"options", cmd_options, "", NULL, 0, NULL},
4344 {"zversion", cmd_zversion, "", NULL, 0, NULL},
4345 {"help", cmd_help, "", NULL,0,NULL},
4346 {"init", cmd_init, "", NULL,0,NULL},
4347 {0,0,0,0,0,0}
4348};
4349
4350static int cmd_help (const char *line)
4351{
4352 int i;
4353 char topic[21];
4354
4355 *topic = 0;
4356 sscanf (line, "%20s", topic);
4357
4358 if (*topic == 0)
4359 printf("Commands:\n");
4360 for (i = 0; cmd_array[i].cmd; i++)
4361 if (*topic == 0 || strcmp (topic, cmd_array[i].cmd) == 0)
4362 printf(" %s %s\n", cmd_array[i].cmd, cmd_array[i].ad);
4363 if (strcmp (topic, "find") == 0)
4364 {
4365 printf ("RPN:\n");
4366 printf (" \"term\" Simple Term\n");
4367 printf (" @attr [attset] type=value op Attribute\n");
4368 printf (" @and opl opr And\n");
4369 printf (" @or opl opr Or\n");
4370 printf (" @not opl opr And-Not\n");
4371 printf (" @set set Result set\n");
4372 printf ("\n");
4373 printf ("Bib-1 attribute types\n");
4374 printf ("1=Use: ");
4375 printf ("4=Title 7=ISBN 8=ISSN 30=Date 62=Abstract 1003=Author 1016=Any\n");
4376 printf ("2=Relation: ");
4377 printf ("1< 2<= 3= 4>= 5> 6!= 102=Relevance\n");
4378 printf ("3=Position: ");
4379 printf ("1=First in Field 2=First in subfield 3=Any position\n");
4380 printf ("4=Structure: ");
4381 printf ("1=Phrase 2=Word 3=Key 4=Year 5=Date 6=WordList\n");
4382 printf ("5=Truncation: ");
4383 printf ("1=Right 2=Left 3=L&R 100=No 101=# 102=Re-1 103=Re-2\n");
4384 printf ("6=Completeness:");
4385 printf ("1=Incomplete subfield 2=Complete subfield 3=Complete field\n");
4386 }
4387 return 1;
4388}
4389
4390int cmd_register_tab(const char* arg) {
4391
4392 char command[101], tabargument[101];
4393 int i;
4394 int num_of_tabs;
4395 char** tabslist;
4396
4397 if (sscanf (arg, "%100s %100s", command, tabargument) < 1) {
4398 return 0;
4399 }
4400
4401 /* locate the amdn in the list */
4402 for (i = 0; cmd_array[i].cmd; i++) {
4403 if (!strncmp(cmd_array[i].cmd, command, strlen(command))) {
4404 break;
4405 }
4406 }
4407
4408 if(!cmd_array[i].cmd) {
4409 fprintf(stderr,"Unknown command %s\n",command);
4410 return 1;
4411 }
4412
4413
4414 if(!cmd_array[i].local_tabcompletes)
4415 cmd_array[i].local_tabcompletes = (char **) calloc(1,sizeof(char**));
4416
4417 num_of_tabs=0;
4418
4419 tabslist = cmd_array[i].local_tabcompletes;
4420 for(;tabslist && *tabslist;tabslist++) {
4421 num_of_tabs++;
4422 }
4423
4424 cmd_array[i].local_tabcompletes = (char **)
4425 realloc(cmd_array[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
4426 tabslist=cmd_array[i].local_tabcompletes;
4427 tabslist[num_of_tabs]=strdup(tabargument);
4428 tabslist[num_of_tabs+1]=NULL;
4429 return 1;
4430}
4431
4432
4433void process_cmd_line(char* line)
4434{
4435 int i,res;
4436 char word[32], arg[10240];
4437
4438#if HAVE_GETTIMEOFDAY
4439 gettimeofday (&tv_start, 0);
4440#endif
4441
4442 if ((res = sscanf(line, "%31s %10239[^;]", word, arg)) <= 0)
4443 {
4444 strcpy(word, last_cmd);
4445 *arg = '\0';
4446 }
4447 else if (res == 1)
4448 *arg = 0;
4449 strcpy(last_cmd, word);
4450
4451 /* removed tailing spaces from the arg command */
4452 {
4453 char* p = arg;
4454 char* lastnonspace=NULL;
4455
4456 for(;*p; ++p) {
4457 if(!isspace(*(unsigned char *) p)) {
4458 lastnonspace = p;
4459 }
4460 }
4461 if(lastnonspace)
4462 *(++lastnonspace) = 0;
4463 }
4464
4465 for (i = 0; cmd_array[i].cmd; i++)
4466 if (!strncmp(cmd_array[i].cmd, word, strlen(word)))
4467 {
4468 res = (*cmd_array[i].fun)(arg);
4469 break;
4470 }
4471
4472 if (!cmd_array[i].cmd) /* dump our help-screen */
4473 {
4474 printf("Unknown command: %s.\n", word);
4475 printf("use help for list of commands\n");
4476 /* cmd_help (""); */
4477 res = 1;
4478 }
4479
4480 if(apdu_file) fflush(apdu_file);
4481
4482 if (res >= 2)
4483 wait_and_handle_response();
4484
4485 if(apdu_file)
4486 fflush(apdu_file);
4487 if(marc_file)
4488 fflush(marc_file);
4489}
4490
4491
4492char *command_generator(const char *text, int state)
4493{
4494 static int idx;
4495 if (state==0) {
4496 idx = 0;
4497 }
4498 for( ; cmd_array[idx].cmd; ++idx) {
4499 if (!strncmp(cmd_array[idx].cmd,text,strlen(text))) {
4500 ++idx; /* skip this entry on the next run */
4501 return strdup(cmd_array[idx-1].cmd);
4502 }
4503 }
4504 return NULL;
4505}
4506
4507
4508/*
4509 This function only known how to complete on the first word
4510*/
4511char ** readline_completer(char *text, int start, int end) {
4512#if HAVE_READLINE_READLINE_H
4513
4514 completerFunctionType completerToUse;
4515
4516 if(start == 0) {
4517#if HAVE_READLINE_RL_COMPLETION_MATCHES
4518 char** res=rl_completion_matches(text,
4519 command_generator);
4520#else
4521 char** res=completion_matches(text,
4522 (CPFunction*)command_generator);
4523#endif
4524 rl_attempted_completion_over = 1;
4525 return res;
4526 } else {
4527 char arg[10240],word[32];
4528 int i=0 ,res;
4529 if ((res = sscanf(rl_line_buffer, "%31s %10239[^;]", word, arg)) <= 0) {
4530 rl_attempted_completion_over = 1;
4531 return NULL;
4532 }
4533
4534 for (i = 0; cmd_array[i].cmd; i++) {
4535 if (!strncmp(cmd_array[i].cmd, word, strlen(word))) {
4536 break;
4537 }
4538 }
4539
4540 if(!cmd_array[i].cmd) return NULL;
4541
4542 curret_global_list = cmd_array[i].local_tabcompletes;
4543
4544 completerToUse = cmd_array[i].rl_completerfunction;
4545 if(completerToUse==NULL) /* if no pr. command completer is defined use the default completer */
4546 completerToUse = default_completer;
4547
4548 if(completerToUse) {
4549#ifdef HAVE_READLINE_RL_COMPLETION_MATCHES
4550 char** res=
4551 rl_completion_matches(text,
4552 completerToUse);
4553#else
4554 char** res=
4555 completion_matches(text,
4556 (CPFunction*)completerToUse);
4557#endif
4558 if(!cmd_array[i].complete_filenames)
4559 rl_attempted_completion_over = 1;
4560 return res;
4561 } else {
4562 if(!cmd_array[i].complete_filenames)
4563 rl_attempted_completion_over = 1;
4564 return 0;
4565 }
4566 }
4567#else
4568 return 0;
4569#endif
4570}
4571
4572
4573static void client(void)
4574{
4575 char line[10240];
4576
4577 line[10239] = '\0';
4578
4579#if HAVE_GETTIMEOFDAY
4580 gettimeofday (&tv_start, 0);
4581#endif
4582
4583 while (1)
4584 {
4585 char *line_in = NULL;
4586#if HAVE_READLINE_READLINE_H
4587 if (isatty(0))
4588 {
4589 line_in=readline(C_PROMPT);
4590 if (!line_in)
4591 break;
4592#if HAVE_READLINE_HISTORY_H
4593 if (*line_in)
4594 add_history(line_in);
4595#endif
4596 strncpy(line, line_in, 10239);
4597 free (line_in);
4598 }
4599#endif
4600 if (!line_in)
4601 {
4602 char *end_p;
4603 printf (C_PROMPT);
4604 fflush(stdout);
4605 if (!fgets(line, 10239, stdin))
4606 break;
4607 if ((end_p = strchr (line, '\n')))
4608 *end_p = '\0';
4609 }
4610 process_cmd_line(line);
4611 }
4612}
4613
4614static void show_version(void)
4615{
4616 char vstr[20];
4617
4618 yaz_version(vstr, 0);
4619 printf ("YAZ version: %s\n", YAZ_VERSION);
4620 if (strcmp(vstr, YAZ_VERSION))
4621 printf ("YAZ DLL/SO: %s\n", vstr);
4622 exit(0);
4623}
4624
4625/*
4626int main(int argc, char **argv)
4627{
4628 char *prog = *argv;
4629 char *open_command = 0;
4630 char *auth_command = 0;
4631 char *arg;
4632 int ret;
4633
4634#if HAVE_LOCALE_H
4635 if (!setlocale(LC_CTYPE, ""))
4636 fprintf (stderr, "setlocale failed\n");
4637#endif
4638#if HAVE_LANGINFO_H
4639#ifdef CODESET
4640 codeset = nl_langinfo(CODESET);
4641#endif
4642#endif
4643 if (codeset)
4644 outputCharset = xstrdup(codeset);
4645
4646 ODR_MASK_SET(&z3950_options, Z_Options_search);
4647 ODR_MASK_SET(&z3950_options, Z_Options_present);
4648 ODR_MASK_SET(&z3950_options, Z_Options_namedResultSets);
4649 ODR_MASK_SET(&z3950_options, Z_Options_triggerResourceCtrl);
4650 ODR_MASK_SET(&z3950_options, Z_Options_scan);
4651 ODR_MASK_SET(&z3950_options, Z_Options_sort);
4652 ODR_MASK_SET(&z3950_options, Z_Options_extendedServices);
4653 ODR_MASK_SET(&z3950_options, Z_Options_delSet);
4654
4655 while ((ret = options("k:c:q:a:b:m:v:p:u:t:Vxd:", argv, argc, &arg)) != -2)
4656 {
4657 switch (ret)
4658 {
4659 case 0:
4660 if (!open_command)
4661 {
4662 open_command = (char *) xmalloc (strlen(arg)+6);
4663 strcpy (open_command, "open ");
4664 strcat (open_command, arg);
4665 }
4666 else
4667 {
4668 fprintf(stderr, "%s: Specify at most one server address\n",
4669 prog);
4670 exit(1);
4671 }
4672 break;
4673 case 'd':
4674 dump_file_prefix = arg;
4675 break;
4676 case 'k':
4677 kilobytes = atoi(arg);
4678 break;
4679 case 'm':
4680 if (!(marc_file = fopen (arg, "a")))
4681 {
4682 perror (arg);
4683 exit (1);
4684 }
4685 break;
4686 case 't':
4687 outputCharset = xstrdup(arg);
4688 break;
4689 case 'c':
4690 strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
4691 ccl_fields[sizeof(ccl_fields)-1] = '\0';
4692 break;
4693 case 'q':
4694 strncpy (cql_fields, arg, sizeof(cql_fields)-1);
4695 cql_fields[sizeof(cql_fields)-1] = '\0';
4696 break;
4697 case 'b':
4698 if (!strcmp(arg, "-"))
4699 ber_file=stderr;
4700 else
4701 ber_file=fopen(arg, "a");
4702 break;
4703 case 'a':
4704 if (!strcmp(arg, "-"))
4705 apdu_file=stderr;
4706 else
4707 apdu_file=fopen(arg, "a");
4708 break;
4709 case 'x':
4710 hex_dump = 1;
4711 break;
4712 case 'p':
4713 yazProxy=strdup(arg);
4714 break;
4715 case 'u':
4716 if (!auth_command)
4717 {
4718 auth_command = (char *) xmalloc (strlen(arg)+6);
4719 strcpy (auth_command, "auth ");
4720 strcat (auth_command, arg);
4721 }
4722 break;
4723 case 'v':
4724 yaz_log_init(yaz_log_mask_str(arg), "", 0);
4725 break;
4726 case 'V':
4727 show_version();
4728 break;
4729 default:
4730 fprintf (stderr, "Usage: %s [-m <marclog>] [ -a <apdulog>] "
4731 "[-b berdump] [-c cclfields] \n"
4732 "[-q cqlfields] [-p <proxy-addr>] [-u <auth>] "
4733 "[-k size] [-d dump] [-V] [<server-addr>]\n",
4734 prog);
4735 exit (1);
4736 }
4737 }
4738 z_initialize();
4739 if (auth_command)
4740 {
4741#ifdef HAVE_GETTIMEOFDAY
4742 gettimeofday (&tv_start, 0);
4743#endif
4744 process_cmd_line (auth_command);
4745#if HAVE_READLINE_HISTORY_H
4746 add_history(auth_command);
4747#endif
4748 xfree(auth_command);
4749 }
4750 if (open_command)
4751 {
4752#ifdef HAVE_GETTIMEOFDAY
4753 gettimeofday (&tv_start, 0);
4754#endif
4755 process_cmd_line (open_command);
4756#if HAVE_READLINE_HISTORY_H
4757 add_history(open_command);
4758#endif
4759 xfree(open_command);
4760 }
4761 client ();
4762 exit (0);
4763}
4764*/
4765/*
4766 * Local variables:
4767 * tab-width: 8
4768 * c-basic-offset: 4
4769 * End:
4770 * vim600: sw=4 ts=8 fdm=marker
4771 * vim<600: sw=4 ts=8
4772 */
4773
4774static int z_getAPDU (Z_APDU **ret_apdu) {
4775 int res;
4776
4777 char *netbuffer= 0;
4778 int netbufferlen = 0;
4779 Z_APDU *apdu;
4780 Z_GDU *gdu;
4781
4782 if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) {
4783 close_session();
4784 perror("cs_get");
4785 exit(1);
4786 }
4787 if (!res) {
4788 printf("Target closed connection.\n");
4789 close_session();
4790 exit(1);
4791 }
4792 odr_reset(in); /* release APDU from last round */
4793 record_last = 0;
4794 do_hex_dump(netbuffer, res);
4795 odr_setbuf(in, netbuffer, res, 0);
4796
4797 if (!z_GDU(in, &gdu, 0, 0)) {
4798
4799 odr_perror(in, "Decoding incoming APDU");
4800 fprintf(stderr, "[Near %d]\n", odr_offset(in));
4801 fprintf(stderr, "Packet dump:\n---------\n");
4802 odr_dumpBER(stderr, netbuffer, res);
4803 fprintf(stderr, "---------\n");
4804 if (apdu_file) {
4805 z_GDU(print, &gdu, 0, 0);
4806 odr_reset(print);
4807 }
4808 xfree(netbuffer);
4809 exit(1); /* was break */
4810 }
4811 xfree(netbuffer);
4812 if (apdu_file && !z_GDU(print, &gdu, 0, 0)) {
4813
4814 odr_perror(print, "Failed to print incoming APDU");
4815 odr_reset(print);
4816 return -1; /* was continue */
4817 }
4818 if (gdu->which == Z_GDU_Z3950) {
4819
4820 Z_APDU *apdu = gdu->u.z3950;
4821 (*ret_apdu)=apdu;
4822 return 0;
4823 }
4824 /* else a differnet kind of response, which we don't handle */
4825 return -1;
4826}
4827
4828/* gets a generic response from the server */
4829int z_getnextAPDU () {
4830 Z_APDU *apdu;
4831 apdu=NULL;
4832
4833 z_getAPDU(&apdu);
4834
4835 switch(apdu->which) {
4836
4837 case Z_APDU_initResponse:
4838 // kjdon copying johnmcp
4839 /* save session parameters for later use */
4840 session_mem = odr_extract_mem(in);
4841 session = apdu->u.initResponse;
4842 // greenstone will call z_get_initResponse to get the info
4843 // about what happened with the connection
4844 //process_initResponse(apdu->u.initResponse);
4845 break;
4846 case Z_APDU_searchResponse:
4847 process_searchResponse(apdu->u.searchResponse);
4848 break;
4849 case Z_APDU_scanResponse:
4850 process_scanResponse(apdu->u.scanResponse);
4851 break;
4852 case Z_APDU_presentResponse:
4853 print_refid (apdu->u.presentResponse->referenceId);
4854 setno +=
4855 *apdu->u.presentResponse->numberOfRecordsReturned;
4856 if (apdu->u.presentResponse->records) {
4857 display_records(apdu->u.presentResponse->records);
4858 printf ("nextResultSetPosition = %d\n",
4859 *apdu->u.presentResponse->nextResultSetPosition);
4860 }
4861 else {
4862 printf("No records.\n");
4863 }
4864 break;
4865 case Z_APDU_sortResponse:
4866 process_sortResponse(apdu->u.sortResponse);
4867 break;
4868 case Z_APDU_extendedServicesResponse:
4869 printf("Got extended services response\n");
4870 process_ESResponse(apdu->u.extendedServicesResponse);
4871 break;
4872 case Z_APDU_close:
4873 printf("Target has closed the association.\n");
4874 process_close(apdu->u.close);
4875 break;
4876 case Z_APDU_resourceControlRequest:
4877 process_resourceControlRequest
4878 (apdu->u.resourceControlRequest);
4879 break;
4880 case Z_APDU_deleteResultSetResponse:
4881 process_deleteResultSetResponse(apdu->u.
4882 deleteResultSetResponse);
4883 break;
4884 default:
4885 printf("Received unknown APDU type (%d).\n",
4886 apdu->which);
4887 close_session ();
4888 }
4889 return 0;
4890
4891}
4892
4893/* returns number of records found */
4894/*int z_cmd_dosearch(char *search){
4895
4896}
4897*/
4898/* returns an array of strings containing record titles. The first element
4899 is an int, saying how many titles follow (can be zero). NULL on error. */
4900/*char **z_getrecordTitles(int start,int count){
4901
4902}
4903*/
4904/* returns a string containing the whole marc record */
4905/*char *z_getfullRecord(int record){
4906
4907}
4908*/
4909
4910
4911/* returns number found, arg is query string */
4912int z_cmd_dosearch(char *arg)
4913{
4914 Z_APDU *apdu;
4915 int matching;
4916 int ret_val;
4917 ret_val=send_searchRequest(arg);
4918 if (ret_val==-1) {
4919 /* prefix query error */
4920 return (-1);
4921 }
4922 z_getAPDU(&apdu);
4923 /* check return value??? */
4924 if (apdu->which != Z_APDU_searchResponse)
4925 {
4926 printf("sendsearchRequest() was not replied with a searchResponse!\n");
4927 return (-2);
4928 }
4929 /* let's keep going anyway... */
4930 matching=process_searchResponse(apdu->u.searchResponse);
4931 /* this assumes we want to take action on failure (-1) here rather than
4932 whereever we were called from */
4933 return (matching);
4934}
4935
4936/* src must be NULL-terminated */
4937static char *safeappendstr(char *dest, size_t *allocsize,
4938 size_t *offset, char *src) {
4939 /* allocsize is the amount of space currently allocated to dest,
4940 offset is how far into dest we want to append src */
4941 if (*offset + strlen(src) >= *allocsize) {
4942 *allocsize+=strlen(src)+64; /* add some extra space to save on reallocs */
4943 if ((dest=realloc(dest,*allocsize))==NULL) {
4944 fprintf(stderr, "malloc failed while decoding marc record.\n");
4945 return (NULL);
4946 }
4947 }
4948 strcpy(dest+(*offset), src);
4949 *offset+=strlen(src);
4950 return (dest);
4951}
4952
4953static char *getmarcfields(Z_External *p, int titleonly) {
4954 /* this code is based on marc_display(), with a couple of lines taken from
4955 display_record() in the original client. */
4956 /* if titleonly is non-zero, we only get a (the?) title field, otherwise
4957 return the whole thing */
4958 const char *buf=(char *)p->u.octet_aligned->buf;
4959 char *title; /* our string to return */
4960 int title_maxlen=0; /* amount of space currently allocated */
4961 int title_curlen=0; /* amount of space actually used */
4962 int entry_p;
4963 int record_length;
4964 int indicator_length;
4965 int identifier_length;
4966 int base_address;
4967 int length_data_entry;
4968 int length_starting;
4969 int length_implementation;
4970 FILE *outf;
4971
4972 /* if (!outf) */
4973 outf = stdout;
4974
4975 /* initialise our title. Start with 64 chars */
4976 title_maxlen=64;
4977 if((title=malloc(title_maxlen))==NULL) {
4978 /* not quite sure where stderr will be going, but.... */
4979 fprintf(stderr,"Malloc failed while decoding marc record\n");
4980 return NULL;
4981 }
4982
4983 if (!titleonly) {
4984 strcpy(title,"<table border=1>\n");
4985 title_curlen=strlen(title);
4986 }
4987 else title_curlen=0;
4988
4989 record_length = atoi_n (buf, 5);
4990 if (record_length < 25)
4991 return (NULL); /* -1 */
4992 if (isdigit(buf[10]))
4993 indicator_length = atoi_n (buf+10, 1);
4994 else
4995 indicator_length = 2;
4996 if (isdigit(buf[11]))
4997 identifier_length = atoi_n (buf+11, 1);
4998 else
4999 identifier_length = 2;
5000 base_address = atoi_n (buf+12, 4);
5001
5002 length_data_entry = atoi_n (buf+20, 1);
5003 length_starting = atoi_n (buf+21, 1);
5004 length_implementation = atoi_n (buf+22, 1);
5005
5006 if (0) /* debug */
5007 {
5008 fprintf (outf, "Record length %5d\n", record_length);
5009 fprintf (outf, "Indicator length %5d\n", indicator_length);
5010 fprintf (outf, "Identifier length %5d\n", identifier_length);
5011 fprintf (outf, "Base address %5d\n", base_address);
5012 fprintf (outf, "Length data entry %5d\n", length_data_entry);
5013 fprintf (outf, "Length starting %5d\n", length_starting);
5014 fprintf (outf, "Length implementation %5d\n", length_implementation);
5015 }
5016 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
5017 {
5018 entry_p += 3+length_data_entry+length_starting;
5019 if (entry_p >= record_length)
5020 return (NULL); /* -1 */
5021 }
5022 base_address = entry_p+1;
5023 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
5024 {
5025 int data_length;
5026 int data_offset;
5027 int end_offset;
5028 int i /*, j*/ ;
5029 int startofstring;
5030 int whichtag;
5031 short int abbrtitle=0;
5032 char tag[4];
5033 memcpy (tag, buf+entry_p, 3);
5034 entry_p += 3;
5035 tag[3] = '\0';
5036 whichtag=atoi(tag);
5037 if (0) /* debug */
5038 fprintf (outf, "Tag: ");
5039 /* johnmcp
5040 Relevant tags (for "main entry") - assume only one of these is set,
5041 as we will only return the first one found.
5042 100=personal name
5043 110=corporate name
5044 111=meeting name
5045 130=uniform title
5046 subfields: $a=personal name, $c=title/other, $d=date
5047
5048 210=Abbreviated Title
5049 222=Key title
5050 240=uniform title
5051 243=collective uniform title
5052 245=title statement
5053 246=varying form of title
5054 247=former title or title variations
5055 subfields: $a=abbrev. title $b=qualifying info $2=source
5056 . $6=linkage $8=link field and sequence number.
5057 */
5058 /*fprintf (outf, "%s ", tag); */
5059 data_length = atoi_n (buf+entry_p, length_data_entry);
5060 entry_p += length_data_entry;
5061 data_offset = atoi_n (buf+entry_p, length_starting);
5062 entry_p += length_starting;
5063 i = data_offset + base_address;
5064 end_offset = i+data_length-1;
5065
5066 if (0) /* debug */
5067 fprintf (outf, " Ind: ");
5068
5069 /* memcmp (tag,"00",2) is true, then we DON'T have a control tag
5070 ie less than 10. */
5071 /*if (memcmp (tag, "00", 2) && indicator_length)
5072 {
5073 for (j = 0; j<indicator_length; j++)
5074 fprintf (outf, "%c", buf[i++]);
5075 }
5076 */
5077 if (whichtag>=10) i+=indicator_length;
5078 /* the control fields (<10) don't have leading chars. */
5079
5080
5081 if (0) /* debug */
5082 fprintf (outf, " Fields: ");
5083
5084 /* If we only want the title, then skip other fields */
5085 if (titleonly &&(whichtag<200||whichtag>249)) {
5086 /* skip this record */
5087 continue;
5088 i=end_offset;
5089 }
5090
5091 /* either titleonly is 0, or titleonly is 1 and whichtag is between
5092 200 and 249... */
5093 if (!titleonly) {
5094 /* This should probably be read in from a separate file.
5095 This is also hard-coded for USMARC/MARC21 fieldnames!!! */
5096
5097 /* print out what kind of tag this is */
5098 char *tagname;
5099 char *field_control1="<tr><td>Marc Control Number:</td><td>";
5100 char *field_control3="<tr><td>Marc Organisation Code:</td><td>";
5101 char *field_control5="<tr><td>Marc record Date Info.:</td><td>";
5102 char *field_control8="<tr><td>Control Field (Marc info):</td><td>";
5103 char *field_loc_nr="<tr><td>Lib. of Congress control #:</td><td>";
5104 char *field_issn="<tr><td>ISSN Number:</td><td>";
5105 char *field_catalog="<tr><td>Catalog agency:</td><td>";
5106 char *field_lang="<tr><td>3-letter language code(s):</td><td>";
5107 char *field_areacode="<tr><td>Geographic Area code:</td><td>";
5108 char *field_cn_loc="<tr><td>Lib. of Congress Call #:</td><td>";
5109 char *field_cn_dewdec="<tr><td>Dewey Decimal Call #:</td><td>";
5110 char *field_cn_other="<tr><td>Other Classification Info.:</td><td>";
5111 char *field_cn_gd="<tr><td>Govt. Document Call #:</td><td>";
5112 char *field_personalname="<tr><td>Personal Name:</td><td>";
5113 char *field_meetingname="<tr><td>Meeting Name:</td><td>";
5114 char *field_maintitle="<tr><td>Title:</td><td>";
5115 char *field_edition="<tr><td><Edition Information:</td><td>";
5116 char *field_publication="<tr><td>Publication Info.:</td><td>";
5117 char *field_physdesc="<tr><td>Physical Description:</td><td>";
5118 char *field_series_title="<tr><td>Series Title:</td><td>";
5119 char *field_series_statement="<tr><td>Series Statement:</td><td>";
5120 char *field_note_general="<tr><td>Note:</td><td>";
5121 char *field_note_bib="<tr><td>Bibliographic Note:</td><td>";
5122 char *field_note_summary="<tr><td>Summary Note:</td><td>";
5123 char *field_sub_note="<tr><td>Subject Notes:</td><td>";
5124 char *field_sub_topic="<tr><td>Subject - Topic:</td><td>";
5125 char *field_sub_geog="<tr><td>Subject - Location:</td><td>";
5126 char *field_added_persname="<tr><td>Author Note - Name:</td><td>";
5127 char *field_added_corpname="<tr><td>Author - Organisation:</td><td>";
5128 char *field_uniform_title="<tr><td>Extra Title Information:</td><td>";
5129 char *field_host_item="<tr><td>In:</td><td>";
5130 char *field_series_corpname="<tr><td>Series - Organisation:</td><td>";
5131 /*char *field_url="<tr><td>Electronic Access</td><td><a href=\"";*/
5132 char *field_url="<tr><td>Electronic Access</td><td>";
5133 /*char *field_other="<tr><td>(other field):</td><td>";*/
5134 char tag_num[100];
5135 switch (whichtag) {
5136 case (1): {tagname=field_control1;break;}
5137 case (3): {tagname=field_control3;break;}
5138 case (5): {tagname=field_control5;break;}
5139 case (8): {tagname=field_control8;break;}
5140 case (10): {tagname=field_loc_nr;break;}
5141 case (20): {tagname=field_issn;break;}
5142 case (40): {tagname=field_catalog;break;}
5143 case (41): {tagname=field_lang;break;}
5144 case (43): {tagname=field_areacode;break;}
5145 case (50): {tagname=field_cn_loc;break;}
5146 case (82): {tagname=field_cn_dewdec;break;}
5147 case (84): {tagname=field_cn_other;break;}
5148 case (86): {tagname=field_cn_gd;break;}
5149 case (100): {tagname=field_personalname;break;}
5150 case (111): {tagname=field_meetingname;break;}
5151 case (245): {tagname=field_maintitle;break;}
5152 case (250): {tagname=field_edition;break;}
5153 case (260): {tagname=field_publication;break;}
5154 case (300): {tagname=field_physdesc;break;}
5155 case (440): {tagname=field_series_title;break;}
5156 case (490): {tagname=field_series_statement;break;}
5157 case (500): {tagname=field_note_general;break;}
5158 case (504): {tagname=field_note_bib;break;}
5159 case (520): {tagname=field_note_summary;break;}
5160 case (630): {tagname=field_sub_note;break;}
5161 case (650): {tagname=field_sub_topic;break;}
5162 case (651): {tagname=field_sub_geog;break;}
5163 case (700): {tagname=field_added_persname;break;}
5164 case (710): {tagname=field_added_corpname;break;}
5165 case (730): {tagname=field_uniform_title;break;}
5166 case (773): {tagname=field_host_item;break;}
5167 case (810): {tagname=field_series_corpname;break;}
5168 case (856): {tagname=field_url;break;}
5169 default:
5170 if (whichtag>=90&&whichtag<=99)
5171 tagname="<tr><td>Local Call #:</td><td>";
5172 else {
5173 /*tagname=field_other;*/
5174
5175 /* The trailing '\0' seems to be necessary...?!? */
5176 sprintf(tag_num,"<tr><td>(field %d)</td><td>\n\0",whichtag);
5177 tagname=tag_num;
5178 }
5179 }
5180
5181 /* add the field type */
5182 title=safeappendstr(title, &title_maxlen, &title_curlen, tagname);
5183 }
5184
5185 /* go through current field in current record */
5186 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
5187 {
5188 /* this loop goes through byte by byte, to find end-of-field or
5189 end-of-record separator tags */
5190
5191 /* if (memcmp (tag, "00", 2) && identifier_length)*/
5192 if ( ((titleonly==1&&whichtag==245)||(titleonly==0))
5193 && identifier_length)
5194 {
5195 if (buf[i]==ISO2709_IDFS) {
5196 /* this implies sub-fields for this field */
5197 /* skip sub-field tag, but wrap $a sub-field with <b> & </b>
5198 for HTML if titleonly==1 */
5199 if (buf[i+1]=='a' && titleonly) {
5200 abbrtitle=1;
5201 title=safeappendstr(title,&title_maxlen,&title_curlen,"<b>");
5202 }
5203 i+=identifier_length;
5204 }
5205 /* find end of this (sub-)field */
5206 startofstring=i;
5207 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
5208 buf[i] != ISO2709_FS && i < end_offset)
5209 i++;
5210 /*fprintf (outf, "%c", buf[i++]);*/
5211
5212 /* this only happens the first time around */
5213 if (i==startofstring) continue;
5214
5215 /* now put from $startofstring$ until $i$ into our
5216 string to return */
5217
5218 if (title_curlen+(i-startofstring)>=title_maxlen) {
5219 /* we need to make more room - add max(64,needed) bytes */
5220 if (title_curlen+(i-startofstring)-title_maxlen>63)
5221 title_maxlen+=(i-startofstring)+1;/*+1 for trailing \0 */
5222 else
5223 title_maxlen+=64;
5224 if ((title=realloc(title,title_maxlen))==NULL) {
5225 fprintf(stderr,"malloc failed decoding marc record\n");
5226 return (NULL);
5227 }
5228 }
5229
5230 strncpy(title+title_curlen,buf+startofstring,i-startofstring);
5231 title_curlen+=(i-startofstring);
5232 *(title+title_curlen)='\0';
5233 /* overwrite ISO2709_?S with \0 */
5234 /* *(title+title_curlen+i-startofstring)='\0';*/
5235 /*safeappendstr(title,&title_maxlen,
5236 &title_curlen,buf+startofstring);*/
5237
5238 /* if 'main' title, close HTML </B> tag */
5239 if (abbrtitle) {
5240 title=safeappendstr(title,&title_maxlen,&title_curlen,"</b>");
5241 abbrtitle=0;
5242 }
5243 /* end of this marc sub--field
5244 buf[i]==ISO2709_RS if end of record.
5245 buf[i]==ISO2709_FS if end of field,
5246 buf[i]==ISO2709_IDFS if end of sub-field. */
5247 if (titleonly==0) {
5248 if (buf[i]==ISO2709_IDFS) {
5249 /* there is a following sub-field, so only add whitespace */
5250 title=safeappendstr(title,&title_maxlen,&title_curlen," ");
5251 }
5252 else {
5253 /* end of record, so close HTML table row */
5254#if 0
5255 if (whichtag==856) /* special case: this is a url! */
5256 title=safeappendstr(title,&title_maxlen,&title_curlen,
5257 "\">Uniform Resource Locator</a>");
5258#endif
5259 title=safeappendstr(title, &title_maxlen, &title_curlen,
5260 "</td></tr>\n");
5261 }
5262 } /* end of if (titleonly==0) */
5263 } /* end of if ( ((titleonly==1&&....... */
5264 else { /* whichtag not matched (if titleonly) */
5265 /*fprintf (outf, "%c", buf[i++]);*/
5266 /* skip this char for now - should ideally skip whole field */
5267 i++;
5268 }
5269 } /* end of while loop - at end of field or record */
5270 /*fprintf (outf, "\n");*/
5271 /*if (i < end_offset)
5272 fprintf (outf, "-- separator but not at end of field\n");
5273 if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
5274 fprintf (outf, "-- no separator at end of field\n");
5275 */
5276 }
5277
5278 /* at end of whole record. */
5279 if (!titleonly)
5280 title=safeappendstr(title, &title_maxlen, &title_curlen, "</table>\n");
5281 return (title);
5282
5283}
5284static char *getrecordtitle(Z_External *record) {
5285 return(getmarcfields(record,1));
5286}
5287
5288char *z_getfullRecord(int start) {
5289 Z_APDU *apdu;
5290 Z_External *record;
5291 char *fullrecord;
5292
5293 fullrecord=NULL;
5294 z_send_getbriefrecords(start,1,1); /* for now, use getbriefrecords */
5295 z_getAPDU(&apdu);
5296
5297 if (apdu->which != Z_APDU_presentResponse) {
5298 /* out-of-order packets.... */
5299 fprintf(stderr,"Not a present response to present request\n");
5300 return NULL;
5301 }
5302
5303 /* just do some double checking */
5304 if (*apdu->u.presentResponse->numberOfRecordsReturned!=1 ||
5305 !apdu->u.presentResponse->records ) {
5306 /* something bad has happened... johnmcp */
5307 fprintf (stderr,"Error occured in yaz while getting record (GSDL)\n");
5308 }
5309
5310 switch (apdu->u.presentResponse->records->which) {
5311 case Z_Records_DBOSD: break; /* do nothing - this is a record */
5312
5313 /* otherwise we got a diagnostic message... */
5314 case Z_Records_NSD:
5315 switch (apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which){
5316 /* these are both represented as char* in yaz, so either is OK */
5317 /* case Z_DefaultDiagForm_v2Addinfo:
5318 case Z_DefaultDiagForm_v3Addinfo: --wrong names*/
5319 case Z_DiagnosticFormat_s_defaultDiagRec:
5320 case Z_DiagnosticFormat_s_explicitDiagnostic:
5321 return apdu->u.presentResponse->records->u.nonSurrogateDiagnostic
5322 ->u.v2Addinfo; /* return the error message */
5323 default: ; /* this should happen for v3 of the spec... */
5324 }
5325 case Z_Records_multipleNSD: ; /* should handle one day... */
5326 }
5327
5328 record=apdu->u.presentResponse->records->u.databaseOrSurDiagnostics->
5329 records[0]->u.databaseRecord;
5330
5331 return(getmarcfields(record,0));
5332}
5333
5334char **z_getrecordTitles(/*int resultset,*/ int starting, int howmany) {
5335 Z_APDU *apdu;
5336 char **titles;
5337 /* titles will be an array of strings. The first element will really
5338 be an int, saying how many strings follow. Ie 1st string in titles[1] */
5339 int count;
5340 int i;
5341
5342 titles=NULL;
5343
5344 /* WE SHOULD SET THE RECORD FORMAT SOMEWHERE..... USMARC (default)
5345 but may also want SUTRS support. */
5346
5347 /* sends a presentRequest - we need to know the set number - johnmcp */
5348 z_send_getbriefrecords(starting, 1, howmany);
5349 /* CHECK RETURN VALUE (currently only 0) */
5350
5351
5352 z_getAPDU(&apdu);
5353 if (apdu->which != Z_APDU_presentResponse) {
5354 /* we got out-of-sync.... */
5355 fprintf(stderr,"Not a present response to present request\n");
5356 return NULL;
5357 }
5358
5359 print_refid (apdu->u.presentResponse->referenceId);
5360 count=*apdu->u.presentResponse->numberOfRecordsReturned;
5361 setno += count;
5362 if (apdu->u.presentResponse->records) {
5363 /* extract the titles from each record, and return it as an array of
5364 strings */
5365 if (count==1 &&
5366 apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
5367 fprintf(stderr,"only one returned");
5368 /* apdu->u.presentResponse->records->which gives a type:
5369 1=databaseOrSurDiagnostics | 2=nonSurrogateDiagnostic |
5370 3=multipleNonSurDiagnostics.
5371 Type 1 implies it is a database record. FROM z-core.h,
5372 NOT prt-proto.h!!!!! */
5373
5374 /* for type 2:
5375 apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which:
5376 1=v2Addinfo | 2=v3Addinfo, and u.v[23]Addinfo is a (char *).
5377
5378 */
5379 titles=malloc(sizeof(char *));
5380 titles[0]=(char *)0;
5381 /* could put error message and titles[1], and set titles[0] to -1. */
5382
5383
5384 }
5385 else /* more than 1 rec returned, so ?has? to be db records (dblcheck!!)*/
5386 {
5387 fprintf(stderr,"more than one rec returned, count=%d\n", count);
5388 titles=malloc(sizeof(char *)*count + 1);
5389 /* check malloc succeeded... */
5390 titles[0]=(char *)count;
5391 for (i=1;i<=count;i++) {
5392 titles[i]=getrecordtitle(apdu->u.presentResponse->records->
5393 u.databaseOrSurDiagnostics->records[i-1]->
5394 u.databaseRecord);
5395 }
5396 }
5397 }
5398 else {
5399 fprintf(stderr,"no records retruend");
5400 titles=malloc(sizeof(char *));
5401 titles[0]=(char *)0;
5402 }
5403 /* printf ("nextResultSetPosition = %d\n",
5404 *apdu->u.presentResponse->nextResultSetPosition); */
5405 return (titles);
5406}
5407
Note: See TracBrowser for help on using the repository browser.