First kick.
[egate.git] / zlayer / zaccess.c
1 /*
2  * Europagate, 1995
3  *
4  * $Log: zaccess.c,v $
5  * Revision 1.1  1995/02/16 14:47:55  quinn
6  * First kick.
7  *
8  */
9
10 /*
11  * Interface to the Z39.50 toolkit.
12  */
13
14 #include <stdlib.h>
15 #include <assert.h>
16
17 #include <z3950.h>
18 #include <z3950sup.h>
19 #include <zutil.h>
20
21 #include <gw-log.h>
22
23 #include <ccl.h>
24 #include <zaccess.h>
25
26 struct zass    /* Z-assoc */
27 {
28     NETBOXPROFILE *ass;              /* ZDIST association handle */
29     int fd;                         /* low-level socket (for select only) */
30     int maxrecordsize;
31     int preferredmessagesize;
32     char *buf;                      /* intermediary buffer */
33 };
34
35 int rpn2kwaqs(struct ccl_rpn_node *q, char **p)
36 {
37     struct ccl_rpn_attr *i;
38     static char *ops[] = {"and", "or", "not"};
39
40     assert(!CCL_RPN_AND);
41     switch (q->kind)
42     {
43         case CCL_RPN_TERM:
44             strcpy(*p, q->u.t.term);
45             (*p) += strlen(q->u.t.term);
46             if (q->u.t.attr_list)
47             {
48                 strcat(*p, "[");
49                 (*p)++;
50                 for (i = q->u.t.attr_list; i; i = i->next)
51                 {
52                     sprintf(*p, "%d,%d", i->type, i->value);
53                     *p += strlen(*p);
54                 }
55                 strcat(*p, "]");
56                 (*p)++;
57             }
58             return 0;
59         case CCL_RPN_SET:
60             gw_log(GW_LOG_FATAL, ZASS_TYPE, "KWAQS Doesn't support set refs");
61             return -1;
62         case CCL_RPN_AND: case CCL_RPN_OR: case CCL_RPN_NOT:
63             strcpy(*p, ops[q->kind]);
64             *p += strlen(ops[q->kind]);
65             strcat(*p, "(");
66             (*p)++;
67             if (rpn2kwaqs(q->u.p[0], p) < 0)
68                 return -1;
69             strcat(*p, ",");
70             (*p)++;
71             if (rpn2kwaqs(q->u.p[1], p) < 0)
72                 return -1;
73             strcat(*p, ")");
74             (*p)++;
75             return 0;
76         default:
77             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Unknown RPN node");
78             return -1;
79     }
80 }
81
82 ZASS zass_open(char *host, int port)
83 {
84     struct zass *p;
85     PINITREQUEST ireq;
86     PINITRESPONSE ires;
87     int len;
88
89     if (!(p = malloc(sizeof(*p))))
90     {
91         gw_log(GW_LOG_FATAL, ZASS_TYPE, "memory alloc failed");
92         return 0;
93     }
94     p->maxrecordsize = ZASS_MAXRECORDSIZE;
95     p->preferredmessagesize = ZASS_PREFERREDMESSAGESIZE;
96     if (!(p->buf = malloc(ZASS_MAXRECORDSIZE + 100)))
97     {
98         gw_log(GW_LOG_FATAL, ZASS_TYPE, "alloc zass-buffer");
99         return 0;
100     }
101     if (!(p->ass = NEWSTRUCT(NETBOXPROFILE)))
102     {
103         gw_log(GW_LOG_FATAL, ZASS_TYPE, "memory alloc failed");
104         return 0;
105     }
106     p->ass->TimeOutSec = 120;
107     p->ass->TimeOutUSec = 0;
108     strcpy(p->ass->HostName, host);
109     p->ass->Port = port;
110
111     if (netbox_Open(p->ass) != 1)
112     {
113         gw_log(GW_LOG_WARN, ZASS_TYPE, "netbox_Open failed");
114         return 0;
115     }
116     gw_log(ZASS_DEBUG, ZASS_TYPE, "Opened connection to %s:%d", p->ass->HostName,
117         p->ass->Port);
118     ireq = InitRequest_CreateInitAllASCII(0, "yy", "yy", p->maxrecordsize,
119         p->preferredmessagesize, ZASS_ID, ZASS_NAME, ZASS_VERSION, 0);
120     if (!ireq)
121     {
122         gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create initrequest");
123         return 0;
124     }
125     zutil_GetBEREncodedBuffer(ireq, (unsigned char*)p->buf, &len,
126         p->maxrecordsize);
127     if (len <= 0)
128     {
129         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode initrequest");
130         return 0;
131     }
132     InitRequest_Destroy(ireq);
133     if (netbox_SendBuffer(p->ass, p->buf, len) != len)
134     {
135         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send initrequest");
136         return 0;
137     }
138     gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent initrequest.");
139     if ((len = zutil_GetBERFromNet(p->ass, (unsigned char*)p->buf,
140         p->maxrecordsize)) <= 0)
141     {
142         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive initresponse");
143         return 0;
144     }
145     ires = (PINITRESPONSE) zutil_CreateFromData((unsigned char*)p->buf, len);
146     if (InitResponse_GetTag(ires) != INITRESPONSE_TAG)
147     {
148         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected initresponse from target");
149         return 0;
150     }
151     gw_log(ZASS_DEBUG, ZASS_TYPE, "Got initresponse");
152     if (!InitResponse_GetResult(ires))
153     {
154         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Access to target denied.");
155         return 0;
156     }
157     gw_log(ZASS_DEBUG, ZASS_TYPE, "Connected OK");
158     p->preferredmessagesize = InitResponse_GetPreferredMessageSize(ires);
159     p->maxrecordsize = InitResponse_GetExceptionalRecordSize(ires);
160     InitResponse_Destroy(ires);
161     return p;
162 }
163
164 const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query,
165     char *resname, char *databases)
166 {
167     static struct zass_searchent r;
168     char kwaqs[512], *p;
169     DATA_DIR *pdu, *record;
170     int len;
171
172     p = kwaqs;
173     if (rpn2kwaqs(query, &p) < 0)
174     {
175         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode query");
176         return 0;
177     }
178     gw_log(ZASS_DEBUG, ZASS_TYPE, "Query: KWAQS: '%s'", kwaqs);
179     pdu = SearchRequest_CreateInitAllASCII(0, 0, 2, 0, 1, resname, databases,
180         0, 0, 0, kwaqs, BIB1_OID);
181     if (!pdu)
182     {
183         gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create searchrequest");
184         return 0;
185     }
186     zutil_GetBEREncodedBuffer(pdu, (unsigned char*)a->buf, &len,
187         a->maxrecordsize);
188     if (len <= 0)
189     {
190         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode initrequest");
191         return 0;
192     }
193     SearchRequest_Destroy(pdu);
194     if (netbox_SendBuffer(a->ass, a->buf, len) != len)
195     {
196         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send initrequest");
197         return 0;
198     }
199     gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent searchrequest.");
200     if ((len = zutil_GetBERFromNet(a->ass, (unsigned char*)a->buf,
201         a->maxrecordsize)) <= 0)
202     {
203         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive searchresponse");
204         return 0;
205     }
206     pdu = zutil_CreateFromData((unsigned char*)a->buf, len);
207     if (zutil_GetTag(pdu) != SEARCHRESPONSE_TAG)
208     {
209         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected serchresponse from target");
210         return 0;
211     }
212     gw_log(ZASS_DEBUG, ZASS_TYPE, "Got searchresponse");
213     r.status = SearchResponse_GetSearchStatus(pdu);
214     r.num = SearchResponse_GetResultCount(pdu);
215     r.status = SearchResponse_GetResultSetStatus(pdu);
216     if ((record = SearchResponse_GetRecords(pdu)))
217     {
218         if (zutil_GetTag(record) == NONSURROGATEDIAGNOSTIC_TAG)
219         {
220             DATA_DIR *ad;
221
222             r.errcode = zutil_GetTaggedInt(record, ASN1_INTEGER);
223             if ((ad = zutil_GetTaggedObject(record, ASN1_VISIBLESTRING)))
224             {
225                 char *s;
226
227                 if ((s = OctetString_GetASCIIString(ad)))
228                 {
229                     strcpy(r.errstring, s);
230                     FREE(s);
231                 }
232                 else
233                     *r.errstring = '\0';
234             }
235             else
236                 *r.errstring = '\0';
237         }
238         else
239             gw_log(GW_LOG_WARN, ZASS_TYPE, "Got real record in SRCHRESP");
240     }
241     SearchResponse_Destroy(pdu);
242
243     return &r;
244 }
245
246 /*
247  * Note that 1== first record.
248  */
249 const struct zass_presentent *zass_present(ZASS a, char *resname, int start,
250     int num)
251 {
252     return 0;
253 }