+ }
+ return apdu;
+}
+
+/*
+ * Maybe we got a little over-friendly when we designed bend_fetch to
+ * get only one record at a time. Some backends can optimise multiple-record
+ * fetches, and at any rate, there is some overhead involved in
+ * all that selecting and hopping around. Problem is, of course, that the
+ * frontend can't know ahead of time how many records it'll need to
+ * fill the negotiated PDU size. Annoying. Segmentation or not, Z/SR
+ * is downright lousy as a bulk data transfer protocol.
+ *
+ * To start with, we'll do the fetching of records from the backend
+ * in one operation: To save some trips in and out of the event-handler,
+ * and to simplify the interface to pack_records. At any rate, asynch
+ * operation is more fun in operations that have an unpredictable execution
+ * speed - which is normally more true for search than for present.
+ */
+static Z_APDU *process_presentRequest(association *assoc, request *reqb,
+ int *fd)
+{
+ Z_PresentRequest *req = reqb->request->u.presentRequest;
+ oident *prefformat;
+ oid_value form;
+ Z_APDU *apdu;
+ Z_PresentResponse *resp;
+ int *presst;
+ int *next;
+ int *num;
+
+ logf(LOG_LOG, "Got PresentRequest.");
+
+ if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
+ prefformat->oclass != CLASS_RECSYN)
+ form = VAL_NONE;
+ else
+ form = prefformat->value;
+ if (assoc->bend_present)
+ {
+ bend_present_rr *bprr = (bend_present_rr *)nmem_malloc (reqb->request_mem, sizeof(*bprr));
+ bprr->setname = req->resultSetId;
+ bprr->start = *req->resultSetStartPoint;
+ bprr->number = *req->numberOfRecordsRequested;
+ bprr->format = form;
+ bprr->comp = req->recordComposition;
+ bprr->stream = assoc->encode;
+ bprr->request = reqb;
+ bprr->association = assoc;
+ bprr->errcode = 0;
+ bprr->errstring = NULL;
+ ((int (*)(void *, bend_present_rr *))(*assoc->bend_present))(assoc->backend, bprr);
+
+ if (!bprr->request)
+ return 0;
+ }
+ apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+ resp = (Z_PresentResponse *)odr_malloc (assoc->encode, sizeof(*resp));
+ presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
+ next = (int *)odr_malloc (assoc->encode, sizeof(*next));
+ num = (int *)odr_malloc (assoc->encode, sizeof(*num));
+ *presst = 0;
+ *next = 0;
+ *num = *req->numberOfRecordsRequested;
+
+ apdu->which = Z_APDU_presentResponse;
+ apdu->u.presentResponse = resp;
+ resp->referenceId = req->referenceId;
+ resp->otherInfo = 0;
+
+ resp->records =
+ pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
+ num, req->recordComposition, next, presst, form);
+ if (!resp->records)
+ return 0;
+ resp->numberOfRecordsReturned = num;
+ resp->presentStatus = presst;
+ resp->nextResultSetPosition = next;
+
+ return apdu;
+}
+
+/*
+ * Scan was implemented rather in a hurry, and with support for only the basic
+ * elements of the service in the backend API. Suggestions are welcome.
+ */
+static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
+{
+ Z_ScanRequest *req = reqb->request->u.scanRequest;
+ Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+ Z_ScanResponse *res = (Z_ScanResponse *)odr_malloc (assoc->encode, sizeof(*res));
+ int *scanStatus = (int *)odr_malloc (assoc->encode, sizeof(*scanStatus));
+ int *numberOfEntriesReturned =
+ (int *)odr_malloc (assoc->encode, sizeof(*numberOfEntriesReturned));
+ Z_ListEntries *ents = (Z_ListEntries *)odr_malloc (assoc->encode, sizeof(*ents));
+ Z_DiagRecs *diagrecs_p = NULL;
+ oident *attent;
+ bend_scanrequest srq;
+ bend_scanresult *srs;
+ oident *attset;
+
+ logf(LOG_LOG, "Got ScanRequest");
+ *scanStatus = Z_Scan_failure;
+ *numberOfEntriesReturned = 0;
+
+ apdu->which = Z_APDU_scanResponse;
+ apdu->u.scanResponse = res;
+ res->referenceId = req->referenceId;
+ res->stepSize = 0;
+ res->scanStatus = scanStatus;
+ res->numberOfEntriesReturned = numberOfEntriesReturned;
+ res->positionOfTerm = 0;
+ res->entries = ents;
+#if ASN_COMPILED
+ ents->num_entries = 0;
+ ents->entries = NULL;
+ ents->num_nonsurrogateDiagnostics = 0;
+ ents->nonsurrogateDiagnostics = NULL;
+#else
+ ents->which = Z_ListEntries_entries;
+#endif
+ res->attributeSet = 0;
+ res->otherInfo = 0;
+
+ if (req->attributeSet && (!(attent = oid_getentbyoid(req->attributeSet)) ||
+ attent->oclass != CLASS_ATTSET
+ || attent->value != VAL_BIB1))
+ diagrecs_p = diagrecs(assoc, 121, 0);
+ else if (req->stepSize && *req->stepSize > 0)
+ diagrecs_p = diagrecs(assoc, 205, 0);
+ else
+ {
+ if (req->termListAndStartPoint->term->which == Z_Term_general)
+ logf(LOG_DEBUG, " term: '%.*s'",
+ req->termListAndStartPoint->term->u.general->len,
+ req->termListAndStartPoint->term->u.general->buf);
+ srq.num_bases = req->num_databaseNames;
+ srq.basenames = req->databaseNames;
+ srq.num_entries = *req->numberOfTermsRequested;
+ srq.term = req->termListAndStartPoint;
+ srq.stream = assoc->encode;
+ if (!(attset = oid_getentbyoid(req->attributeSet)) ||
+ attset->oclass != CLASS_RECSYN)
+ srq.attributeset = VAL_NONE;
+ else
+ srq.attributeset = attset->value;
+ srq.term_position = req->preferredPositionInResponse ?
+ *req->preferredPositionInResponse : 1;
+ if (!(srs = bend_scan(assoc->backend, &srq, 0)))
+ diagrecs_p = diagrecs(assoc, 2, 0);
+ else if (srs->errcode)
+ diagrecs_p = diagrecs(assoc, srs->errcode, srs->errstring);