00001
00002
00003
00004
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <assert.h>
00032 #include <ctype.h>
00033
00034 #if HAVE_SYS_TYPES_H
00035 #include <sys/types.h>
00036 #endif
00037 #if HAVE_SYS_STAT_H
00038 #include <sys/stat.h>
00039 #endif
00040
00041 #ifdef WIN32
00042 #include <io.h>
00043 #define S_ISREG(x) (x & _S_IFREG)
00044 #include <process.h>
00045 #endif
00046
00047 #if HAVE_UNISTD_H
00048 #include <unistd.h>
00049 #endif
00050
00051 #if YAZ_HAVE_XML2
00052 #include <libxml/parser.h>
00053 #include <libxml/tree.h>
00054 #endif
00055
00056 #include <yaz/yconfig.h>
00057 #include <yaz/xmalloc.h>
00058 #include <yaz/comstack.h>
00059 #include "eventl.h"
00060 #include "session.h"
00061 #include "mime.h"
00062 #include <yaz/proto.h>
00063 #include <yaz/oid_db.h>
00064 #include <yaz/log.h>
00065 #include <yaz/logrpn.h>
00066 #include <yaz/querytowrbuf.h>
00067 #include <yaz/statserv.h>
00068 #include <yaz/diagbib1.h>
00069 #include <yaz/charneg.h>
00070 #include <yaz/otherinfo.h>
00071 #include <yaz/yaz-util.h>
00072 #include <yaz/pquery.h>
00073 #include <yaz/oid_db.h>
00074
00075 #include <yaz/srw.h>
00076 #include <yaz/backend.h>
00077 #include <yaz/yaz-ccl.h>
00078
00079 static void process_gdu_request(association *assoc, request *req);
00080 static int process_z_request(association *assoc, request *req, char **msg);
00081 void backend_response(IOCHAN i, int event);
00082 static int process_gdu_response(association *assoc, request *req, Z_GDU *res);
00083 static int process_z_response(association *assoc, request *req, Z_APDU *res);
00084 static Z_APDU *process_initRequest(association *assoc, request *reqb);
00085 static Z_External *init_diagnostics(ODR odr, int errcode,
00086 const char *errstring);
00087 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
00088 int *fd);
00089 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
00090 bend_search_rr *bsrr, int *fd);
00091 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
00092 int *fd);
00093 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
00094 static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
00095 static void process_close(association *assoc, request *reqb);
00096 void save_referenceId(request *reqb, Z_ReferenceId *refid);
00097 static Z_APDU *process_deleteRequest(association *assoc, request *reqb,
00098 int *fd);
00099 static Z_APDU *process_segmentRequest(association *assoc, request *reqb);
00100
00101 static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd);
00102
00103
00104 static int logbits_set = 0;
00105 static int log_session = 0;
00106 static int log_sessiondetail = 0;
00107 static int log_request = 0;
00108 static int log_requestdetail = 0;
00109
00111 static void get_logbits(void)
00112 {
00113 if (!logbits_set)
00114 {
00115 logbits_set = 1;
00116 log_session = yaz_log_module_level("session");
00117 log_sessiondetail = yaz_log_module_level("sessiondetail");
00118 log_request = yaz_log_module_level("request");
00119 log_requestdetail = yaz_log_module_level("requestdetail");
00120 }
00121 }
00122
00123
00124
00125 static void wr_diag(WRBUF w, int error, const char *addinfo)
00126 {
00127 wrbuf_printf(w, "ERROR %d+", error);
00128 wrbuf_puts_replace_char(w, diagbib1_str(error), ' ', '_');
00129 if (addinfo){
00130 wrbuf_puts(w, "+");
00131 wrbuf_puts_replace_char(w, addinfo, ' ', '_');
00132 }
00133
00134 wrbuf_puts(w, " ");
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144 association *create_association(IOCHAN channel, COMSTACK link,
00145 const char *apdufile)
00146 {
00147 association *anew;
00148
00149 if (!logbits_set)
00150 get_logbits();
00151 if (!(anew = (association *)xmalloc(sizeof(*anew))))
00152 return 0;
00153 anew->init = 0;
00154 anew->version = 0;
00155 anew->last_control = 0;
00156 anew->client_chan = channel;
00157 anew->client_link = link;
00158 anew->cs_get_mask = 0;
00159 anew->cs_put_mask = 0;
00160 anew->cs_accept_mask = 0;
00161 if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
00162 !(anew->encode = odr_createmem(ODR_ENCODE)))
00163 return 0;
00164 if (apdufile && *apdufile)
00165 {
00166 FILE *f;
00167
00168 if (!(anew->print = odr_createmem(ODR_PRINT)))
00169 return 0;
00170 if (*apdufile == '@')
00171 {
00172 odr_setprint(anew->print, yaz_log_file());
00173 }
00174 else if (*apdufile != '-')
00175 {
00176 char filename[256];
00177 sprintf(filename, "%.200s.%ld", apdufile, (long)getpid());
00178 if (!(f = fopen(filename, "w")))
00179 {
00180 yaz_log(YLOG_WARN|YLOG_ERRNO, "%s", filename);
00181 return 0;
00182 }
00183 setvbuf(f, 0, _IONBF, 0);
00184 odr_setprint(anew->print, f);
00185 }
00186 }
00187 else
00188 anew->print = 0;
00189 anew->input_buffer = 0;
00190 anew->input_buffer_len = 0;
00191 anew->backend = 0;
00192 anew->state = ASSOC_NEW;
00193 request_initq(&anew->incoming);
00194 request_initq(&anew->outgoing);
00195 anew->proto = cs_getproto(link);
00196 anew->server = 0;
00197 return anew;
00198 }
00199
00200
00201
00202
00203 void destroy_association(association *h)
00204 {
00205 statserv_options_block *cb = statserv_getcontrol();
00206 request *req;
00207
00208 xfree(h->init);
00209 odr_destroy(h->decode);
00210 odr_destroy(h->encode);
00211 if (h->print)
00212 odr_destroy(h->print);
00213 if (h->input_buffer)
00214 xfree(h->input_buffer);
00215 if (h->backend)
00216 (*cb->bend_close)(h->backend);
00217 while ((req = request_deq(&h->incoming)))
00218 request_release(req);
00219 while ((req = request_deq(&h->outgoing)))
00220 request_release(req);
00221 request_delq(&h->incoming);
00222 request_delq(&h->outgoing);
00223 xfree(h);
00224 xmalloc_trav("session closed");
00225 if (cb && cb->one_shot)
00226 {
00227 exit(0);
00228 }
00229 }
00230
00231 static void do_close_req(association *a, int reason, char *message,
00232 request *req)
00233 {
00234 Z_APDU apdu;
00235 Z_Close *cls = zget_Close(a->encode);
00236
00237
00238 while (request_deq(&a->incoming));
00239 while (request_deq(&a->outgoing));
00240 if (a->version >= 3)
00241 {
00242 yaz_log(log_requestdetail, "Sending Close PDU, reason=%d, message=%s",
00243 reason, message ? message : "none");
00244 apdu.which = Z_APDU_close;
00245 apdu.u.close = cls;
00246 *cls->closeReason = reason;
00247 cls->diagnosticInformation = message;
00248 process_z_response(a, req, &apdu);
00249 iochan_settimeout(a->client_chan, 20);
00250 }
00251 else
00252 {
00253 request_release(req);
00254 yaz_log(log_requestdetail, "v2 client. No Close PDU");
00255 iochan_setevent(a->client_chan, EVENT_TIMEOUT);
00256 a->cs_put_mask = 0;
00257 }
00258 a->state = ASSOC_DEAD;
00259 }
00260
00261 static void do_close(association *a, int reason, char *message)
00262 {
00263 request *req = request_get(&a->outgoing);
00264 do_close_req (a, reason, message, req);
00265 }
00266
00267
00268 int ir_read(IOCHAN h, int event)
00269 {
00270 association *assoc = (association *)iochan_getdata(h);
00271 COMSTACK conn = assoc->client_link;
00272 request *req;
00273
00274 if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
00275 {
00276 yaz_log(YLOG_DEBUG, "ir_session (input)");
00277
00278 if (assoc->state == ASSOC_DEAD)
00279 {
00280 yaz_log(log_sessiondetail, "Connection closed - end of session");
00281 cs_close(conn);
00282 destroy_association(assoc);
00283 iochan_destroy(h);
00284 return 0;
00285 }
00286 assoc->cs_get_mask = EVENT_INPUT;
00287
00288 do
00289 {
00290 int res = cs_get(conn, &assoc->input_buffer,
00291 &assoc->input_buffer_len);
00292 if (res < 0 && cs_errno(conn) == CSBUFSIZE)
00293 {
00294 yaz_log(log_session, "Connection error: %s res=%d",
00295 cs_errmsg(cs_errno(conn)), res);
00296 req = request_get(&assoc->incoming);
00297 do_close_req(assoc, Z_Close_protocolError,
00298 "Incoming package too large", req);
00299 return 0;
00300 }
00301 else if (res <= 0)
00302 {
00303 yaz_log(log_session, "Connection closed by client");
00304 assoc->state = ASSOC_DEAD;
00305 return 0;
00306 }
00307 else if (res == 1)
00308 {
00309 if (conn->io_pending & CS_WANT_WRITE)
00310 assoc->cs_get_mask |= EVENT_OUTPUT;
00311 iochan_setflag(h, assoc->cs_get_mask);
00312 return 0;
00313 }
00314
00315 yaz_log(YLOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
00316 assoc->input_buffer[0] & 0xff,
00317 assoc->input_buffer[1] & 0xff,
00318 assoc->input_buffer[2] & 0xff);
00319 req = request_get(&assoc->incoming);
00320 odr_reset(assoc->decode);
00321 odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
00322 if (!z_GDU(assoc->decode, &req->gdu_request, 0, 0))
00323 {
00324 yaz_log(YLOG_WARN, "ODR error on incoming PDU: %s [element %s] "
00325 "[near byte %ld] ",
00326 odr_errmsg(odr_geterror(assoc->decode)),
00327 odr_getelement(assoc->decode),
00328 (long) odr_offset(assoc->decode));
00329 if (assoc->decode->error != OHTTP)
00330 {
00331 yaz_log(YLOG_WARN, "PDU dump:");
00332 odr_dumpBER(yaz_log_file(), assoc->input_buffer, res);
00333 request_release(req);
00334 do_close(assoc, Z_Close_protocolError, "Malformed package");
00335 }
00336 else
00337 {
00338 Z_GDU *p = z_get_HTTP_Response(assoc->encode, 400);
00339 assoc->state = ASSOC_DEAD;
00340 process_gdu_response(assoc, req, p);
00341 }
00342 return 0;
00343 }
00344 req->request_mem = odr_extract_mem(assoc->decode);
00345 if (assoc->print)
00346 {
00347 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
00348 yaz_log(YLOG_WARN, "ODR print error: %s",
00349 odr_errmsg(odr_geterror(assoc->print)));
00350 odr_reset(assoc->print);
00351 }
00352 request_enq(&assoc->incoming, req);
00353 }
00354 while (cs_more(conn));
00355 }
00356 return 1;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 void ir_session(IOCHAN h, int event)
00369 {
00370 int res;
00371 association *assoc = (association *)iochan_getdata(h);
00372 COMSTACK conn = assoc->client_link;
00373 request *req;
00374
00375 assert(h && conn && assoc);
00376 if (event == EVENT_TIMEOUT)
00377 {
00378 if (assoc->state != ASSOC_UP)
00379 {
00380 yaz_log(YLOG_DEBUG, "Final timeout - closing connection.");
00381
00382 cs_close(conn);
00383 destroy_association(assoc);
00384 iochan_destroy(h);
00385 }
00386 else
00387 {
00388 yaz_log(log_sessiondetail,
00389 "Session idle too long. Sending close.");
00390 do_close(assoc, Z_Close_lackOfActivity, 0);
00391 }
00392 return;
00393 }
00394 if (event & assoc->cs_accept_mask)
00395 {
00396 if (!cs_accept(conn))
00397 {
00398 yaz_log(YLOG_WARN, "accept failed");
00399 destroy_association(assoc);
00400 iochan_destroy(h);
00401 return;
00402 }
00403 iochan_clearflag(h, EVENT_OUTPUT);
00404 if (conn->io_pending)
00405 {
00406 assoc->cs_accept_mask =
00407 ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
00408 ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
00409
00410 iochan_setflag(h, assoc->cs_accept_mask);
00411 }
00412 else
00413 {
00414 assoc->cs_accept_mask = 0;
00415 assoc->cs_get_mask = EVENT_INPUT;
00416 iochan_setflag(h, assoc->cs_get_mask);
00417 }
00418 return;
00419 }
00420 if (event & assoc->cs_get_mask)
00421 {
00422 if (!ir_read(h, event))
00423 return;
00424 req = request_head(&assoc->incoming);
00425 if (req->state == REQUEST_IDLE)
00426 {
00427 request_deq(&assoc->incoming);
00428 process_gdu_request(assoc, req);
00429 }
00430 }
00431 if (event & assoc->cs_put_mask)
00432 {
00433 request *req = request_head(&assoc->outgoing);
00434
00435 assoc->cs_put_mask = 0;
00436 yaz_log(YLOG_DEBUG, "ir_session (output)");
00437 req->state = REQUEST_PENDING;
00438 switch (res = cs_put(conn, req->response, req->len_response))
00439 {
00440 case -1:
00441 yaz_log(log_sessiondetail, "Connection closed by client");
00442 cs_close(conn);
00443 destroy_association(assoc);
00444 iochan_destroy(h);
00445 break;
00446 case 0:
00447 yaz_log(YLOG_DEBUG, "Wrote PDU, %d bytes", req->len_response);
00448 #if 0
00449 yaz_log(YLOG_DEBUG, "HTTP out:\n%.*s", req->len_response,
00450 req->response);
00451 #endif
00452 nmem_destroy(req->request_mem);
00453 request_deq(&assoc->outgoing);
00454 request_release(req);
00455 if (!request_head(&assoc->outgoing))
00456 {
00457 iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
00458 iochan_setflag(h, assoc->cs_get_mask);
00459 if (assoc->state == ASSOC_DEAD)
00460 iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
00461 }
00462 else
00463 {
00464 assoc->cs_put_mask = EVENT_OUTPUT;
00465 }
00466 break;
00467 default:
00468 if (conn->io_pending & CS_WANT_WRITE)
00469 assoc->cs_put_mask |= EVENT_OUTPUT;
00470 if (conn->io_pending & CS_WANT_READ)
00471 assoc->cs_put_mask |= EVENT_INPUT;
00472 iochan_setflag(h, assoc->cs_put_mask);
00473 }
00474 }
00475 if (event & EVENT_EXCEPT)
00476 {
00477 yaz_log(YLOG_WARN, "ir_session (exception)");
00478 cs_close(conn);
00479 destroy_association(assoc);
00480 iochan_destroy(h);
00481 }
00482 }
00483
00484 static int process_z_request(association *assoc, request *req, char **msg);
00485
00486
00487 static void assoc_init_reset(association *assoc)
00488 {
00489 xfree (assoc->init);
00490 assoc->init = (bend_initrequest *) xmalloc(sizeof(*assoc->init));
00491
00492 assoc->init->stream = assoc->encode;
00493 assoc->init->print = assoc->print;
00494 assoc->init->auth = 0;
00495 assoc->init->referenceId = 0;
00496 assoc->init->implementation_version = 0;
00497 assoc->init->implementation_id = 0;
00498 assoc->init->implementation_name = 0;
00499 assoc->init->query_charset = 0;
00500 assoc->init->records_in_same_charset = 0;
00501 assoc->init->bend_sort = NULL;
00502 assoc->init->bend_search = NULL;
00503 assoc->init->bend_present = NULL;
00504 assoc->init->bend_esrequest = NULL;
00505 assoc->init->bend_delete = NULL;
00506 assoc->init->bend_scan = NULL;
00507 assoc->init->bend_segment = NULL;
00508 assoc->init->bend_fetch = NULL;
00509 assoc->init->bend_explain = NULL;
00510 assoc->init->bend_srw_scan = NULL;
00511 assoc->init->bend_srw_update = NULL;
00512
00513 assoc->init->charneg_request = NULL;
00514 assoc->init->charneg_response = NULL;
00515
00516 assoc->init->decode = assoc->decode;
00517 assoc->init->peer_name =
00518 odr_strdup(assoc->encode, cs_addrstr(assoc->client_link));
00519
00520 yaz_log(log_requestdetail, "peer %s", assoc->init->peer_name);
00521 }
00522
00523 static int srw_bend_init(association *assoc, Z_SRW_diagnostic **d, int *num, Z_SRW_PDU *sr)
00524 {
00525 statserv_options_block *cb = statserv_getcontrol();
00526 if (!assoc->init)
00527 {
00528 const char *encoding = "UTF-8";
00529 Z_External *ce;
00530 bend_initresult *binitres;
00531
00532 yaz_log(log_requestdetail, "srw_bend_init config=%s", cb->configname);
00533 assoc_init_reset(assoc);
00534
00535 if (sr->username)
00536 {
00537 Z_IdAuthentication *auth = (Z_IdAuthentication *)
00538 odr_malloc(assoc->decode, sizeof(*auth));
00539 int len;
00540
00541 len = strlen(sr->username) + 1;
00542 if (sr->password)
00543 len += strlen(sr->password) + 2;
00544 auth->which = Z_IdAuthentication_open;
00545 auth->u.open = (char *) odr_malloc(assoc->decode, len);
00546 strcpy(auth->u.open, sr->username);
00547 if (sr->password && *sr->password)
00548 {
00549 strcat(auth->u.open, "/");
00550 strcat(auth->u.open, sr->password);
00551 }
00552 assoc->init->auth = auth;
00553 }
00554
00555 #if 1
00556 ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
00557 assoc->init->charneg_request = ce->u.charNeg3;
00558 #endif
00559 assoc->backend = 0;
00560 if (!(binitres = (*cb->bend_init)(assoc->init)))
00561 {
00562 assoc->state = ASSOC_DEAD;
00563 yaz_add_srw_diagnostic(assoc->encode, d, num,
00564 YAZ_SRW_AUTHENTICATION_ERROR, 0);
00565 return 0;
00566 }
00567 assoc->backend = binitres->handle;
00568 assoc->init->auth = 0;
00569 if (binitres->errcode)
00570 {
00571 int srw_code = yaz_diag_bib1_to_srw(binitres->errcode);
00572 assoc->state = ASSOC_DEAD;
00573 yaz_add_srw_diagnostic(assoc->encode, d, num, srw_code,
00574 binitres->errstring);
00575 return 0;
00576 }
00577 return 1;
00578 }
00579 return 1;
00580 }
00581
00582 static int retrieve_fetch(association *assoc, bend_fetch_rr *rr)
00583 {
00584 #if YAZ_HAVE_XML2
00585 yaz_record_conv_t rc = 0;
00586 const char *match_schema = 0;
00587 Odr_oid *match_syntax = 0;
00588
00589 if (assoc->server)
00590 {
00591 int r;
00592 const char *input_schema = yaz_get_esn(rr->comp);
00593 Odr_oid *input_syntax_raw = rr->request_format;
00594
00595 const char *backend_schema = 0;
00596 Odr_oid *backend_syntax = 0;
00597
00598 r = yaz_retrieval_request(assoc->server->retrieval,
00599 input_schema,
00600 input_syntax_raw,
00601 &match_schema,
00602 &match_syntax,
00603 &rc,
00604 &backend_schema,
00605 &backend_syntax);
00606 if (r == -1)
00607 {
00608 const char *details = yaz_retrieval_get_error(
00609 assoc->server->retrieval);
00610
00611 rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
00612 if (details)
00613 rr->errstring = odr_strdup(rr->stream, details);
00614 return -1;
00615 }
00616 else if (r == 1 || r == 3)
00617 {
00618 const char *details = input_schema;
00619 rr->errcode =
00620 YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
00621 if (details)
00622 rr->errstring = odr_strdup(rr->stream, details);
00623 return -1;
00624 }
00625 else if (r == 2)
00626 {
00627 rr->errcode = YAZ_BIB1_RECORD_SYNTAX_UNSUPP;
00628 if (input_syntax_raw)
00629 {
00630 char oidbuf[OID_STR_MAX];
00631 oid_oid_to_dotstring(input_syntax_raw, oidbuf);
00632 rr->errstring = odr_strdup(rr->stream, oidbuf);
00633 }
00634 return -1;
00635 }
00636 if (backend_schema)
00637 {
00638 yaz_set_esn(&rr->comp, backend_schema, odr_getmem(rr->stream));
00639 }
00640 if (backend_syntax)
00641 rr->request_format = backend_syntax;
00642 }
00643 (*assoc->init->bend_fetch)(assoc->backend, rr);
00644 if (rc && rr->record && rr->errcode == 0 && rr->len > 0)
00645 {
00646 WRBUF output_record = wrbuf_alloc();
00647 int r = yaz_record_conv_record(rc, rr->record, rr->len, output_record);
00648 if (r)
00649 {
00650 const char *details = yaz_record_conv_get_error(rc);
00651 rr->errcode = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
00652 if (details)
00653 rr->errstring = odr_strdup(rr->stream, details);
00654 }
00655 else
00656 {
00657 rr->len = wrbuf_len(output_record);
00658 rr->record = (char *) odr_malloc(rr->stream, rr->len);
00659 memcpy(rr->record, wrbuf_buf(output_record), rr->len);
00660 }
00661 wrbuf_destroy(output_record);
00662 }
00663 if (match_syntax)
00664 rr->output_format = match_syntax;
00665 if (match_schema)
00666 rr->schema = odr_strdup(rr->stream, match_schema);
00667 return 0;
00668 #else
00669 (*assoc->init->bend_fetch)(assoc->backend, rr);
00670 #endif
00671 return 0;
00672 }
00673
00674 static int srw_bend_fetch(association *assoc, int pos,
00675 Z_SRW_searchRetrieveRequest *srw_req,
00676 Z_SRW_record *record,
00677 const char **addinfo)
00678 {
00679 bend_fetch_rr rr;
00680 ODR o = assoc->encode;
00681
00682 rr.setname = "default";
00683 rr.number = pos;
00684 rr.referenceId = 0;
00685 rr.request_format = odr_oiddup(assoc->decode, yaz_oid_recsyn_xml);
00686
00687 rr.comp = (Z_RecordComposition *)
00688 odr_malloc(assoc->decode, sizeof(*rr.comp));
00689 rr.comp->which = Z_RecordComp_complex;
00690 rr.comp->u.complex = (Z_CompSpec *)
00691 odr_malloc(assoc->decode, sizeof(Z_CompSpec));
00692 rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
00693 odr_malloc(assoc->encode, sizeof(bool_t));
00694 *rr.comp->u.complex->selectAlternativeSyntax = 0;
00695 rr.comp->u.complex->num_dbSpecific = 0;
00696 rr.comp->u.complex->dbSpecific = 0;
00697 rr.comp->u.complex->num_recordSyntax = 0;
00698 rr.comp->u.complex->recordSyntax = 0;
00699
00700 rr.comp->u.complex->generic = (Z_Specification *)
00701 odr_malloc(assoc->decode, sizeof(Z_Specification));
00702
00703
00704 rr.comp->u.complex->generic->which = Z_Schema_uri;
00705 rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
00706
00707
00708 rr.comp->u.complex->generic->elementSpec = 0;
00709 if (srw_req->recordSchema)
00710 {
00711 rr.comp->u.complex->generic->elementSpec =
00712 (Z_ElementSpec *) odr_malloc(assoc->encode, sizeof(Z_ElementSpec));
00713 rr.comp->u.complex->generic->elementSpec->which =
00714 Z_ElementSpec_elementSetName;
00715 rr.comp->u.complex->generic->elementSpec->u.elementSetName =
00716 srw_req->recordSchema;
00717 }
00718
00719 rr.stream = assoc->encode;
00720 rr.print = assoc->print;
00721
00722 rr.basename = 0;
00723 rr.len = 0;
00724 rr.record = 0;
00725 rr.last_in_set = 0;
00726 rr.errcode = 0;
00727 rr.errstring = 0;
00728 rr.surrogate_flag = 0;
00729 rr.schema = srw_req->recordSchema;
00730
00731 if (!assoc->init->bend_fetch)
00732 return 1;
00733
00734 retrieve_fetch(assoc, &rr);
00735
00736 if (rr.errcode && rr.surrogate_flag)
00737 {
00738 int code = yaz_diag_bib1_to_srw(rr.errcode);
00739 yaz_mk_sru_surrogate(o, record, pos, code, rr.errstring);
00740 return 0;
00741 }
00742 else if (rr.len >= 0)
00743 {
00744 record->recordData_buf = rr.record;
00745 record->recordData_len = rr.len;
00746 record->recordPosition = odr_intdup(o, pos);
00747 record->recordSchema = odr_strdup_null(
00748 o, rr.schema ? rr.schema : srw_req->recordSchema);
00749 }
00750 if (rr.errcode)
00751 {
00752 *addinfo = rr.errstring;
00753 return rr.errcode;
00754 }
00755 return 0;
00756 }
00757
00758 static int cql2pqf(ODR odr, const char *cql, cql_transform_t ct,
00759 Z_Query *query_result)
00760 {
00761
00762 CQL_parser cp = cql_parser_create();
00763 int r;
00764 int srw_errcode = 0;
00765 const char *add = 0;
00766 char rpn_buf[5120];
00767
00768 r = cql_parser_string(cp, cql);
00769 if (r)
00770 {
00771 srw_errcode = YAZ_SRW_QUERY_SYNTAX_ERROR;
00772 }
00773 if (!r)
00774 {
00775
00776 r = cql_transform_buf(ct,
00777 cql_parser_result(cp),
00778 rpn_buf, sizeof(rpn_buf)-1);
00779 if (r)
00780 srw_errcode = cql_transform_error(ct, &add);
00781 }
00782 if (!r)
00783 {
00784
00785
00786 YAZ_PQF_Parser pp = yaz_pqf_create();
00787 Z_RPNQuery *rpnquery = yaz_pqf_parse(pp, odr, rpn_buf);
00788 if (!rpnquery)
00789 {
00790 size_t off;
00791 const char *pqf_msg;
00792 int code = yaz_pqf_error(pp, &pqf_msg, &off);
00793 yaz_log(YLOG_WARN, "PQF Parser Error %s (code %d)",
00794 pqf_msg, code);
00795 srw_errcode = YAZ_SRW_QUERY_SYNTAX_ERROR;
00796 }
00797 else
00798 {
00799 query_result->which = Z_Query_type_1;
00800 query_result->u.type_1 = rpnquery;
00801 }
00802 yaz_pqf_destroy(pp);
00803 }
00804 cql_parser_destroy(cp);
00805 return srw_errcode;
00806 }
00807
00808 static int cql2pqf_scan(ODR odr, const char *cql, cql_transform_t ct,
00809 Z_AttributesPlusTerm *result)
00810 {
00811 Z_Query query;
00812 Z_RPNQuery *rpn;
00813 int srw_error = cql2pqf(odr, cql, ct, &query);
00814 if (srw_error)
00815 return srw_error;
00816 if (query.which != Z_Query_type_1 && query.which != Z_Query_type_101)
00817 return YAZ_SRW_QUERY_SYNTAX_ERROR;
00818 rpn = query.u.type_1;
00819 if (!rpn->RPNStructure)
00820 return YAZ_SRW_QUERY_SYNTAX_ERROR;
00821 if (rpn->RPNStructure->which != Z_RPNStructure_simple)
00822 return YAZ_SRW_QUERY_SYNTAX_ERROR;
00823 if (rpn->RPNStructure->u.simple->which != Z_Operand_APT)
00824 return YAZ_SRW_QUERY_SYNTAX_ERROR;
00825 memcpy(result, rpn->RPNStructure->u.simple->u.attributesPlusTerm,
00826 sizeof(*result));
00827 return 0;
00828 }
00829
00830
00831 static int ccl2pqf(ODR odr, const Odr_oct *ccl, CCL_bibset bibset,
00832 bend_search_rr *bsrr) {
00833 char *ccl0;
00834 struct ccl_rpn_node *node;
00835 int errcode, pos;
00836
00837 ccl0 = odr_strdupn(odr, (char*) ccl->buf, ccl->len);
00838 if ((node = ccl_fin