+int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
+
+/*
+ * Prepare a searchresponse based on the backend results. We probably want
+ * to look at making the fetching of records nonblocking as well, but
+ * so far, we'll keep things simple.
+ * If bsrt is null, that means we're called in response to a communications
+ * event, and we'll have to get the response for ourselves.
+ */
+static Z_APDU *response_searchRequest(association *assoc, request *reqb,
+ bend_search_rr *bsrt, int *fd)
+{
+ Z_SearchRequest *req = reqb->request->u.searchRequest;
+ Z_APDU *apdu = (Z_APDU *)odr_malloc (assoc->encode, sizeof(*apdu));
+ Z_SearchResponse *resp = (Z_SearchResponse *)odr_malloc (assoc->encode, sizeof(*resp));
+ int *nulint = (int *)odr_malloc (assoc->encode, sizeof(*nulint));
+ bool_t *sr = (bool_t *)odr_malloc (assoc->encode, sizeof(*sr));
+ int *next = (int *)odr_malloc (assoc->encode, sizeof(*next));
+ int *none = (int *)odr_malloc (assoc->encode, sizeof(*none));
+
+ *nulint = 0;
+ *sr = 1;
+ *next = 0;
+ *none = Z_RES_NONE;
+
+ apdu->which = Z_APDU_searchResponse;
+ apdu->u.searchResponse = resp;
+ resp->referenceId = req->referenceId;
+ resp->additionalSearchInfo = 0;
+ resp->otherInfo = 0;
+ *fd = -1;
+ if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
+ {
+ logf(LOG_FATAL, "Bad result from backend");
+ return 0;
+ }
+ else if (bsrt->errcode)
+ {
+ resp->records = diagrec(assoc, bsrt->errcode, bsrt->errstring);
+ resp->resultCount = nulint;
+ resp->numberOfRecordsReturned = nulint;
+ resp->nextResultSetPosition = nulint;
+ resp->searchStatus = nulint;
+ resp->resultSetStatus = none;
+ resp->presentStatus = 0;
+ }
+ else
+ {
+ int *toget = (int *)odr_malloc (assoc->encode, sizeof(*toget));
+ int *presst = (int *)odr_malloc (assoc->encode, sizeof(*presst));
+ Z_RecordComposition comp, *compp = 0;
+
+ *toget = 0;
+ *presst = 0;
+ resp->records = 0;
+ resp->resultCount = &bsrt->hits;
+
+ comp.which = Z_RecordComp_simple;
+ /* how many records does the user agent want, then? */
+ if (bsrt->hits <= *req->smallSetUpperBound)
+ {
+ *toget = bsrt->hits;
+ if ((comp.u.simple = req->smallSetElementSetNames))
+ compp = ∁
+ }
+ else if (bsrt->hits < *req->largeSetLowerBound)
+ {
+ *toget = *req->mediumSetPresentNumber;
+ if (*toget > bsrt->hits)
+ *toget = bsrt->hits;
+ if ((comp.u.simple = req->mediumSetElementSetNames))
+ compp = ∁
+ }
+ else
+ *toget = 0;
+
+ if (*toget && !resp->records)
+ {
+ oident *prefformat;
+ oid_value form;
+
+ if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
+ prefformat->oclass != CLASS_RECSYN)
+ form = VAL_NONE;
+ else
+ form = prefformat->value;
+ resp->records = pack_records(assoc, req->resultSetName, 1,
+ toget, compp, next, presst, form);
+ if (!resp->records)
+ return 0;
+ resp->numberOfRecordsReturned = toget;
+ resp->nextResultSetPosition = next;
+ resp->searchStatus = sr;
+ resp->resultSetStatus = 0;
+ resp->presentStatus = presst;
+ }
+ else
+ {
+ if (*resp->resultCount)
+ *next = 1;
+ resp->numberOfRecordsReturned = nulint;
+ resp->nextResultSetPosition = next;
+ resp->searchStatus = sr;
+ resp->resultSetStatus = 0;
+ resp->presentStatus = 0;
+ }
+ }
+ 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;
+ ents->num_entries = 0;
+ ents->entries = NULL;
+ ents->num_nonsurrogateDiagnostics = 0;
+ ents->nonsurrogateDiagnostics = NULL;
+ 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->databaseNames)
+ {
+ int i;
+ for (i = 0; i < req->num_databaseNames; i++)
+ logf (LOG_LOG, "Database '%s'", req->databaseNames[i]);
+ }
+ 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;