YAZ  4.2.57
zoom-z3950.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <assert.h>
14 #include <string.h>
15 #include <errno.h>
16 #include "zoom-p.h"
17 
18 #include <yaz/yaz-util.h>
19 #include <yaz/xmalloc.h>
20 #include <yaz/otherinfo.h>
21 #include <yaz/log.h>
22 #include <yaz/pquery.h>
23 #include <yaz/marcdisp.h>
24 #include <yaz/diagbib1.h>
25 #include <yaz/charneg.h>
26 #include <yaz/ill.h>
27 #include <yaz/query-charset.h>
28 #include <yaz/copy_types.h>
29 #include <yaz/snprintf.h>
30 #include <yaz/facet.h>
31 
32 #include <yaz/shptr.h>
33 
34 /*
35  * This wrapper is just for logging failed lookups. It would be nicer
36  * if it could cause failure when a lookup fails, but that's hard.
37  */
39  oid_class oid_class, const char *str) {
40  Odr_oid *res = yaz_string_to_oid_odr(yaz_oid_std(), oid_class, str,
41  c->odr_out);
42  if (res == 0)
43  yaz_log(YLOG_WARN, "%p OID lookup (%d, '%s') failed",
44  c, (int) oid_class, str);
45  return res;
46 }
47 
49 {
50  const char *str;
53 
54  str = ZOOM_options_get(p->options, "package-name");
55  if (str && *str)
56  req->packageName = odr_strdup(p->odr_out, str);
57 
58  str = ZOOM_options_get(p->options, "user-id");
59  if (str)
60  req->userId = odr_strdup_null(p->odr_out, str);
61 
62  req->packageType = odr_oiddup(p->odr_out, oid);
63 
64  str = ZOOM_options_get(p->options, "function");
65  if (str)
66  {
67  if (!strcmp (str, "create"))
69  if (!strcmp (str, "delete"))
71  if (!strcmp (str, "modify"))
73  }
74 
75  str = ZOOM_options_get(p->options, "waitAction");
76  if (str)
77  {
78  if (!strcmp (str, "wait"))
80  if (!strcmp (str, "waitIfPossible"))
82  if (!strcmp (str, "dontWait"))
84  if (!strcmp (str, "dontReturnPackage"))
86  }
87  return apdu;
88 }
89 
90 static const char *ill_array_lookup(void *clientData, const char *idx)
91 {
92  ZOOM_package p = (ZOOM_package) clientData;
93  return ZOOM_options_get(p->options, idx+4);
94 }
95 
97 {
98  ODR out = p->odr_out;
99  ILL_Request *req;
100  Z_External *r = 0;
101  struct ill_get_ctl ctl;
102 
103  ctl.odr = p->odr_out;
104  ctl.clientData = p;
105  ctl.f = ill_array_lookup;
106 
107  req = ill_get_ILLRequest(&ctl, "ill", 0);
108 
109  if (!ill_Request(out, &req, 0, 0))
110  {
111  int ill_request_size;
112  char *ill_request_buf = odr_getbuf(out, &ill_request_size, 0);
113  if (ill_request_buf)
114  odr_setbuf(out, ill_request_buf, ill_request_size, 1);
115  return 0;
116  }
117  else
118  {
119  int illRequest_size = 0;
120  char *illRequest_buf = odr_getbuf(out, &illRequest_size, 0);
121 
122  r = (Z_External *) odr_malloc(out, sizeof(*r));
124  r->indirect_reference = 0;
125  r->descriptor = 0;
127 
128  r->u.single_ASN1_type =
129  odr_create_Odr_oct(out,
130  (unsigned char *)illRequest_buf,
131  illRequest_size);
132  }
133  return r;
134 }
135 
137 {
138  Z_ItemOrder *req = (Z_ItemOrder *) odr_malloc(p->odr_out, sizeof(*req));
139  const char *str;
140  int len;
141 
143  req->u.esRequest = (Z_IORequest *)
144  odr_malloc(p->odr_out,sizeof(Z_IORequest));
145 
146  /* to keep part ... */
149  req->u.esRequest->toKeep->supplDescription = 0;
150  req->u.esRequest->toKeep->contact = (Z_IOContact *)
151  odr_malloc(p->odr_out, sizeof(*req->u.esRequest->toKeep->contact));
152 
153  str = ZOOM_options_get(p->options, "contact-name");
154  req->u.esRequest->toKeep->contact->name =
155  odr_strdup_null(p->odr_out, str);
156 
157  str = ZOOM_options_get(p->options, "contact-phone");
158  req->u.esRequest->toKeep->contact->phone =
159  odr_strdup_null(p->odr_out, str);
160 
161  str = ZOOM_options_get(p->options, "contact-email");
162  req->u.esRequest->toKeep->contact->email =
163  odr_strdup_null(p->odr_out, str);
164 
165  req->u.esRequest->toKeep->addlBilling = 0;
166 
167  /* not to keep part ... */
170 
171  str = ZOOM_options_get(p->options, "itemorder-setname");
172  if (!str)
173  str = "default";
174 
175  if (!*str)
176  req->u.esRequest->notToKeep->resultSetItem = 0;
177  else
178  {
180  odr_malloc(p->odr_out, sizeof(Z_IOResultSetItem));
181 
183  odr_strdup(p->odr_out, str);
185  odr_intdup(p->odr_out, 0);
186 
187  str = ZOOM_options_get(p->options, "itemorder-item");
189  (str ? atoi(str) : 1);
190  }
191 
192  str = ZOOM_options_getl(p->options, "doc", &len);
193  if (str)
194  {
196  z_ext_record_xml(p->odr_out, str, len);
197  }
198  else
200 
201  return req;
202 }
203 
205  Z_ESAdminOriginPartToKeep **toKeepP,
206  Z_ESAdminOriginPartNotToKeep **notToKeepP)
207 {
209  if (apdu)
210  {
212  Z_ESAdminOriginPartNotToKeep *notToKeep;
213  Z_External *r = (Z_External *) odr_malloc(p->odr_out, sizeof(*r));
214  const char *first_db = "Default";
215  int num_db;
217  p->options, &num_db,
218  p->odr_out);
219  if (num_db > 0)
220  first_db = db[0];
221 
223  r->descriptor = 0;
224  r->indirect_reference = 0;
226 
227  r->u.adminService = (Z_Admin *)
228  odr_malloc(p->odr_out, sizeof(*r->u.adminService));
231  odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest));
232 
233  toKeep = r->u.adminService->u.esRequest->toKeep =
235  odr_malloc(p->odr_out, sizeof(*r->u.adminService->u.esRequest->toKeep));
236  toKeep->which = type;
237  toKeep->databaseName = odr_strdup(p->odr_out, first_db);
238  toKeep->u.create = odr_nullval();
240 
241  r->u.adminService->u.esRequest->notToKeep = notToKeep =
243  odr_malloc(p->odr_out,
244  sizeof(*r->u.adminService->u.esRequest->notToKeep));
246  notToKeep->u.recordsWillFollow = odr_nullval();
247  if (toKeepP)
248  *toKeepP = toKeep;
249  if (notToKeepP)
250  *notToKeepP = notToKeep;
251  }
252  return apdu;
253 }
254 
256 {
259  Z_External *ext = (Z_External *) odr_malloc(p->odr_out, sizeof(*ext));
260  int len;
261  const char *doc = ZOOM_options_getl(p->options, "doc", &len);
262 
263  if (!doc)
264  {
265  doc = "";
266  len = 0;
267  }
268 
269  req->taskSpecificParameters = ext;
270  ext->direct_reference = req->packageType;
271  ext->descriptor = 0;
272  ext->indirect_reference = 0;
273 
274  ext->which = Z_External_octet;
275  ext->u.single_ASN1_type =
276  odr_create_Odr_oct(p->odr_out, (const unsigned char *) doc, len);
277  return apdu;
278 }
279 
281 {
282  Z_APDU *apdu = 0;
283  const char *first_db = "Default";
284  int num_db;
286  &num_db, p->odr_out);
287  const char *action = ZOOM_options_get(p->options, "action");
288  int recordIdOpaque_len;
289  const char *recordIdOpaque = ZOOM_options_getl(p->options, "recordIdOpaque",
290  &recordIdOpaque_len);
291  const char *recordIdNumber = ZOOM_options_get(p->options, "recordIdNumber");
292  int record_len;
293  const char *record_buf = ZOOM_options_getl(p->options, "record",
294  &record_len);
295  int recordOpaque_len;
296  const char *recordOpaque_buf = ZOOM_options_getl(p->options, "recordOpaque",
297  &recordOpaque_len);
298  const char *syntax_str = ZOOM_options_get(p->options, "syntax");
299  const char *version = ZOOM_options_get(p->options, "updateVersion");
300 
301  const char *correlationInfo_note =
302  ZOOM_options_get(p->options, "correlationInfo.note");
303  const char *correlationInfo_id =
304  ZOOM_options_get(p->options, "correlationInfo.id");
305  int action_no = -1;
306  Odr_oid *syntax_oid = 0;
307  const Odr_oid *package_oid = yaz_oid_extserv_database_update;
308 
309  if (!version)
310  version = "3";
311  if (!syntax_str)
312  syntax_str = "xml";
313  if (!record_buf && !recordOpaque_buf)
314  {
315  record_buf = "void";
316  record_len = 4;
317  syntax_str = "SUTRS";
318  }
319 
320  if (syntax_str)
321  {
322  syntax_oid = yaz_string_to_oid_odr(yaz_oid_std(),
323  CLASS_RECSYN, syntax_str,
324  p->odr_out);
325  }
326  if (!syntax_oid)
327  {
329  return 0;
330  }
331 
332  if (num_db > 0)
333  first_db = db[0];
334 
335  switch (*version)
336  {
337  case '1':
339  /* old update does not support specialUpdate */
340  if (!action)
341  action = "recordInsert";
342  break;
343  case '2':
344  if (!action)
345  action = "specialUpdate";
347  break;
348  case '3':
349  if (!action)
350  action = "specialUpdate";
351  package_oid = yaz_oid_extserv_database_update;
352  break;
353  default:
355  return 0;
356  }
357 
358  if (!strcmp(action, "recordInsert"))
360  else if (!strcmp(action, "recordReplace"))
362  else if (!strcmp(action, "recordDelete"))
364  else if (!strcmp(action, "elementUpdate"))
366  else if (!strcmp(action, "specialUpdate"))
368  else
369  {
371  return 0;
372  }
373 
374  apdu = create_es_package(p, package_oid);
375  if (apdu)
376  {
377  Z_IUOriginPartToKeep *toKeep;
378  Z_IUSuppliedRecords *notToKeep;
379  Z_External *r = (Z_External *)
380  odr_malloc(p->odr_out, sizeof(*r));
381  const char *elementSetName =
382  ZOOM_options_get(p->options, "elementSetName");
383 
385 
386  r->direct_reference = odr_oiddup(p->odr_out, package_oid);
387  r->descriptor = 0;
389  r->indirect_reference = 0;
390  r->u.update = (Z_IUUpdate *)
391  odr_malloc(p->odr_out, sizeof(*r->u.update));
392 
395  odr_malloc(p->odr_out, sizeof(*r->u.update->u.esRequest));
396  toKeep = r->u.update->u.esRequest->toKeep =
398  odr_malloc(p->odr_out, sizeof(*toKeep));
399 
400  toKeep->databaseName = odr_strdup(p->odr_out, first_db);
401  toKeep->schema = 0;
402 
403  toKeep->elementSetName = odr_strdup_null(p->odr_out, elementSetName);
404 
405  toKeep->actionQualifier = 0;
406  toKeep->action = odr_intdup(p->odr_out, action_no);
407 
408  notToKeep = r->u.update->u.esRequest->notToKeep =
410  odr_malloc(p->odr_out, sizeof(*notToKeep));
411  notToKeep->num = 1;
412  notToKeep->elements = (Z_IUSuppliedRecords_elem **)
413  odr_malloc(p->odr_out, sizeof(*notToKeep->elements));
414  notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
415  odr_malloc(p->odr_out, sizeof(**notToKeep->elements));
417  if (recordIdOpaque)
418  {
419  notToKeep->elements[0]->u.opaque =
421  (const unsigned char *) recordIdOpaque,
422  recordIdOpaque_len);
423  }
424  else if (recordIdNumber)
425  {
427 
428  notToKeep->elements[0]->u.number =
429  odr_intdup(p->odr_out, atoi(recordIdNumber));
430  }
431  else
432  notToKeep->elements[0]->u.opaque = 0;
433  notToKeep->elements[0]->supplementalId = 0;
434  if (correlationInfo_note || correlationInfo_id)
435  {
437  ci = notToKeep->elements[0]->correlationInfo =
438  (Z_IUCorrelationInfo *) odr_malloc(p->odr_out, sizeof(*ci));
439  ci->note = odr_strdup_null(p->odr_out, correlationInfo_note);
440  ci->id = correlationInfo_id ?
441  odr_intdup(p->odr_out, atoi(correlationInfo_id)) : 0;
442  }
443  else
444  notToKeep->elements[0]->correlationInfo = 0;
445  if (recordOpaque_buf)
446  {
447  notToKeep->elements[0]->record =
448  z_ext_record_oid_any(p->odr_out, syntax_oid,
449  recordOpaque_buf, recordOpaque_len);
450  }
451  else
452  {
453  notToKeep->elements[0]->record =
454  z_ext_record_oid(p->odr_out, syntax_oid,
455  record_buf, record_len);
456  }
457  }
458  if (0 && apdu)
459  {
460  ODR print = odr_createmem(ODR_PRINT);
461 
462  z_APDU(print, &apdu, 0, 0);
463  odr_destroy(print);
464  }
465  return apdu;
466 }
467 
468 
470 {
471  int i;
472  for (i = 0; i<200; i++)
473  {
474  size_t len;
475  Odr_oid *oid;
476  Z_OtherInformation **oi;
477  char buf[80];
478  const char *val;
479  const char *cp;
480 
481  sprintf(buf, "otherInfo%d", i);
482  val = ZOOM_options_get(c->options, buf);
483  if (!val)
484  break;
485  cp = strchr(val, ':');
486  if (!cp)
487  continue;
488  len = cp - val;
489  if (len >= sizeof(buf))
490  len = sizeof(buf)-1;
491  memcpy(buf, val, len);
492  buf[len] = '\0';
493 
495  buf, out);
496  if (!oid)
497  continue;
498 
499  yaz_oi_APDU(a, &oi);
500  yaz_oi_set_string_oid(oi, out, oid, 1, cp+1);
501  }
502 }
503 
504 
505 
506 static int encode_APDU(ZOOM_connection c, Z_APDU *a, ODR out)
507 {
508  assert(a);
509  if (c->cookie_out)
510  {
511  Z_OtherInformation **oi;
512  yaz_oi_APDU(a, &oi);
514  1, c->cookie_out);
515  }
516  if (c->client_IP)
517  {
518  Z_OtherInformation **oi;
519  yaz_oi_APDU(a, &oi);
521  1, c->client_IP);
522  }
523  otherInfo_attach(c, a, out);
524  if (!z_APDU(out, &a, 0, 0))
525  {
526  FILE *outf = fopen("/tmp/apdu.txt", "a");
527  if (a && outf)
528  {
529  ODR odr_pr = odr_createmem(ODR_PRINT);
530  fprintf(outf, "a=%p\n", a);
531  odr_setprint(odr_pr, outf);
532  z_APDU(odr_pr, &a, 0, 0);
533  odr_destroy(odr_pr);
534  }
535  yaz_log(c->log_api, "%p encoding_APDU: encoding failed", c);
537  odr_reset(out);
538  return -1;
539  }
540  if (c->odr_print)
541  z_APDU(c->odr_print, &a, 0, 0);
542  if (c->odr_save)
543  z_APDU(c->odr_save, &a, 0, 0);
544  yaz_log(c->log_details, "%p encoding_APDU encoding OK", c);
545  return 0;
546 }
547 
549 {
550  ZOOM_Event event;
551  assert(a);
552  if (encode_APDU(c, a, c->odr_out))
553  return zoom_complete;
554  yaz_log(c->log_details, "%p send APDU type=%d", c, a->which);
555  c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
557  ZOOM_connection_put_event(c, event);
558  odr_reset(c->odr_out);
559  return ZOOM_send_buf(c);
560 }
561 
563 {
565  Z_InitRequest *ireq = apdu->u.initRequest;
567  odr_malloc(c->odr_out, sizeof(*auth));
568 
575 
579 
580  ireq->implementationId =
581  odr_prepend(c->odr_out,
582  ZOOM_options_get(c->options, "implementationId"),
583  ireq->implementationId);
584 
585  ireq->implementationName =
586  odr_prepend(c->odr_out,
587  ZOOM_options_get(c->options, "implementationName"),
588  odr_prepend(c->odr_out, "ZOOM-C",
589  ireq->implementationName));
590 
591  ireq->implementationVersion =
592  odr_prepend(c->odr_out,
593  ZOOM_options_get(c->options, "implementationVersion"),
594  ireq->implementationVersion);
595 
598 
599  if (c->group || c->password)
600  {
601  Z_IdPass *pass = (Z_IdPass *) odr_malloc(c->odr_out, sizeof(*pass));
602  pass->groupId = odr_strdup_null(c->odr_out, c->group);
603  pass->userId = odr_strdup_null(c->odr_out, c->user);
604  pass->password = odr_strdup_null(c->odr_out, c->password);
606  auth->u.idPass = pass;
607  ireq->idAuthentication = auth;
608  }
609  else if (c->user)
610  {
612  auth->u.open = odr_strdup(c->odr_out, c->user);
613  ireq->idAuthentication = auth;
614  }
615  if (c->proxy)
616  {
619  }
620  if (c->charset || c->lang)
621  {
622  Z_OtherInformation **oi;
623  Z_OtherInformationUnit *oi_unit;
624 
625  yaz_oi_APDU(apdu, &oi);
626 
627  if ((oi_unit = yaz_oi_update(oi, c->odr_out, NULL, 0, 0)))
628  {
633  c->charset, c->lang, 1);
634  }
635  }
636  assert(apdu);
637  return send_APDU(c, apdu);
638 }
639 
641 {
642  ZOOM_resultset r;
643  int lslb, ssub, mspn;
644  const char *syntax;
646  Z_SearchRequest *search_req = apdu->u.searchRequest;
647  const char *elementSetName;
648  const char *smallSetElementSetName;
649  const char *mediumSetElementSetName;
650  const char *facets;
651 
652  assert(c->tasks);
653  assert(c->tasks->which == ZOOM_TASK_SEARCH);
654 
655  r = c->tasks->u.search.resultset;
656 
657  yaz_log(c->log_details, "%p ZOOM_connection_send_search set=%p", c, r);
658 
659  elementSetName =
660  ZOOM_options_get(r->options, "elementSetName");
661  smallSetElementSetName =
662  ZOOM_options_get(r->options, "smallSetElementSetName");
663  mediumSetElementSetName =
664  ZOOM_options_get(r->options, "mediumSetElementSetName");
665 
666  if (!smallSetElementSetName)
667  smallSetElementSetName = elementSetName;
668 
669  if (!mediumSetElementSetName)
670  mediumSetElementSetName = elementSetName;
671 
672  facets = ZOOM_options_get(r->options, "facets");
673  if (facets) {
674  Z_FacetList *facet_list = yaz_pqf_parse_facet_list(c->odr_out, facets);
675  if (facet_list) {
676  Z_OtherInformation **oi;
677  yaz_oi_APDU(apdu, &oi);
678  yaz_oi_set_facetlist(oi, c->odr_out, facet_list);
679  }
680  else
681  yaz_log(YLOG_WARN, "Unable to parse facets: %s", facets);
682  }
683 
684  assert(r);
685  assert(r->query);
686 
687  /* prepare query for the search request */
688  search_req->query = ZOOM_query_get_Z_Query(r->query);
689  if (!search_req->query)
690  {
692  return zoom_complete;
693  }
694  if (search_req->query->which == Z_Query_type_1 ||
695  search_req->query->which == Z_Query_type_101)
696  {
697  const char *cp = ZOOM_options_get(r->options, "rpnCharset");
698  if (cp)
699  {
700  yaz_iconv_t cd = yaz_iconv_open(cp, "UTF-8");
701  if (cd)
702  {
703  int r;
704  search_req->query = yaz_copy_Z_Query(search_req->query,
705  c->odr_out);
706 
708  search_req->query->u.type_1,
709  c->odr_out, cd);
710  yaz_iconv_close(cd);
711  if (r)
712  { /* query could not be char converted */
714  return zoom_complete;
715  }
716  }
717  }
718  }
719  search_req->databaseNames = r->databaseNames;
720  search_req->num_databaseNames = r->num_databaseNames;
721 
722  /* get syntax (no need to provide unless piggyback is in effect) */
723  syntax = c->tasks->u.search.syntax;
724 
725  lslb = ZOOM_options_get_int(r->options, "largeSetLowerBound", -1);
726  ssub = ZOOM_options_get_int(r->options, "smallSetUpperBound", -1);
727  mspn = ZOOM_options_get_int(r->options, "mediumSetPresentNumber", -1);
728  if (lslb != -1 && ssub != -1 && mspn != -1)
729  {
730  /* So're a Z39.50 expert? Let's hope you don't do sort */
731  *search_req->largeSetLowerBound = lslb;
732  *search_req->smallSetUpperBound = ssub;
733  *search_req->mediumSetPresentNumber = mspn;
734  }
735  else if (c->tasks->u.search.start == 0 && c->tasks->u.search.count > 0
736  && r->piggyback && !r->r_sort_spec && !r->schema)
737  {
738  /* Regular piggyback - do it unless we're going to do sort */
739  *search_req->largeSetLowerBound = 2000000000;
740  *search_req->smallSetUpperBound = 1;
741  *search_req->mediumSetPresentNumber =
742  r->step>0 ? r->step : c->tasks->u.search.count;
743  }
744  else
745  {
746  /* non-piggyback. Need not provide elementsets or syntaxes .. */
747  smallSetElementSetName = 0;
748  mediumSetElementSetName = 0;
749  syntax = 0;
750  }
751  if (smallSetElementSetName && *smallSetElementSetName)
752  {
754  odr_malloc(c->odr_out, sizeof(*esn));
755 
757  esn->u.generic = odr_strdup(c->odr_out, smallSetElementSetName);
758  search_req->smallSetElementSetNames = esn;
759  }
760  if (mediumSetElementSetName && *mediumSetElementSetName)
761  {
763  odr_malloc(c->odr_out, sizeof(*esn));
764 
766  esn->u.generic = odr_strdup(c->odr_out, mediumSetElementSetName);
767  search_req->mediumSetElementSetNames = esn;
768  }
769  if (syntax)
770  search_req->preferredRecordSyntax =
772 
773  if (!r->setname)
774  {
776  {
777  char setname[14];
778  int ord;
779  /* find the lowest unused ordinal so that we re-use
780  result sets on the server. */
781  for (ord = 1; ; ord++)
782  {
783 #if ZOOM_RESULT_LISTS
784  ZOOM_resultsets rsp;
785  sprintf(setname, "%d", ord);
786  for (rsp = c->resultsets; rsp; rsp = rsp->next)
787  if (rsp->resultset->setname && !strcmp(rsp->resultset->setname, setname))
788  break;
789  if (!rsp)
790  break;
791 #else
792  ZOOM_resultset rp;
793  sprintf(setname, "%d", ord);
794  for (rp = c->resultsets; rp; rp = rp->next)
795  if (rp->setname && !strcmp(rp->setname, setname))
796  break;
797  if (!rp)
798  break;
799 #endif
800 
801  }
802  r->setname = xstrdup(setname);
803  yaz_log(c->log_details, "%p ZOOM_connection_send_search: "
804  "allocating set %s", c, r->setname);
805  }
806  else
807  {
808  yaz_log(c->log_details, "%p ZOOM_connection_send_search: using "
809  "default set", c);
810  r->setname = xstrdup("default");
811  }
812  ZOOM_options_set(r->options, "setname", r->setname);
813  }
814  search_req->resultSetName = odr_strdup(c->odr_out, r->setname);
815  return send_APDU(c, apdu);
816 }
817 
819 {
820  ZOOM_scanset scan;
822  Z_ScanRequest *req = apdu->u.scanRequest;
823  Z_Query *z_query;
824 
825  yaz_log(c->log_details, "%p send_scan", c);
826  if (!c->tasks)
827  return zoom_complete;
828  assert (c->tasks->which == ZOOM_TASK_SCAN);
829  scan = c->tasks->u.scan.scan;
830 
831  z_query = ZOOM_query_get_Z_Query(scan->query);
832 
833  /* Z39.50 scan can only carry RPN */
834  if (z_query->which == Z_Query_type_1 ||
835  z_query->which == Z_Query_type_101)
836  {
837  Z_RPNQuery *rpn = z_query->u.type_1;
838  const char *cp = ZOOM_options_get(scan->options, "rpnCharset");
839  if (cp)
840  {
841  yaz_iconv_t cd = yaz_iconv_open(cp, "UTF-8");
842  if (cd)
843  {
844  rpn = yaz_copy_z_RPNQuery(rpn, c->odr_out);
845 
847  rpn, c->odr_out, cd);
848  yaz_iconv_close(cd);
849  }
850  }
851  req->attributeSet = rpn->attributeSetId;
852  if (!req->attributeSet)
856  {
857  req->termListAndStartPoint =
859  }
860  else
861  {
863  return zoom_complete;
864  }
865  }
866  else
867  {
869  return zoom_complete;
870  }
871 
872  *req->numberOfTermsRequested =
873  ZOOM_options_get_int(scan->options, "number", 20);
874 
876  odr_intdup(c->odr_out,
877  ZOOM_options_get_int(scan->options, "position", 1));
878 
879  req->stepSize =
880  odr_intdup(c->odr_out,
881  ZOOM_options_get_int(scan->options, "stepSize", 0));
882 
883  req->databaseNames = scan->databaseNames;
885 
886  return send_APDU(c, apdu);
887 }
888 
889 ZOOM_API(void)
891 {
892  Z_APDU *apdu = 0;
893  ZOOM_connection c;
894  if (!p)
895  return;
896  c = p->connection;
897  odr_reset(p->odr_out);
898  xfree(p->buf_out);
899  p->buf_out = 0;
900  if (!strcmp(type, "itemorder"))
901  {
903  if (apdu)
904  {
905  Z_External *r = (Z_External *) odr_malloc(p->odr_out, sizeof(*r));
906 
907  r->direct_reference =
909  r->descriptor = 0;
911  r->indirect_reference = 0;
912  r->u.itemOrder = encode_item_order(p);
913 
915  }
916  }
917  else if (!strcmp(type, "create")) /* create database */
918  {
920  0, 0);
921  }
922  else if (!strcmp(type, "drop")) /* drop database */
923  {
925  0, 0);
926  }
927  else if (!strcmp(type, "commit")) /* commit changes */
928  {
930  0, 0);
931  }
932  else if (!strcmp(type, "update")) /* update record(s) */
933  {
934  apdu = create_update_package(p);
935  }
936  else if (!strcmp(type, "xmlupdate"))
937  {
938  apdu = create_xmlupdate_package(p);
939  }
940  if (apdu)
941  {
942  if (encode_APDU(p->connection, apdu, p->odr_out) == 0)
943  {
944  char *buf;
945 
947  task->u.package = p;
948  buf = odr_getbuf(p->odr_out, &p->len_out, 0);
949  p->buf_out = (char *) xmalloc(p->len_out);
950  memcpy(p->buf_out, buf, p->len_out);
951 
952  (p->refcount)++;
953  if (!c->async)
954  {
955  while (ZOOM_event(1, &c))
956  ;
957  }
958  }
959  }
960 }
961 
963  int present_phase);
964 
966 {
967  char oid_name_buf[OID_STR_MAX];
968  const char *oid_name;
969  char *addinfo = 0;
970 
971  oid_name = yaz_oid_to_string_buf(r->diagnosticSetId, 0, oid_name_buf);
972  switch (r->which)
973  {
975  addinfo = r->u.v2Addinfo;
976  break;
978  addinfo = r->u.v3Addinfo;
979  break;
980  }
981  xfree(c->addinfo);
982  c->addinfo = 0;
983  ZOOM_set_dset_error(c, *r->condition, oid_name, addinfo, 0);
984 }
985 
987 {
988  if (p->which != Z_DiagRec_defaultFormat)
990  else
992 }
993 
996 {
997  if (utp && utp->targetPart)
998  {
999  Z_IUTargetPart *targetPart = utp->targetPart;
1000  switch ( *targetPart->updateStatus ) {
1002  ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "success");
1003  break;
1005  ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "partial");
1006  break;
1008  ZOOM_options_set(c->tasks->u.package->options,"updateStatus", "failure");
1009  if (targetPart->globalDiagnostics && targetPart->num_globalDiagnostics > 0)
1010  response_diag(c, targetPart->globalDiagnostics[0]);
1011  break;
1012  }
1013  /* NOTE: Individual record status, surrogate diagnostics, and supplemental diagnostics ARE NOT REPORTED. */
1014  }
1015  return 1;
1016 }
1017 
1019  Z_TaskPackage *taskPackage)
1020 {
1021  Odr_oct *id = taskPackage->targetReference;
1022  if (id)
1024  "targetReference", (char*) id->buf, id->len);
1025 
1026  switch ( *taskPackage->taskStatus ) {
1027  case Z_TaskPackage_pending:
1028  ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "pending");
1029  break;
1030  case Z_TaskPackage_active:
1031  ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "active");
1032  break;
1034  ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "complete");
1035  break;
1036  case Z_TaskPackage_aborted:
1037  ZOOM_options_set(c->tasks->u.package->options,"taskStatus", "aborted");
1038  if ( taskPackage->num_packageDiagnostics && taskPackage->packageDiagnostics )
1039  response_diag(c, taskPackage->packageDiagnostics[0]);
1040  break;
1041  }
1042  /* NOTE: Only Update implemented, no others. */
1043  if ( taskPackage->taskSpecificParameters->which == Z_External_update )
1044  {
1047  }
1048  return 1;
1049 }
1050 
1051 
1054 {
1055  if (!c->tasks || c->tasks->which != ZOOM_TASK_PACKAGE)
1056  return 0;
1057  switch (*res->operationStatus)
1058  {
1060  ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "done");
1061  break;
1063  ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "accepted");
1064  break;
1066  ZOOM_options_set(c->tasks->u.package->options,"operationStatus", "failure");
1067  if (res->diagnostics && res->num_diagnostics > 0)
1068  response_diag(c, res->diagnostics[0]);
1069  break;
1070  }
1071  if (res->taskPackage &&
1073  {
1074  Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
1075  es_response_taskpackage(c, taskPackage);
1076  }
1077  if (res->taskPackage &&
1079  {
1080  Odr_oct *doc = res->taskPackage->u.octet_aligned;
1082  "xmlUpdateDoc", (char*) doc->buf, doc->len);
1083  }
1084  return 1;
1085 }
1086 
1087 static char *get_term_cstr(ODR odr, Z_Term *term) {
1088 
1089  switch (term->which) {
1090  case Z_Term_general:
1091  return odr_strdupn(odr, (const char *) term->u.general->buf, (size_t) term->u.general->len);
1092  break;
1094  return odr_strdup(odr, term->u.characterString);
1095  }
1096  return 0;
1097 }
1098 
1100  int term_index;
1101  struct yaz_facet_attr attr_values;
1102  ZOOM_facet_field facet_field = odr_malloc(odr, sizeof(*facet_field));
1103  yaz_facet_attr_init(&attr_values);
1104  yaz_facet_attr_get_z_attributes(facet->attributes, &attr_values);
1105  facet_field->facet_name = odr_strdup(odr, attr_values.useattr);
1106  facet_field->num_terms = facet->num_terms;
1107  yaz_log(YLOG_DEBUG, "ZOOM_facet_field %s %d terms %d", attr_values.useattr, attr_values.limit, facet->num_terms);
1108  facet_field->facet_terms = odr_malloc(odr, facet_field->num_terms * sizeof(*facet_field->facet_terms));
1109  for (term_index = 0 ; term_index < facet->num_terms; term_index++) {
1110  Z_FacetTerm *facetTerm = facet->terms[term_index];
1111  facet_field->facet_terms[term_index].frequency = *facetTerm->count;
1112  facet_field->facet_terms[term_index].term = get_term_cstr(odr, facetTerm->term);
1113  yaz_log(YLOG_DEBUG, " term[%d] %s %d",
1114  term_index, facet_field->facet_terms[term_index].term, facet_field->facet_terms[term_index].frequency);
1115  }
1116  return facet_field;
1117 }
1118 
1119 /* Can be share with SOLR/SRU/SRW requests */
1121 {
1122  int j;
1123  r->num_facets = fl->num;
1124  yaz_log(YLOG_DEBUG, "Facets found: %d", fl->num);
1125  r->facets = odr_malloc(r->odr, r->num_facets * sizeof(*r->facets));
1126  r->facets_names = odr_malloc(r->odr, r->num_facets * sizeof(*r->facets_names));
1127  for (j = 0; j < fl->num; j++)
1128  {
1129  r->facets[j] = get_zoom_facet_field(r->odr, fl->elements[j]);
1130  if (!r->facets[j])
1131  yaz_log(YLOG_DEBUG, "Facet field missing on index %d !", j);
1132  r->facets_names[j] = (char *) ZOOM_facet_field_name(r->facets[j]);
1133  }
1134 }
1135 
1137  Z_OtherInformation *o)
1138 {
1139  int i;
1140  for (i = 0; o && i < o->num_elements; i++)
1141  {
1143  {
1145  if (ext->which == Z_External_userFacets)
1146  {
1148  }
1149  }
1150  }
1151 }
1152 
1154  Z_Term *term)
1155 {
1156  switch (term->which)
1157  {
1158  case Z_Term_general:
1159  ZOOM_options_setl(opt, name,
1160  (const char *)(term->u.general->buf),
1161  term->u.general->len);
1162  break;
1164  ZOOM_options_set(opt, name, term->u.characterString);
1165  break;
1166  case Z_Term_numeric:
1167  ZOOM_options_set_int(opt, name, *term->u.numeric);
1168  break;
1169  }
1170 }
1171 
1172 static void handle_queryExpression(ZOOM_options opt, const char *name,
1173  Z_QueryExpression *exp)
1174 {
1175  char opt_name[80];
1176 
1177  switch (exp->which)
1178  {
1180  if (exp->u.term && exp->u.term->queryTerm)
1181  {
1182  sprintf(opt_name, "%s.term", name);
1183  handle_queryExpressionTerm(opt, opt_name, exp->u.term->queryTerm);
1184  }
1185  break;
1187  break;
1188  }
1189 }
1190 
1191 
1193  Z_OtherInformation *o)
1194 {
1195  int i;
1196  for (i = 0; o && i < o->num_elements; i++)
1197  {
1199  {
1201 
1202  if (ext->which == Z_External_searchResult1)
1203  {
1204  int j;
1205  Z_SearchInfoReport *sr = ext->u.searchResult1;
1206 
1207  if (sr->num)
1209  resultset->options, "searchresult.size", sr->num);
1210 
1211  for (j = 0; j < sr->num; j++)
1212  {
1213  Z_SearchInfoReport_s *ent =
1214  ext->u.searchResult1->elements[j];
1215  char pref[80];
1216 
1217  sprintf(pref, "searchresult.%d", j);
1218 
1219  if (ent->subqueryId)
1220  {
1221  char opt_name[80];
1222  sprintf(opt_name, "%s.id", pref);
1223  ZOOM_options_set(resultset->options, opt_name,
1224  ent->subqueryId);
1225  }
1226  if (ent->subqueryExpression)
1227  {
1228  char opt_name[80];
1229  sprintf(opt_name, "%s.subquery", pref);
1230  handle_queryExpression(resultset->options, opt_name,
1231  ent->subqueryExpression);
1232  }
1233  if (ent->subqueryInterpretation)
1234  {
1235  char opt_name[80];
1236  sprintf(opt_name, "%s.interpretation", pref);
1237  handle_queryExpression(resultset->options, opt_name,
1238  ent->subqueryInterpretation);
1239  }
1240  if (ent->subqueryRecommendation)
1241  {
1242  char opt_name[80];
1243  sprintf(opt_name, "%s.recommendation", pref);
1244  handle_queryExpression(resultset->options, opt_name,
1245  ent->subqueryRecommendation);
1246  }
1247  if (ent->subqueryCount)
1248  {
1249  char opt_name[80];
1250  sprintf(opt_name, "%s.count", pref);
1251  ZOOM_options_set_int(resultset->options, opt_name,
1252  *ent->subqueryCount);
1253  }
1254  }
1255  }
1256  }
1257  }
1258 }
1259 
1261  Z_SearchResponse *sr)
1262 {
1263  ZOOM_resultset resultset;
1264  ZOOM_Event event;
1265 
1266  if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH)
1267  return ;
1268 
1270  ZOOM_connection_put_event(c, event);
1271 
1272  resultset = c->tasks->u.search.resultset;
1273 
1274  if (sr->resultSetStatus)
1275  {
1276  ZOOM_options_set_int(resultset->options, "resultSetStatus",
1277  *sr->resultSetStatus);
1278  }
1279  if (sr->presentStatus)
1280  {
1281  ZOOM_options_set_int(resultset->options, "presentStatus",
1282  *sr->presentStatus);
1283  }
1284  handle_search_result(c, resultset, sr->additionalSearchInfo);
1285 
1286  handle_facet_result(c, resultset, sr->additionalSearchInfo);
1287 
1288  resultset->size = *sr->resultCount;
1289  handle_Z3950_records(c, sr->records, 0);
1290 }
1291 
1293 {
1294  if (res->diagnostics && res->num_diagnostics > 0)
1295  response_diag(c, res->diagnostics[0]);
1296 }
1297 
1299 {
1300  NMEM nmem = odr_extract_mem(c->odr_in);
1301  ZOOM_scanset scan;
1302 
1303  if (!c->tasks || c->tasks->which != ZOOM_TASK_SCAN)
1304  return 0;
1305  scan = c->tasks->u.scan.scan;
1306 
1307  if (res->entries && res->entries->nonsurrogateDiagnostics)
1309  scan->scan_response = res;
1310  scan->srw_scan_response = 0;
1311  nmem_transfer(odr_getmem(scan->odr), nmem);
1312  if (res->stepSize)
1313  ZOOM_options_set_int(scan->options, "stepSize", *res->stepSize);
1314  if (res->positionOfTerm)
1315  ZOOM_options_set_int(scan->options, "position", *res->positionOfTerm);
1316  if (res->scanStatus)
1317  ZOOM_options_set_int(scan->options, "scanStatus", *res->scanStatus);
1318  if (res->numberOfEntriesReturned)
1319  ZOOM_options_set_int(scan->options, "number",
1320  *res->numberOfEntriesReturned);
1321  nmem_destroy(nmem);
1322  return 1;
1323 }
1324 
1326  int present_phase)
1327 {
1328  ZOOM_resultset resultset;
1329  int *start, *count;
1330  const char *syntax = 0, *elementSetName = 0;
1331 
1332  if (!c->tasks)
1333  return ;
1334  switch (c->tasks->which)
1335  {
1336  case ZOOM_TASK_SEARCH:
1337  resultset = c->tasks->u.search.resultset;
1338  start = &c->tasks->u.search.start;
1339  count = &c->tasks->u.search.count;
1340  syntax = c->tasks->u.search.syntax;
1341  elementSetName = c->tasks->u.search.elementSetName;
1342  break;
1343  case ZOOM_TASK_RETRIEVE:
1344  resultset = c->tasks->u.retrieve.resultset;
1345  start = &c->tasks->u.retrieve.start;
1346  count = &c->tasks->u.retrieve.count;
1347  syntax = c->tasks->u.retrieve.syntax;
1348  elementSetName = c->tasks->u.retrieve.elementSetName;
1349  break;
1350  default:
1351  return;
1352  }
1353  if (sr && sr->which == Z_Records_NSD)
1355  else if (sr && sr->which == Z_Records_multipleNSD)
1356  {
1359  else
1361  }
1362  else
1363  {
1364  if (*count + *start > resultset->size)
1365  *count = resultset->size - *start;
1366  if (*count < 0)
1367  *count = 0;
1368  if (sr && sr->which == Z_Records_DBOSD)
1369  {
1370  int i;
1371  NMEM nmem = odr_extract_mem(c->odr_in);
1374  for (i = 0; i<p->num_records; i++)
1375  {
1376  ZOOM_record_cache_add(resultset, p->records[i], i + *start,
1377  syntax, elementSetName,
1378  elementSetName, 0);
1379  }
1380  *count -= i;
1381  if (*count < 0)
1382  *count = 0;
1383  *start += i;
1384  yaz_log(c->log_details,
1385  "handle_records resultset=%p start=%d count=%d",
1386  resultset, *start, *count);
1387 
1388  /* transfer our response to search_nmem .. we need it later */
1389  nmem_transfer(odr_getmem(resultset->odr), nmem);
1390  nmem_destroy(nmem);
1391  if (present_phase && p->num_records == 0)
1392  {
1393  /* present response and we didn't get any records! */
1394  Z_NamePlusRecord *myrec =
1396  resultset->odr, 0,
1398  "ZOOM C generated. Present phase and no records");
1399  ZOOM_record_cache_add(resultset, myrec, *start,
1400  syntax, elementSetName, 0, 0);
1401  }
1402  }
1403  else if (present_phase)
1404  {
1405  /* present response and we didn't get any records! */
1406  Z_NamePlusRecord *myrec =
1408  resultset->odr, 0,
1410  "ZOOM C generated: Present response and no records");
1411  ZOOM_record_cache_add(resultset, myrec, *start,
1412  syntax, elementSetName, 0, 0);
1413  }
1414  }
1415 }
1416 
1418  Z_PresentResponse *pr)
1419 {
1420  handle_Z3950_records(c, pr->records, 1);
1421 }
1422 
1423 static void set_init_option(const char *name, void *clientData)
1424 {
1425  ZOOM_connection c = (ZOOM_connection) clientData;
1426  char buf[80];
1427 
1428  sprintf(buf, "init_opt_%.70s", name);
1429  ZOOM_connection_option_set(c, buf, "1");
1430 }
1431 
1432 
1434 {
1435  if (c->error)
1436  resultset->r_sort_spec = 0;
1437  if (resultset->r_sort_spec)
1438  {
1440  Z_SortRequest *req = apdu->u.sortRequest;
1441 
1442  req->num_inputResultSetNames = 1;
1444  odr_malloc(c->odr_out, sizeof(*req->inputResultSetNames));
1445  req->inputResultSetNames[0] =
1446  odr_strdup(c->odr_out, resultset->setname);
1447  req->sortedResultSetName = odr_strdup(c->odr_out, resultset->setname);
1448  req->sortSequence = resultset->r_sort_spec;
1449  resultset->r_sort_spec = 0;
1450  return send_APDU(c, apdu);
1451  }
1452  return zoom_complete;
1453 }
1454 
1456 {
1457  Z_APDU *apdu = 0;
1458  Z_PresentRequest *req = 0;
1459  int i = 0;
1460  const char *syntax = 0;
1461  const char *elementSetName = 0;
1462  ZOOM_resultset resultset;
1463  int *start, *count;
1464 
1465  if (!c->tasks)
1466  {
1467  yaz_log(c->log_details, "%p send_present no tasks", c);
1468  return zoom_complete;
1469  }
1470 
1471  switch (c->tasks->which)
1472  {
1473  case ZOOM_TASK_SEARCH:
1474  resultset = c->tasks->u.search.resultset;
1475  start = &c->tasks->u.search.start;
1476  count = &c->tasks->u.search.count;
1477  syntax = c->tasks->u.search.syntax;
1478  elementSetName = c->tasks->u.search.elementSetName;
1479  break;
1480  case ZOOM_TASK_RETRIEVE:
1481  resultset = c->tasks->u.retrieve.resultset;
1482  start = &c->tasks->u.retrieve.start;
1483  count = &c->tasks->u.retrieve.count;
1484  syntax = c->tasks->u.retrieve.syntax;
1485  elementSetName = c->tasks->u.retrieve.elementSetName;
1486  break;
1487  default:
1488  return zoom_complete;
1489  }
1490  yaz_log(c->log_details, "%p send_present start=%d count=%d",
1491  c, *start, *count);
1492 
1493  if (*start < 0 || *count < 0 || *start + *count > resultset->size)
1494  {
1496  "", 0);
1497  }
1498  if (c->error) /* don't continue on error */
1499  return zoom_complete;
1500  yaz_log(c->log_details, "send_present resultset=%p start=%d count=%d",
1501  resultset, *start, *count);
1502 
1503  for (i = 0; i < *count; i++)
1504  {
1505  ZOOM_record rec =
1506  ZOOM_record_cache_lookup(resultset, i + *start,
1507  syntax, elementSetName);
1508  if (!rec)
1509  break;
1510  else
1511  {
1513  ZOOM_connection_put_event(c, event);
1514  }
1515  }
1516  *start += i;
1517  *count -= i;
1518 
1519  if (*count == 0)
1520  {
1521  yaz_log(c->log_details, "%p send_present skip=%d no more to fetch", c, i);
1522  return zoom_complete;
1523  }
1524 
1526  req = apdu->u.presentRequest;
1527 
1528  if (i)
1529  yaz_log(c->log_details, "%p send_present skip=%d", c, i);
1530 
1531  *req->resultSetStartPoint = *start + 1;
1532 
1533  if (resultset->step > 0 && resultset->step < *count)
1534  *req->numberOfRecordsRequested = resultset->step;
1535  else
1536  *req->numberOfRecordsRequested = *count;
1537 
1538  if (*req->numberOfRecordsRequested + *start > resultset->size)
1539  *req->numberOfRecordsRequested = resultset->size - *start;
1540  assert(*req->numberOfRecordsRequested > 0);
1541 
1542  if (syntax && *syntax)
1543  req->preferredRecordSyntax =
1545 
1546  if (resultset->schema && *resultset->schema)
1547  {
1549  odr_malloc(c->odr_out, sizeof(*compo));
1550 
1551  req->recordComposition = compo;
1552  compo->which = Z_RecordComp_complex;
1553  compo->u.complex = (Z_CompSpec *)
1554  odr_malloc(c->odr_out, sizeof(*compo->u.complex));
1555  compo->u.complex->selectAlternativeSyntax = (bool_t *)
1556  odr_malloc(c->odr_out, sizeof(bool_t));
1557  *compo->u.complex->selectAlternativeSyntax = 0;
1558 
1559  compo->u.complex->generic = (Z_Specification *)
1560  odr_malloc(c->odr_out, sizeof(*compo->u.complex->generic));
1561 
1562  compo->u.complex->generic->which = Z_Schema_oid;
1563  compo->u.complex->generic->schema.oid = (Odr_oid *)
1564  zoom_yaz_str_to_z3950oid (c, CLASS_SCHEMA, resultset->schema);
1565 
1566  if (!compo->u.complex->generic->schema.oid)
1567  {
1568  /* OID wasn't a schema! Try record syntax instead. */
1569 
1570  compo->u.complex->generic->schema.oid = (Odr_oid *)
1571  zoom_yaz_str_to_z3950oid (c, CLASS_RECSYN, resultset->schema);
1572  }
1573  if (elementSetName && *elementSetName)
1574  {
1575  compo->u.complex->generic->elementSpec = (Z_ElementSpec *)
1576  odr_malloc(c->odr_out, sizeof(Z_ElementSpec));
1577  compo->u.complex->generic->elementSpec->which =
1580  odr_strdup(c->odr_out, elementSetName);
1581  }
1582  else
1583  compo->u.complex->generic->elementSpec = 0;
1584  compo->u.complex->num_dbSpecific = 0;
1585  compo->u.complex->dbSpecific = 0;
1586  compo->u.complex->num_recordSyntax = 0;
1587  compo->u.complex->recordSyntax = 0;
1588  }
1589  else if (elementSetName && *elementSetName)
1590  {
1592  odr_malloc(c->odr_out, sizeof(*esn));
1594  odr_malloc(c->odr_out, sizeof(*compo));
1595 
1597  esn->u.generic = odr_strdup(c->odr_out, elementSetName);
1598  compo->which = Z_RecordComp_simple;
1599  compo->u.simple = esn;
1600  req->recordComposition = compo;
1601  }
1602  req->resultSetId = odr_strdup(c->odr_out, resultset->setname);
1603  return send_APDU(c, apdu);
1604 }
1605 
1607 {
1608  zoom_ret r = zoom_complete;
1609 
1610  if (c->tasks && c->tasks->which == ZOOM_TASK_SEARCH)
1611  r = send_Z3950_sort(c, c->tasks->u.search.resultset);
1612  if (r == zoom_complete)
1613  r = send_Z3950_present(c);
1614  return r;
1615 }
1616 
1618 {
1619  Z_InitResponse *initrs;
1620 
1622  yaz_log(c->log_details, "%p handle_Z3950_apdu apdu->which=%d",
1623  c, apdu->which);
1624  switch (apdu->which)
1625  {
1626  case Z_APDU_initResponse:
1627  yaz_log(c->log_api, "%p handle_Z3950_apdu: Received Init response", c);
1628  initrs = apdu->u.initResponse;
1629  ZOOM_connection_option_set(c, "serverImplementationId",
1630  initrs->implementationId ?
1631  initrs->implementationId : "");
1632  ZOOM_connection_option_set(c, "serverImplementationName",
1633  initrs->implementationName ?
1634  initrs->implementationName : "");
1635  ZOOM_connection_option_set(c, "serverImplementationVersion",
1636  initrs->implementationVersion ?
1637  initrs->implementationVersion : "");
1638  /* Set the three old options too, for old applications */
1639  ZOOM_connection_option_set(c, "targetImplementationId",
1640  initrs->implementationId ?
1641  initrs->implementationId : "");
1642  ZOOM_connection_option_set(c, "targetImplementationName",
1643  initrs->implementationName ?
1644  initrs->implementationName : "");
1645  ZOOM_connection_option_set(c, "targetImplementationVersion",
1646  initrs->implementationVersion ?
1647  initrs->implementationVersion : "");
1648 
1649  /* Make initrs->options available as ZOOM-level options */
1650  yaz_init_opt_decode(initrs->options, set_init_option, (void*) c);
1651 
1652  if (!*initrs->result)
1653  {
1654  Z_DefaultDiagFormat *df = yaz_decode_init_diag(0, initrs);
1655  if (df)
1656  response_default_diag(c, df);
1657  else
1658  ZOOM_set_error(c, ZOOM_ERROR_INIT, 0); /* default error */
1659  }
1660  else
1661  {
1662  char *cookie =
1664  yaz_oid_userinfo_cookie, 1, 0);
1665  xfree(c->cookie_in);
1666  c->cookie_in = 0;
1667  if (cookie)
1668  c->cookie_in = xstrdup(cookie);
1671  c->support_named_resultsets = 1;
1672  if (c->tasks)
1673  {
1674  assert(c->tasks->which == ZOOM_TASK_CONNECT);
1676  }
1678  }
1680  {
1681  NMEM tmpmem = nmem_create();
1684 
1685  if (p)
1686  {
1687  char *charset = NULL, *lang = NULL;
1688  int sel;
1689 
1690  yaz_get_response_charneg(tmpmem, p, &charset, &lang, &sel);
1691  yaz_log(c->log_details, "%p handle_Z3950_apdu target accepted: "
1692  "charset %s, language %s, select %d",
1693  c,
1694  charset ? charset : "none", lang ? lang : "none", sel);
1695  if (charset)
1696  ZOOM_connection_option_set(c, "negotiation-charset",
1697  charset);
1698  if (lang)
1699  ZOOM_connection_option_set(c, "negotiation-lang",
1700  lang);
1701 
1703  c, "negotiation-charset-in-effect-for-records",
1704  (sel != 0) ? "1" : "0");
1705  nmem_destroy(tmpmem);
1706  }
1707  }
1708  break;
1709  case Z_APDU_searchResponse:
1710  yaz_log(c->log_api, "%p handle_Z3950_apdu Search response", c);
1714  break;
1716  yaz_log(c->log_api, "%p handle_Z3950_apdu Present response", c);
1720  break;
1721  case Z_APDU_sortResponse:
1722  yaz_log(c->log_api, "%p handle_Z3950_apdu Sort response", c);
1726  break;
1727  case Z_APDU_scanResponse:
1728  yaz_log(c->log_api, "%p handle_Z3950_apdu Scan response", c);
1731  break;
1733  yaz_log(c->log_api, "%p handle_Z3950_apdu Extended Services response", c);
1736  break;
1737  case Z_APDU_close:
1738  yaz_log(c->log_api, "%p handle_Z3950_apdu Close PDU", c);
1739  if (!ZOOM_test_reconnect(c))
1740  {
1743  }
1744  break;
1745  default:
1746  yaz_log(c->log_api, "%p Received unknown PDU", c);
1749  }
1750 }
1751 
1752 /*
1753  * Local variables:
1754  * c-basic-offset: 4
1755  * c-file-style: "Stroustrup"
1756  * indent-tabs-mode: nil
1757  * End:
1758  * vim: shiftwidth=4 tabstop=8 expandtab
1759  */
1760