source: main/trunk/greenstone2/runtime-src/src/z3950/yaz_zclient.c@ 27061

Last change on this file since 27061 was 15492, checked in by mdewsnip, 16 years ago

New directory to contain all the Z39.50 code (currently incomplete).

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