Debugging.
[egate.git] / zlayer / zaccess.c
1 /*
2  * Europagate, 1995
3  *
4  * $Log: zaccess.c,v $
5  * Revision 1.6  1995/02/17 14:41:22  quinn
6  * Debugging.
7  *
8  * Revision 1.5  1995/02/17  13:58:01  quinn
9  * First kick at present handling
10  *
11  * Revision 1.4  1995/02/16  15:33:45  quinn
12  * Fixed bug in KWAQS generator
13  *
14  * Revision 1.3  1995/02/16  15:20:45  quinn
15  * Added initialization of response from search
16  *
17  * Revision 1.2  1995/02/16  15:14:53  quinn
18  * Fixed KWAQS-generator
19  *
20  * Revision 1.1  1995/02/16  14:47:55  quinn
21  * First kick.
22  *
23  */
24
25 /*
26  * Interface to the Z39.50 toolkit.
27  */
28
29 #include <stdlib.h>
30 #include <assert.h>
31
32 #include <z3950.h>
33 #include <z3950sup.h>
34 #include <zutil.h>
35
36 #include <gw-log.h>
37
38 #include <ccl.h>
39 #include <zaccess.h>
40
41 struct zass    /* Z-assoc */
42 {
43     NETBOXPROFILE *ass;              /* ZDIST association handle */
44     int fd;                         /* low-level socket (for select only) */
45     int maxrecordsize;
46     int preferredmessagesize;
47     char *buf;                      /* intermediary buffer */
48 };
49
50 int rpn2kwaqs(struct ccl_rpn_node *q, char **p)
51 {
52     struct ccl_rpn_attr *i;
53     static char *ops[] = {"and", "or", "not"};
54
55     assert(!CCL_RPN_AND);
56     switch (q->kind)
57     {
58         case CCL_RPN_TERM:
59             strcpy(*p, q->u.t.term);
60             (*p) += strlen(q->u.t.term);
61             if (q->u.t.attr_list)
62             {
63                 strcat(*p, "[");
64                 (*p)++;
65                 for (i = q->u.t.attr_list; i; i = i->next)
66                 {
67                     sprintf(*p, "%d,%d%s", i->type, i->value, i->next ?
68                         "," : "");
69                     *p += strlen(*p);
70                 }
71                 strcat(*p, "]");
72                 (*p)++;
73             }
74             return 0;
75         case CCL_RPN_SET:
76             gw_log(GW_LOG_FATAL, ZASS_TYPE, "KWAQS Doesn't support set refs");
77             return -1;
78         case CCL_RPN_AND: case CCL_RPN_OR: case CCL_RPN_NOT:
79             strcpy(*p, ops[q->kind]);
80             *p += strlen(ops[q->kind]);
81             strcat(*p, "(");
82             (*p)++;
83             if (rpn2kwaqs(q->u.p[0], p) < 0)
84                 return -1;
85             strcat(*p, ",");
86             (*p)++;
87             if (rpn2kwaqs(q->u.p[1], p) < 0)
88                 return -1;
89             strcat(*p, ")");
90             (*p)++;
91             return 0;
92         default:
93             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Unknown RPN node");
94             return -1;
95     }
96 }
97
98 ZASS zass_open(char *host, int port)
99 {
100     struct zass *p;
101     PINITREQUEST ireq;
102     PINITRESPONSE ires;
103     int len;
104
105     if (!(p = malloc(sizeof(*p))))
106     {
107         gw_log(GW_LOG_FATAL, ZASS_TYPE, "memory alloc failed");
108         return 0;
109     }
110     p->maxrecordsize = ZASS_MAXRECORDSIZE;
111     p->preferredmessagesize = ZASS_PREFERREDMESSAGESIZE;
112     if (!(p->buf = malloc(ZASS_MAXRECORDSIZE + 100)))
113     {
114         gw_log(GW_LOG_FATAL, ZASS_TYPE, "alloc zass-buffer");
115         return 0;
116     }
117     if (!(p->ass = NEWSTRUCT(NETBOXPROFILE)))
118     {
119         gw_log(GW_LOG_FATAL, ZASS_TYPE, "memory alloc failed");
120         return 0;
121     }
122     p->ass->TimeOutSec = 120;
123     p->ass->TimeOutUSec = 0;
124     strcpy(p->ass->HostName, host);
125     p->ass->Port = port;
126
127     if (netbox_Open(p->ass) != 1)
128     {
129         gw_log(GW_LOG_WARN, ZASS_TYPE, "netbox_Open failed");
130         return 0;
131     }
132     gw_log(ZASS_DEBUG, ZASS_TYPE, "Opened connection to %s:%d", p->ass->HostName,
133         p->ass->Port);
134     ireq = InitRequest_CreateInitAllASCII(0, "yy", "yy", p->maxrecordsize,
135         p->preferredmessagesize, ZASS_ID, ZASS_NAME, ZASS_VERSION, 0);
136     if (!ireq)
137     {
138         gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create initrequest");
139         return 0;
140     }
141     zutil_GetBEREncodedBuffer(ireq, (unsigned char*)p->buf, &len,
142         p->maxrecordsize);
143     if (len <= 0)
144     {
145         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode initrequest");
146         return 0;
147     }
148     InitRequest_Destroy(ireq);
149     if (netbox_SendBuffer(p->ass, p->buf, len) != len)
150     {
151         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send initrequest");
152         return 0;
153     }
154     gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent initrequest.");
155     if ((len = zutil_GetBERFromNet(p->ass, (unsigned char*)p->buf,
156         p->maxrecordsize)) <= 0)
157     {
158         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive initresponse");
159         return 0;
160     }
161     ires = (PINITRESPONSE) zutil_CreateFromData((unsigned char*)p->buf, len);
162     if (InitResponse_GetTag(ires) != INITRESPONSE_TAG)
163     {
164         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected initresponse from target");
165         return 0;
166     }
167     gw_log(ZASS_DEBUG, ZASS_TYPE, "Got initresponse");
168     if (!InitResponse_GetResult(ires))
169     {
170         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Access to target denied.");
171         return 0;
172     }
173     gw_log(ZASS_DEBUG, ZASS_TYPE, "Connected OK");
174     p->preferredmessagesize = InitResponse_GetPreferredMessageSize(ires);
175     p->maxrecordsize = InitResponse_GetExceptionalRecordSize(ires);
176     InitResponse_Destroy(ires);
177     return p;
178 }
179
180 const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query,
181     char *resname, char *databases)
182 {
183     static struct zass_searchent r;
184     char kwaqs[512], *p;
185     DATA_DIR *pdu, *record;
186     int len;
187
188     p = kwaqs;
189     if (rpn2kwaqs(query, &p) < 0)
190     {
191         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode query");
192         return 0;
193     }
194     gw_log(ZASS_DEBUG, ZASS_TYPE, "Query: KWAQS: '%s'", kwaqs);
195     pdu = SearchRequest_CreateInitAllASCII(0, 0, 2, 0, 1, resname, databases,
196         0, 0, 0, kwaqs, BIB1_OID);
197     if (!pdu)
198     {
199         gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create searchrequest");
200         return 0;
201     }
202     zutil_GetBEREncodedBuffer(pdu, (unsigned char*)a->buf, &len,
203         a->maxrecordsize);
204     if (len <= 0)
205     {
206         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode initrequest");
207         return 0;
208     }
209     SearchRequest_Destroy(pdu);
210     if (netbox_SendBuffer(a->ass, a->buf, len) != len)
211     {
212         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send initrequest");
213         return 0;
214     }
215     gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent searchrequest.");
216     if ((len = zutil_GetBERFromNet(a->ass, (unsigned char*)a->buf,
217         a->maxrecordsize)) <= 0)
218     {
219         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive searchresponse");
220         return 0;
221     }
222     pdu = zutil_CreateFromData((unsigned char*)a->buf, len);
223     if (zutil_GetTag(pdu) != SEARCHRESPONSE_TAG)
224     {
225         gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected serchresponse from target");
226         return 0;
227     }
228     gw_log(ZASS_DEBUG, ZASS_TYPE, "Got searchresponse");
229     r.status = SearchResponse_GetSearchStatus(pdu);
230     r.num = SearchResponse_GetResultCount(pdu);
231     r.status = SearchResponse_GetResultSetStatus(pdu);
232     r.errcode = -1;
233     *r.errstring = '\0';
234     if ((record = SearchResponse_GetRecords(pdu)))
235     {
236         if (zutil_GetTag(record) == NONSURROGATEDIAGNOSTIC_TAG)
237         {
238             DATA_DIR *ad;
239
240             r.errcode = zutil_GetTaggedInt(record, ASN1_INTEGER);
241             if ((ad = zutil_GetTaggedObject(record, ASN1_VISIBLESTRING)))
242             {
243                 char *s;
244
245                 if ((s = OctetString_GetASCIIString(ad)))
246                 {
247                     strcpy(r.errstring, s);
248                     FREE(s);
249                 }
250             }
251         }
252         else
253             gw_log(GW_LOG_WARN, ZASS_TYPE, "Got real record in SRCHRESP");
254     }
255     SearchResponse_Destroy(pdu);
256
257     return &r;
258 }
259
260 /*
261  * Triple indirection - that's kinda heavy. We'll fix it later.
262  * There are worse things around, though. Like ZDist.
263  */
264 void get_diagrec(zass_record ***p, DATA_DIR *rec)
265 {
266     DATA_DIR *ad;
267
268     **p = malloc(sizeof(***p));
269     (**p)->next = 0;
270     (**p)->errcode = zutil_GetTaggedInt(rec, ASN1_INTEGER);
271     if ((ad = zutil_GetTaggedObject(rec, ASN1_VISIBLESTRING)))
272     {
273         char *s;
274
275         if ((s = OctetString_GetASCIIString(ad)))
276         {
277             strcpy((**p)->errstring, s);
278             FREE(s);
279         }
280     }
281     (**p)->which = ZASS_REC_DIAG;
282     *p = &(**p)->next;
283 }
284
285 void get_responserecords(zass_record ***p, DATA_DIR *rec)
286 {
287     int num, recsyntaxlen, i;
288     DATA_DIR *record, *retrec, *align;
289     PEXTERNAL ext;
290     POBJECTIDENTIFIER oid;
291     char recsyntax[256];
292
293     num = ResponseRecords_GetCount(rec);
294     for (i = 1; i <= num; i++)
295     {
296         record = ResponseRecords_GetRecord(rec, i);
297         if (!record)
298         {
299             gw_log(GW_LOG_WARN, ZASS_TYPE, "Failed to get record.");
300             return;
301         }
302         retrec = NamePlusRecord_GetRetrievalRecord(record);
303         if (!retrec)
304         {
305             /* check if it's a diagrec */
306             if (record->ptr.child->fldid == 2)
307                 get_diagrec(p, record->ptr.child);
308             else
309             {
310                 gw_log(GW_LOG_WARN, ZASS_TYPE, "Illegal record.");
311                 return;
312             }
313         }
314         ext = RetrievalRecord_GetExternal(retrec);
315         if (!ext)
316         {
317             gw_log(GW_LOG_WARN, ZASS_TYPE, "No external in record");
318             return;
319         }
320         oid = External_GetDirectReference(ext);
321         if (!oid)
322         {
323             gw_log(GW_LOG_WARN, ZASS_TYPE, "Unknown record type.");
324             return;
325         }
326         recsyntaxlen = DirectReference_GetLength(oid);
327         memcpy(recsyntax, DirectReference_GetData(oid), recsyntaxlen);
328         recsyntax[recsyntaxlen] = '\0';
329         **p = malloc(sizeof(***p));
330         (**p)->next = 0;
331         if (!strcmp(recsyntax, USMARC_OID))
332             (**p)->which = ZASS_REC_USMARC;
333         else
334         {
335             gw_log(GW_LOG_WARN, ZASS_TYPE, "ZLAYER only knows USMARC at this point.");
336             return;
337         }
338         align = External_GetEncodingAligned(ext);
339         if (!align)
340         {
341             gw_log(GW_LOG_WARN, ZASS_TYPE, "AAAARRRGH!! Enough of these log-messages!!!");
342             return;
343         }
344         if (!((**p)->record = malloc(align->count + 1)))
345         {
346             gw_log(GW_LOG_FATAL, ZASS_TYPE, "malloc");
347             return;
348         }
349         memcpy((**p)->record, align->ptr.data, align->count);
350         (**p)->record[align->count] = '\0';
351         gw_log(ZASS_DEBUG, ZASS_TYPE, "Got a record of %d bytes",
352             align->count);
353
354         (*p) = &(**p)->next;
355     }
356 }
357
358 static void zass_records_free(zass_record *p)
359 {
360 }
361
362 /*
363  * Note that 1== first record.
364  */
365 const struct zass_presentent *zass_present(ZASS a, char *resname, int start,
366     int num)
367 {
368     static struct zass_presentent r = {0, 0, 0, 0};
369     zass_record **rec = &r.records;
370     DATA_DIR *pdu;
371     int len;
372
373     r.num = 0;
374     if (r.records)
375     {
376         zass_records_free(r.records);
377         r.records = 0;
378     }
379     do
380     {
381         gw_log(ZASS_DEBUG, ZASS_TYPE, "Fetching %d records from # %d", num,
382             start);
383         pdu = PresentRequest_CreateInitAllASCII(0, resname, start, num, "F",
384             USMARC_OID);
385         if (!pdu)
386         {
387             gw_log(GW_LOG_FATAL, "ZASS_TYPE", "failed to create presentrequest");
388             return 0;
389         }
390         zutil_GetBEREncodedBuffer(pdu, (unsigned char*)a->buf, &len,
391             a->maxrecordsize);
392         if (len <= 0)
393         {
394             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to encode presentrequest");
395             return 0;
396         }
397         PresentRequest_Destroy(pdu);
398         if (netbox_SendBuffer(a->ass, a->buf, len) != len)
399         {
400             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send presentrequest");
401             return 0;
402         }
403         gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent presentrequest.");
404         if ((len = zutil_GetBERFromNet(a->ass, (unsigned char*)a->buf,
405             a->maxrecordsize)) <= 0)
406         {
407             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive presentresponse");
408             return 0;
409         }
410         pdu = zutil_CreateFromData((unsigned char*)a->buf, len);
411         if (zutil_GetTag(pdu) != PRESENTRESPONSE_TAG)
412         {
413             gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected presentresponse from target");
414             return 0;
415         }
416         gw_log(ZASS_DEBUG, ZASS_TYPE, "Got presentresponse");
417         r.num = PresentResponse_GetNumberOfRecordsReturned(pdu);
418         if (r.num == 0)
419         {
420             gw_log(GW_LOG_WARN, ZASS_TYPE, "Got 0 records from target.");
421             return 0;
422         }
423         r.nextpos = PresentResponse_GetNextResultSetPosition(pdu);
424         start += r.nextpos;
425         num -= r.num;
426         switch(PresentResponse_GetRecordType(pdu))
427         {
428             case RESPONSERECORDS_TAG:
429                 get_responserecords(&rec, PresentResponse_GetResponseRecords(pdu));
430                 break;
431             case NONSURROGATEDIAGNOSTIC_TAG:
432                 get_diagrec(&rec, PresentResponse_GetNonSurrogateDiagnostic(pdu));
433                 break;
434             default:
435                 gw_log(GW_LOG_WARN, ZASS_TYPE, "Bad tag in response rec.");
436         }
437         *rec = 0;
438     }
439     while (num);
440     PresentResponse_Destroy(pdu);
441         
442     return &r;
443 }