Added YAZ version of zaccess
authorSebastian Hammer <quinn@indexdata.com>
Mon, 17 Apr 1995 11:26:52 +0000 (11:26 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Mon, 17 Apr 1995 11:26:52 +0000 (11:26 +0000)
zlayer/Makefile
zlayer/zaccess-yaz.c [new file with mode: 0644]
zlayer/zaccess.c

index e1dbc4d..44566aa 100644 (file)
@@ -2,7 +2,10 @@
 # Europagate, 1995
 #
 # $Log: Makefile,v $
-# Revision 1.8  1995/04/17 09:36:44  adam
+# Revision 1.9  1995/04/17 11:26:52  quinn
+# Added YAZ version of zaccess
+#
+# Revision 1.8  1995/04/17  09:36:44  adam
 # Minor changes in makefile.
 #
 # Revision 1.7  1995/03/27  12:52:25  adam
 #
 SHELL=/bin/sh
 
-ZDEFS=-DLOW_TO_HIGH -Dfar=
-ZPRE=/home/proj/zdist/zdist102b1-1/libz3950
-ZINC=-I$(ZPRE)
-ZLIB=$(ZPRE)/libz3950.a
+#ZDEFS=-DLOW_TO_HIGH -Dfar=
+#ZPRE=/home/proj/zdist/zdist102b1-1/libz3950
+#ZINC=-I$(ZPRE)
+#ZLIB=$(ZPRE)/libz3950.a
+
+ZINC=-I../../yaz/include
+ZDEFS=  # -DUSE_XTIMOSI
+ZLIB=../../yaz/lib/libyaz.a
 
 INCLUDE=-I. -I../include $(ZINC)
 #CFLAGS=-g -Wall -pedantic -ansi
 TPROG1=test
 LIB=../lib/libzass.a
-PO=zaccess.o
+PO=zaccess-yaz.o
 CPP=$(CC) -E
 DEFS=$(INCLUDE)
 
diff --git a/zlayer/zaccess-yaz.c b/zlayer/zaccess-yaz.c
new file mode 100644 (file)
index 0000000..f8615d9
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Europagate, 1995
+ *
+ * Z39.50 API for the Email gateway - YAZ version
+ *
+ * $Log: zaccess-yaz.c,v $
+ * Revision 1.1  1995/04/17 11:26:53  quinn
+ * Added YAZ version of zaccess
+ *
+ *
+ */
+
+/*
+ * Interface to the Z39.50 toolkit.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <gw-log.h>
+#include <proto.h>
+#include <comstack.h>
+#include <tcpip.h>
+#ifdef USE_XTIMOSI
+#include <xmosi.h>
+#endif
+#include <oid.h>
+
+#include <ccl.h>
+#include <zaccess.h>
+
+struct zass    /* Z-assoc */
+{
+    COMSTACK ass;              /* comstack association handle */
+    ODR encode;
+    ODR decode;
+    int fd;                         /* low-level socket (for select only) */
+    int maxrecordsize;
+    int preferredmessagesize;
+    char *outbuf;                      /* intermediary buffer */
+    char *inbuf;
+    int inbuflen;
+};
+
+static Z_APDU *get_apdu(struct zass *z)
+{
+    int res;
+    Z_APDU *ap;
+
+    if ((res = cs_get(z->ass, &z->inbuf, &z->inbuflen)) <= 0)
+    {
+       gw_log(GW_LOG_WARN, ZASS_TYPE, "cs_get failed");
+       return 0;
+    }
+    odr_reset(z->decode);
+    odr_setbuf(z->decode, z->inbuf, res);
+    if (!z_APDU(z->decode, &ap, 0))
+    {
+       gw_log(GW_LOG_WARN, ZASS_TYPE, "decode: %s",
+           odr_errlist[odr_geterror(z->decode)]);
+       return 0;
+    }
+    return ap;
+}
+
+static int send_apdu(struct zass *z, Z_APDU *a)
+{
+    char *buf;
+    int len;
+
+    if (!z_APDU(z->encode, &a, 0))
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "encoding initreq");
+       return -1;
+    }
+    buf = odr_getbuf(z->encode, &len);
+    if (cs_put(z->ass, buf, len) < 0)
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "cs_put");
+       return -1;
+    }
+    odr_reset(z->encode);
+    return 0;
+}
+
+static int send_initreq(struct zass *p)
+{
+    Z_APDU a;
+    Z_InitRequest init;
+    Odr_bitmask options, protocolVersion;
+    char name[512];
+
+    a.which = Z_APDU_initRequest;
+    a.u.initRequest = &init;
+    init.referenceId = 0;
+    init.options = &options;
+    ODR_MASK_ZERO(&options);
+    ODR_MASK_SET(&options, Z_Options_search);
+    ODR_MASK_SET(&options, Z_Options_present);
+    ODR_MASK_SET(&options, Z_Options_delSet);
+    init.protocolVersion = &protocolVersion;
+    ODR_MASK_ZERO(&protocolVersion);
+    ODR_MASK_SET(&protocolVersion, Z_ProtocolVersion_1);
+    ODR_MASK_SET(&protocolVersion, Z_ProtocolVersion_2);
+    init.preferredMessageSize = &p->preferredmessagesize;
+    init.maximumRecordSize = &p->maxrecordsize;
+    init.idAuthentication = 0;
+    init.implementationId = ZASS_ID;
+    sprintf(name, "%s (YAZ protocol layer)", ZASS_NAME);
+    init.implementationName = name;
+    init.implementationVersion = ZASS_VERSION;
+    init.userInformationField = 0;
+    if (send_apdu(p, &a) < 0)
+       return -1;
+    return 0;
+}
+
+static int receive_initres(struct zass *p)
+{
+    Z_APDU *ap;
+    Z_InitResponse *res;
+
+    if (!(ap = get_apdu(p)))
+       return -1;
+    if (ap->which != Z_APDU_initResponse)
+    {
+       gw_log(GW_LOG_WARN, ZASS_TYPE, "bad APDU");
+       return -1;
+    }
+    res = ap->u.initResponse;
+    if (!*res->result)
+    {
+       gw_log(GW_LOG_WARN, ZASS_TYPE, "Negative result on initres");
+       return -1;
+    }
+    p->preferredmessagesize = *res->preferredMessageSize;
+    p->maxrecordsize = *res->maximumRecordSize;
+    if (res->implementationId)
+       gw_log(GW_LOG_NOTICE, ZASS_TYPE, "imp. ID  : %s",
+           res->implementationId);
+    if (res->implementationName)
+       gw_log(GW_LOG_NOTICE, ZASS_TYPE, "imp. ID  : %s",
+           res->implementationName);
+    if (res->implementationVersion)
+       gw_log(GW_LOG_NOTICE, ZASS_TYPE, "imp. ID  : %s",
+           res->implementationVersion);
+    gw_log(ZASS_DEBUG, ZASS_TYPE, "Initialized ok");
+    return 0;
+}
+
+ZASS zass_open(char *host, int port)
+{
+    struct zass *p;
+    char addstr[512];
+    void *address;
+
+    if (!(p = malloc(sizeof(*p))))
+    {
+       gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "malloc");
+       return 0;
+    }
+    if (!(p->encode = odr_createmem(ODR_ENCODE)) ||
+       !(p->decode = odr_createmem(ODR_DECODE)))
+    {
+       gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "odr_createmem");
+       return 0;
+    }
+    p->maxrecordsize = ZASS_MAXRECORDSIZE;
+    p->preferredmessagesize = ZASS_PREFERREDMESSAGESIZE;
+    if (!(p->outbuf = malloc(p->maxrecordsize + 1024)))
+    {
+       gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "malloc");
+       return 0;
+    }
+    odr_setbuf(p->encode, p->outbuf, p->maxrecordsize + 1024);
+    if (!(p->ass = cs_create(tcpip_type, 1, CS_Z3950)))
+    {
+       gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "cs_create");
+       return 0;
+    }
+    sprintf(addstr, "%s:%d", host, port);
+    if (!(address = tcpip_strtoaddr(addstr)))
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "failed to resolve %s", addstr);
+       return 0;
+    }
+    p->fd = cs_fileno(p->ass);
+    gw_log(ZASS_DEBUG, ZASS_TYPE, "Connecting to %s", addstr);
+    if (cs_connect(p->ass, address) < 0)
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to connect to %s", addstr);
+       return 0;
+    }
+    gw_log(ZASS_DEBUG, ZASS_TYPE, "connected ok");
+    if (send_initreq(p) < 0 || receive_initres(p) < 0)
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to initialize");
+       return 0;
+    }
+    gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent init request");
+    p->inbuf = 0;
+    p->inbuflen = 0;
+    return p;
+}
+
+static Z_RPNStructure *rpn2rpn(ODR o, struct ccl_rpn_node *q)
+{
+    Z_RPNStructure *r = odr_malloc(o, sizeof(*r));
+    Z_AttributesPlusTerm *t;
+    struct ccl_rpn_attr *i;
+    int len;
+    static int op[] = { Z_Operator_and, Z_Operator_or, Z_Operator_and_not };
+
+    switch (q->kind)
+    {
+       case CCL_RPN_TERM:
+           r->which = Z_RPNStructure_simple;
+           r->u.simple = odr_malloc(o, sizeof(Z_Operand));
+           r->u.simple->which = Z_Operand_APT;
+           r->u.simple->u.attributesPlusTerm = t = odr_malloc(o, sizeof(*t));
+           t->term = odr_malloc(o, sizeof(Z_Term));
+           t->term->which = Z_Term_general;
+           t->term->u.general = odr_malloc(o, sizeof(Odr_oct));
+           t->term->u.general->len = t->term->u.general->size =
+               strlen(q->u.t.term);
+           t->term->u.general->buf = odr_malloc(o, t->term->u.general->size);
+           memcpy(t->term->u.general->buf, q->u.t.term,
+               t->term->u.general->len);
+           t->num_attributes = 0;
+           t->attributeList = odr_malloc(o, sizeof(Z_AttributeElement*) * 100);
+           for (i = q->u.t.attr_list; i && t->num_attributes < 100;
+               i = i->next)
+           {
+               Z_AttributeElement *a;
+               
+               t->attributeList[t->num_attributes++] = a =
+                   odr_malloc(o, sizeof(*a));
+               a->attributeType = odr_malloc(o, sizeof(int));
+               *a->attributeType = i->type;
+               a->attributeValue = odr_malloc(o, sizeof(*a));
+               *a->attributeValue = i->value;
+           }
+           return r;
+       case CCL_RPN_SET:
+           r->which = Z_RPNStructure_simple;
+           r->u.simple = odr_malloc(o, sizeof(Z_Operand));
+           r->u.simple->which = Z_Operand_resultSetId;
+           r->u.simple->u.resultSetId = odr_malloc(o, len =
+               strlen(q->u.setname));
+           memcpy(r->u.simple->u.resultSetId, q->u.setname, len);
+           return r;
+       case CCL_RPN_AND: case CCL_RPN_OR: case CCL_RPN_NOT:
+           r->which = Z_RPNStructure_complex;
+           r->u.complex = odr_malloc(o, sizeof(Z_Complex));
+           if (!(r->u.complex->s1 = rpn2rpn(o, q->u.p[0])) ||
+               !(r->u.complex->s2 = rpn2rpn(o, q->u.p[1])))
+                   return 0;
+           r->u.complex->operator = odr_malloc(o, sizeof(Z_Operator));
+           r->u.complex->operator->which = op[q->kind];
+           r->u.complex->operator->u.and = "";
+           return r;
+       default:
+           gw_log(GW_LOG_FATAL, ZASS_TYPE, "Bad operator in RPN");
+           return 0;
+    }
+}
+
+static const struct zass_searchent *search_result(ZASS a)
+{
+    static struct zass_searchent r;
+    Z_APDU *apdu;
+    Z_SearchResponse *res;
+
+    if (!(apdu = get_apdu(a)))
+       return 0;
+    if (apdu->which != Z_APDU_searchResponse)
+    {
+       gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected searchresponse, got #%d",
+           apdu->which);
+       return 0;
+    }
+    res = apdu->u.searchResponse;
+    r.status = *res->searchStatus;
+    r.num = *res->resultCount;
+    r.status = res->resultSetStatus ? *res->resultSetStatus : 0;
+    r.errcode = -1;
+    *r.errstring = '\0';
+    if (res->records)
+    {
+       if (res->records->which != Z_Records_NSD)
+           gw_log(GW_LOG_WARN, ZASS_TYPE, "Unexpected record types in SchR");
+       else
+       {
+           oident *id;
+           Z_DiagRec *dr = res->records->u.nonSurrogateDiagnostic;
+
+           if (!(id = oid_getentbyoid(dr->diagnosticSetId)) ||
+               id->class != CLASS_DIAGSET || id->value != VAL_BIB1)
+                   gw_log(GW_LOG_WARN, ZASS_TYPE,
+                       "Missing or unknown diagset - ignoring error!");
+           else
+           {
+               r.errcode = *dr->condition;
+               if (dr->addinfo)
+               {
+                   strncpy(r.errstring, dr->addinfo, 512);
+                   r.errstring[511] = '\0';
+               }
+           }
+       }
+    }
+    return &r;
+}
+
+const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query,
+    char *resname, char *databases)
+{
+    Z_Query q;
+    Z_RPNQuery rpnq;
+    Z_APDU apdu;
+    Z_SearchRequest req;
+    oident bib1;
+    int smallSetUpperBound = 0;
+    int largeSetLowerBound = 1;
+    int mediumSetPresentNumber = 0;
+    int replaceIndicator = 1;
+    char *datab[100];
+
+    apdu.which = Z_APDU_searchRequest;
+    apdu.u.searchRequest = &req;
+    req.referenceId = 0;
+    req.smallSetUpperBound = &smallSetUpperBound;
+    req.largeSetLowerBound = &largeSetLowerBound;
+    req.mediumSetPresentNumber = &mediumSetPresentNumber;
+    req.replaceIndicator = &replaceIndicator;
+    req.resultSetName = resname;
+    req.num_databaseNames = 0;
+    req.databaseNames = datab;
+    while (*databases && req.num_databaseNames < 100)
+    {
+       char *p = databases;
+       int more;
+
+       while (*p && !isspace(*p))
+           p++;
+       if (isspace(*p))
+           more = 1;
+       else
+           more = 0;
+       *p = '\0';
+       if (p - databases)
+       {
+           req.databaseNames[req.num_databaseNames] = odr_malloc(a->encode,
+               (p - databases) + 1);
+           strcpy(req.databaseNames[req.num_databaseNames++], databases);
+       }
+       databases = p + more;
+    }
+    req.smallSetElementSetNames = 0;
+    req.mediumSetElementSetNames = 0;
+    req.preferredRecordSyntax = 0;
+    req.query = &q;
+    q.which = Z_Query_type_1;
+    q.u.type_1 = &rpnq;
+    bib1.proto = PROTO_Z3950;
+    bib1.class = CLASS_ATTSET;
+    bib1.value = VAL_BIB1;
+    rpnq.attributeSetId = oid_getoidbyent(&bib1);
+    if (!(rpnq.RPNStructure = rpn2rpn(a->encode, query)))
+       return 0;
+    if (send_apdu(a, &apdu) < 0)
+       return 0;
+
+    return search_result(a);
+}
+
+/*
+ * Triple indirection - that's kinda heavy. We'll fix it later.
+ * There are worse things around, though. Like ZDist.
+ */
+void get_diagrec(zass_record ***p, Z_DiagRec *r)
+{
+    **p = malloc(sizeof(***p));
+    (**p)->next = 0;
+    (**p)->errcode = *r->condition;
+    if (r->addinfo)
+    {
+       strncpy((**p)->errstring, r->addinfo, 200);
+       (**p)->errstring[200] = 0;
+    }
+    else
+       (**p)->errstring[0] = '\0';
+    (**p)->which = ZASS_REC_DIAG;
+    *p = &(**p)->next;
+}
+
+void get_responserecords(zass_record ***p, Z_NamePlusRecordList *recs)
+{
+    int i;
+
+    for (i = 0; i < recs->num_records; i++)
+    {
+       Z_NamePlusRecord *record;
+
+       record = recs->records[i];
+       if (record->which == Z_NamePlusRecord_surrogateDiagnostic)
+           get_diagrec(p, record->u.surrogateDiagnostic);
+       else
+       {
+           Z_DatabaseRecord *r = record->u.databaseRecord;
+           oident *recform;
+
+           **p = malloc(sizeof(***p));
+           (**p)->next = 0;
+
+           if (!(recform = oid_getentbyoid(r->direct_reference)) ||
+                recform->class != CLASS_RECSYN)
+           {
+               gw_log(GW_LOG_WARN, ZASS_TYPE, "Unknown or bad record syntax");
+               (**p)->which = ZASS_REC_UNKNOWN;
+           }
+           else
+               switch (recform->value)
+               {
+                   case VAL_USMARC: (**p)->which = ZASS_REC_USMARC; break;
+                   default:
+                       gw_log(GW_LOG_WARN, ZASS_TYPE, "Unknown recsyn");
+                       (**p)->which = ZASS_REC_UNKNOWN;
+               }
+           if (r->which != ODR_EXTERNAL_octet)
+           {
+               gw_log(GW_LOG_WARN, ZASS_TYPE, "Record wasn't octet-aligned");
+               (**p)->record = 0;
+           }
+           else
+           {
+               if (!((**p)->record = malloc(r->u.octet_aligned->len + 1)))
+               {
+                   gw_log(GW_LOG_FATAL, ZASS_TYPE, "malloc");
+                   return;
+               }
+               memcpy((**p)->record, r->u.octet_aligned->buf,
+                   r->u.octet_aligned->len);
+               (**p)->record[r->u.octet_aligned->len] = '\0';
+               gw_log(ZASS_DEBUG, ZASS_TYPE, "Got a record of %d bytes",
+                   r->u.octet_aligned->len);
+           }
+       }
+       (*p) = &(**p)->next;
+    }
+}
+
+static void zass_records_free(zass_record *p)
+{
+}
+
+static int send_present(ZASS a, char *name, int start, int num,
+    enum oid_value form)
+{
+    Z_APDU apdu;
+    Z_PresentRequest req;
+    oident recsyn;
+
+    apdu.which = Z_APDU_presentRequest;
+    apdu.u.presentRequest = &req;
+    req.referenceId = 0;
+    req.resultSetId = name;
+    req.resultSetStartPoint = &start;
+    req.numberOfRecordsRequested = &num;
+    req.elementSetNames = 0;
+    recsyn.proto = PROTO_Z3950;
+    recsyn.class = CLASS_RECSYN;
+    recsyn.value = form;
+    req.preferredRecordSyntax = oid_getoidbyent(&recsyn);
+    return send_apdu(a, &apdu);
+}
+
+/*
+ * Note that 1== first record.
+ */
+const struct zass_presentent *zass_present(ZASS a, char *resname, int start,
+    int num)
+{
+    static struct zass_presentent r;
+    zass_record **rec = &r.records;
+
+    r.num = 0;
+    if (r.records)
+    {
+       zass_records_free(r.records);
+       r.records = 0;
+    }
+    do
+    {
+       Z_APDU *apdu;
+       Z_PresentResponse *res;
+
+       gw_log(ZASS_DEBUG, ZASS_TYPE,
+           "Fetching %d records from # %d", num - r.num, start);
+       if (send_present(a, resname, start, num - r.num, VAL_USMARC) < 0)
+           return 0;
+       if (!(apdu = get_apdu(a)))
+           return 0;
+       if (apdu->which != Z_APDU_presentResponse)
+       {
+           gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected presentresponse, got #%d",
+               apdu->which);
+           return 0;
+       }
+       res = apdu->u.presentResponse;
+       r.presentstatus = *res->presentStatus;
+       r.num += *res->numberOfRecordsReturned;
+       if (*res->numberOfRecordsReturned == 0)
+       {
+           gw_log(GW_LOG_WARN, ZASS_TYPE, "Got 0 records from target");
+           return 0;
+       }
+       r.nextpos = *res->nextResultSetPosition;
+       start = r.nextpos;
+       switch (res->records->which)
+       {
+           case Z_Records_DBOSD:
+               get_responserecords(&rec,
+                   res->records->u.databaseOrSurDiagnostics);
+               break;
+           case Z_Records_NSD:
+               get_diagrec(&rec, res->records->u.nonSurrogateDiagnostic);
+               break;
+           default:
+               gw_log(GW_LOG_WARN, ZASS_TYPE, "Bad tag in response rec.");
+               return 0;
+       }
+    }
+    while (num - r.num && start);
+    return &r;
+}
index 3cbc5ca..0420161 100644 (file)
@@ -4,7 +4,10 @@
  * Z39.50 API for the Email gateway
  *
  * $Log: zaccess.c,v $
- * Revision 1.14  1995/02/23 08:32:26  adam
+ * Revision 1.15  1995/04/17 11:26:55  quinn
+ * Added YAZ version of zaccess
+ *
+ * Revision 1.14  1995/02/23  08:32:26  adam
  * Changed header.
  *
  * Revision 1.12  1995/02/20  20:35:37  quinn
@@ -124,6 +127,7 @@ ZASS zass_open(char *host, int port)
     PINITREQUEST ireq;
     PINITRESPONSE ires;
     int len;
+    char name[512];
 
     if (!(p = malloc(sizeof(*p))))
     {
@@ -154,8 +158,9 @@ ZASS zass_open(char *host, int port)
     }
     gw_log(ZASS_DEBUG, ZASS_TYPE, "Opened connection to %s:%d", p->ass->HostName,
        p->ass->Port);
+    sprintf(name, "%s (ZDIST protocol layer)", ZASS_NAME);
     ireq = InitRequest_CreateInitAllASCII(0, "yy", "yy", p->maxrecordsize,
-       p->preferredmessagesize, ZASS_ID, ZASS_NAME, ZASS_VERSION, 0);
+       p->preferredmessagesize, ZASS_ID, name, ZASS_VERSION, 0);
     if (!ireq)
     {
        gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create initrequest");
@@ -465,7 +470,7 @@ const struct zass_presentent *zass_present(ZASS a, char *resname, int start,
        }
        PresentResponse_Destroy(pdu);
     }
-    while (num - r.num);
+    while (num - r.num && start);
     *rec = 0;
        
     return &r;