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