+ ODR o = odr_encode();
+ Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_scan_response);
+ Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
+
+ srw_res->num_diagnostics = num_diagnostics;
+ srw_res->diagnostics = diagnostics;
+ return send_srw_response(srw_pdu, http_code);
+}
+
+int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+ int num_diagnostics)
+{
+ int http_status = 404;
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (cfg)
+ {
+ int len;
+ char *b = cfg->get_explain_doc(odr_encode(), 0 /* target */,
+ m_s2z_database, &len, &http_status);
+ if (b)
+ {
+ Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
+ Z_SRW_explainResponse *er = res->u.explain_response;
+
+ er->record.recordData_buf = b;
+ er->record.recordData_len = len;
+ er->record.recordPacking = m_s2z_packing;
+ er->record.recordSchema = odr_strdup(odr_encode(),
+ "http://explain.z3950.org/dtd/2.0/");
+
+ er->diagnostics = diagnostics;
+ er->num_diagnostics = num_diagnostics;
+ return send_srw_response(res);
+ }
+ }
+ return send_http_response(http_status);
+}
+
+int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
+{
+ if (m_http_version)
+ {
+ if (apdu->which == Z_APDU_initResponse)
+ {
+ Z_InitResponse *res = apdu->u.initResponse;
+ if (*res->result == 0)
+ {
+ send_to_srw_client_error(3, 0);
+ }
+ else if (m_s2z_search_apdu)
+ {
+ handle_incoming_Z_PDU(m_s2z_search_apdu);
+ }
+ else if (m_s2z_scan_apdu)
+ {
+ handle_incoming_Z_PDU(m_s2z_scan_apdu);
+ }
+ else
+ {
+ send_srw_explain_response(0, 0);
+ }
+ }
+ else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
+ {
+ m_s2z_search_apdu = 0;
+ Z_SearchResponse *res = apdu->u.searchResponse;
+ m_s2z_hit_count = *res->resultCount;
+ if (res->records && res->records->which == Z_Records_NSD)
+ {
+ send_to_srw_client_ok(0, res->records, 1);
+ }
+ else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
+ {
+ // adjust
+ Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
+
+ if (*pr->resultSetStartPoint <= m_s2z_hit_count)
+ {
+ if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
+ > m_s2z_hit_count)
+ *pr->numberOfRecordsRequested =
+ 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
+ }
+ handle_incoming_Z_PDU(m_s2z_present_apdu);
+ }
+ else
+ {
+ m_s2z_present_apdu = 0;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
+ }
+ }
+ else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
+ {
+ int start =
+ *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
+
+ m_s2z_present_apdu = 0;
+ Z_PresentResponse *res = apdu->u.presentResponse;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
+ }
+ else if (m_s2z_scan_apdu && apdu->which == Z_APDU_scanResponse)
+ {
+ Z_ScanResponse *res = apdu->u.scanResponse;
+ send_to_srw_client_ok(res->entries);
+ }
+ }
+ else
+ {
+ int len = 0;
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ yaz_log(YLOG_LOG, "%sSending %s to client", m_session_str,
+ apdu_name(apdu));
+ int r = send_Z_PDU(apdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+ }
+ return 0;
+}
+
+int Yaz_Proxy::send_to_client(Z_APDU *apdu)
+{
+ int kill_session = 0;
+ Z_ReferenceId **new_id = get_referenceIdP(apdu);
+
+ if (new_id)
+ *new_id = m_referenceId;
+
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+
+ *sr->searchStatus = 0;
+ display_diagrecs(&dr_p, 1);
+ }
+ else
+ {
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_backend_type
+#if HAVE_USEMARCON
+ || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+ )
+ convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
+ if (m_marcxml_mode == marcxml)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics,
+ m_backend_charset);
+ else
+ convert_records_charset(p->u.databaseOrSurDiagnostics,
+ m_backend_charset);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+
+ }
+ if (sr->resultCount)
+ {
+ yaz_log(YLOG_LOG, "%s" ODR_INT_PRINTF " hits", m_session_str,
+ *sr->resultCount);
+ if (*sr->resultCount < 0)
+ {
+ m_flag_invalid_session = 1;
+ kill_session = 1;
+
+ *sr->searchStatus = 0;
+ sr->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
+ *sr->resultCount = 0;
+ }
+ }
+ }
+ }
+ else if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *sr = apdu->u.presentResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+ if (*sr->presentStatus == Z_PresentStatus_success)
+ *sr->presentStatus = Z_PresentStatus_failure;
+ display_diagrecs(&dr_p, 1);
+ }
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_backend_type
+#if HAVE_USEMARCON
+ || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+ )
+ convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
+ if (m_marcxml_mode == marcxml)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics,
+ m_backend_charset);
+ else
+ convert_records_charset(p->u.databaseOrSurDiagnostics,
+ m_backend_charset);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+ }
+ }
+ else if (apdu->which == Z_APDU_initResponse)
+ {
+ //Get and check negotiation record
+ //from init response.
+ handle_charset_lang_negotiation(apdu);
+
+ if (m_initRequest_options)
+ {
+ Z_Options *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<24; i++)
+ if (ODR_MASK_GET(m_initRequest_options, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->options, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->options = nopt;
+ }
+ if (m_initRequest_version)
+ {
+ Z_ProtocolVersion *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<8; i++)
+ if (ODR_MASK_GET(m_initRequest_version, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->protocolVersion = nopt;
+ }
+ apdu->u.initResponse->preferredMessageSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_preferredMessageSize >
+ m_initRequest_preferredMessageSize ?
+ m_initRequest_preferredMessageSize :
+ m_client->m_initResponse_preferredMessageSize);
+ apdu->u.initResponse->maximumRecordSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_maximumRecordSize >
+ m_initRequest_maximumRecordSize ?
+ m_initRequest_maximumRecordSize :
+ m_client->m_initResponse_maximumRecordSize);
+ }
+
+ int r = send_PDU_convert(apdu);
+ if (r)
+ return r;
+ if (kill_session)
+ {
+ delete m_client;
+ m_client = 0;
+ m_parent->pre_init();
+ }
+ return r;
+}
+
+void Yaz_ProxyClient::set_idAuthentication(Z_APDU *apdu)
+{
+ Z_IdAuthentication *t = apdu->u.initRequest->idAuthentication;
+
+ odr_reset(m_idAuthentication_odr);
+ z_IdAuthentication(m_idAuthentication_odr, &t, 1, 0);
+ m_idAuthentication_ber_buf =
+ odr_getbuf(m_idAuthentication_odr,
+ &m_idAuthentication_ber_size, 0);
+}
+
+bool Yaz_ProxyClient::compare_charset(Z_APDU *apdu)
+{
+ return true;
+}
+
+bool Yaz_ProxyClient::compare_idAuthentication(Z_APDU *apdu)
+{
+ Z_IdAuthentication *t = apdu->u.initRequest->idAuthentication;
+ ODR odr = odr_createmem(ODR_ENCODE);
+
+ z_IdAuthentication(odr, &t, 1, 0);
+ int sz;
+ char *buf = odr_getbuf(odr, &sz, 0);
+ if (buf && m_idAuthentication_ber_buf
+ && sz == m_idAuthentication_ber_size
+ && !memcmp(m_idAuthentication_ber_buf, buf, sz))
+ {
+ odr_destroy(odr);
+ return true;
+ }
+ odr_destroy(odr);
+ if (!buf && !m_idAuthentication_ber_buf)
+ return true;
+ return false;
+}
+
+int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
+{
+ int len = 0;
+ const char *apdu_name_tmp = apdu_name(apdu);
+ int r = send_Z_PDU(apdu, &len);
+ if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
+ yaz_log(YLOG_LOG, "%sSending %s to %s %d bytes",
+ get_session_str(),
+ apdu_name_tmp, get_hostname(), len);