Implemented ILL protocol. Minor updates ASN.1 compiler.
[yaz-moved-to-github.git] / ztest / ztest.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * NT Service interface by
7  *    Chas Woodfield, Fretwell Downing Datasystems.
8  *
9  * $Log: ztest.c,v $
10  * Revision 1.28  1999-12-16 23:36:19  adam
11  * Implemented ILL protocol. Minor updates ASN.1 compiler.
12  *
13  * Revision 1.27  1999/11/30 13:47:12  adam
14  * Improved installation. Moved header files to include/yaz.
15  *
16  * Revision 1.26  1999/08/27 09:40:32  adam
17  * Renamed logf function to yaz_log. Removed VC++ project files.
18  *
19  * Revision 1.25  1999/06/01 14:29:12  adam
20  * Work on Extended Services.
21  *
22  * Revision 1.24  1999/05/27 13:07:54  adam
23  * Fix.
24  *
25  * Revision 1.23  1999/05/27 13:02:20  adam
26  * Assigned OID for old DB Update (VAL_DBUPDATE0).
27  *
28  * Revision 1.22  1999/05/26 13:49:12  adam
29  * DB Update implemented in client (very basic).
30  *
31  * Revision 1.21  1998/12/15 12:45:42  adam
32  * Minor change.
33  *
34  * Revision 1.20  1998/12/14 14:48:05  adam
35  * Fixed memory leak - happened when fetching MARC records.
36  *
37  * Revision 1.19  1998/10/20 15:16:22  adam
38  * Minor change to prevent warning.
39  *
40  * Revision 1.18  1998/10/20 15:13:45  adam
41  * Minor fix regarding output for Item Order.
42  *
43  * Revision 1.17  1998/10/18 22:33:35  quinn
44  * Added diagnostic dump of Item Order Eservice.
45  *
46  * Revision 1.16  1998/10/15 08:26:23  adam
47  * Added type cast to make C++ happy.
48  *
49  * Revision 1.15  1998/10/13 20:05:57  adam
50  * Minor change.
51  *
52  * Revision 1.14  1998/10/13 16:12:25  adam
53  * Added support for Surrogate Diagnostics for Scan Term entries.
54  *
55  * Revision 1.13  1998/08/19 16:10:09  adam
56  * Changed som member names of DeleteResultSetRequest/Response.
57  *
58  * Revision 1.12  1998/07/20 12:38:44  adam
59  * Implemented delete result set service to server API.
60  *
61  * Revision 1.11  1998/06/09 13:55:08  adam
62  * Minor changes.
63  *
64  * Revision 1.10  1998/05/27 16:55:54  adam
65  * Minor changes.
66  *
67  * Revision 1.9  1998/03/31 11:07:45  adam
68  * Furhter work on UNIverse resource report.
69  * Added Extended Services handling in frontend server.
70  *
71  * Revision 1.8  1998/02/11 11:53:36  adam
72  * Changed code so that it compiles as C++.
73  *
74  * Revision 1.7  1998/02/10 11:03:57  adam
75  * Added support for extended handlers in backend server interface.
76  *
77  * Revision 1.6  1998/01/29 13:16:02  adam
78  * Added dummy sort in test server.
79  *
80  * Revision 1.5  1997/11/07 13:31:58  adam
81  * Added NT Service name part of statserv_options_block. Moved NT
82  * service utility to server library.
83  *
84  * Revision 1.4  1997/09/17 12:10:43  adam
85  * YAZ version 1.4.
86  *
87  * Revision 1.3  1997/09/09 10:10:20  adam
88  * Another MSV5.0 port. Changed projects to include proper
89  * library/include paths.
90  * Server starts server in test-mode when no options are given.
91  *
92  * Revision 1.2  1997/09/04 13:50:31  adam
93  * Bug fix in ztest.
94  *
95  */
96
97 /*
98  * Demonstration of simple server
99  */
100
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include <ctype.h>
104 #include <assert.h>
105
106 #include <yaz/backend.h>
107 #include <yaz/log.h>
108
109 #ifdef ASN_COMPILED
110 #include <yaz/ill.h>
111 #endif
112
113 Z_GenericRecord *read_grs1(FILE *f, ODR o);
114
115 int ztest_search (void *handle, bend_search_rr *rr);
116 int ztest_sort (void *handle, bend_sort_rr *rr);
117 int ztest_present (void *handle, bend_present_rr *rr);
118 int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
119 int ztest_delete (void *handle, bend_delete_rr *rr);
120
121 bend_initresult *bend_init(bend_initrequest *q)
122 {
123     bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
124     static char *dummy = "Hej fister";
125
126     r->errcode = 0;
127     r->errstring = 0;
128     r->handle = dummy;
129     q->bend_sort = ztest_sort;       /* register sort handler */
130     q->bend_search = ztest_search;   /* register search handler */
131     q->bend_present = ztest_present; /* register present handle */
132     q->bend_esrequest = ztest_esrequest;
133     q->bend_delete = ztest_delete;
134     return r;
135 }
136
137 int ztest_search (void *handle, bend_search_rr *rr)
138 {
139     rr->hits = rand() % 22;
140     return 0;
141 }
142
143 int ztest_present (void *handle, bend_present_rr *rr)
144 {
145     return 0;
146 }
147
148 int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
149 {
150     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
151     if (rr->esr->packageName)
152         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
153     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
154
155     if (!rr->esr->taskSpecificParameters)
156     {
157         yaz_log (LOG_WARN, "No task specific parameters");
158     }
159     else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
160     {
161         Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
162         yaz_log (LOG_LOG, "Received ItemOrder");
163         switch (it->which)
164         {
165 #ifdef ASN_COMPILED
166         case Z_IOItemOrder_esRequest:
167 #else
168         case Z_ItemOrder_esRequest:
169 #endif
170         {
171             Z_IORequest *ir = it->u.esRequest;
172             Z_IOOriginPartToKeep *k = ir->toKeep;
173             Z_IOOriginPartNotToKeep *n = ir->notToKeep;
174             
175             if (k && k->contact)
176             {
177                 if (k->contact->name)
178                     yaz_log(LOG_LOG, "contact name %s", k->contact->name);
179                 if (k->contact->phone)
180                     yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
181                 if (k->contact->email)
182                     yaz_log(LOG_LOG, "contact email %s", k->contact->email);
183             }
184             if (k->addlBilling)
185             {
186                 yaz_log(LOG_LOG, "Billing info (not shown)");
187             }
188             
189             if (n->resultSetItem)
190             {
191                 yaz_log(LOG_LOG, "resultsetItem");
192                 yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
193                 yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
194             }
195 #ifdef ASN_COMPILED
196             if (n->itemRequest)
197             {
198                 Z_External *r = (Z_External*) n->itemRequest;
199                 ILL_ItemRequest *item_req = 0;
200                 if (r->direct_reference)
201                 {
202                     oident *ent = oid_getentbyoid(r->direct_reference);
203                     if (ent)
204                         yaz_log(LOG_LOG, "ItemRequest %s", ent->desc);
205                     if (ent && ent->value == VAL_ISO_ILL_1)
206                     {
207                         if (r->which == ODR_EXTERNAL_single)
208                         {
209                             odr_setbuf(rr->decode,
210                                        r->u.single_ASN1_type->buf,
211                                        r->u.single_ASN1_type->len, 0);
212                             
213                             ill_ItemRequest (rr->decode, &item_req, 0, 0);
214                         }
215                     }
216                 }
217                 if (item_req)
218                 {
219                     yaz_log (LOG_LOG, "ILL protocol version = %d",
220                              *item_req->protocol_version_num);
221                 }
222             }
223 #endif
224         }
225         break;
226         }
227     }
228     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
229     {
230         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
231         yaz_log (LOG_LOG, "Received DB Update");
232         if (up->which == Z_IUUpdate_esRequest)
233         {
234             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
235             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
236             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
237             
238             yaz_log (LOG_LOG, "action");
239             if (toKeep->action)
240             {
241                 switch (*toKeep->action)
242                 {
243                 case Z_IUOriginPartToKeep_recordInsert:
244                     yaz_log (LOG_LOG, " recordInsert");
245                     break;
246                 case Z_IUOriginPartToKeep_recordReplace:
247                     yaz_log (LOG_LOG, " recordUpdate");
248                     break;
249                 case Z_IUOriginPartToKeep_recordDelete:
250                     yaz_log (LOG_LOG, " recordDelete");
251                     break;
252                 case Z_IUOriginPartToKeep_elementUpdate:
253                     yaz_log (LOG_LOG, " elementUpdate");
254                     break;
255                 case Z_IUOriginPartToKeep_specialUpdate:
256                     yaz_log (LOG_LOG, " specialUpdate");
257                     break;
258                 default:
259                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
260                 }
261             }
262             if (toKeep->databaseName)
263             {
264                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
265                 if (!strcmp(toKeep->databaseName, "fault"))
266                 {
267                     rr->errcode = 109;
268                     rr->errstring = toKeep->databaseName;
269                 }
270                 if (!strcmp(toKeep->databaseName, "accept"))
271                     rr->errcode = -1;
272             }
273             if (notToKeep)
274             {
275                 int i;
276                 for (i = 0; i < notToKeep->num; i++)
277                 {
278                     Z_External *rec = notToKeep->elements[i]->record;
279
280                     if (rec->direct_reference)
281                     {
282                         struct oident *oident;
283                         oident = oid_getentbyoid(rec->direct_reference);
284                         if (oident)
285                             yaz_log (LOG_LOG, "record %d type %s", i,
286                                      oident->desc);
287                     }
288                     switch (rec->which)
289                     {
290                     case Z_External_sutrs:
291                         if (rec->u.octet_aligned->len > 170)
292                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
293                                      rec->u.sutrs->len,
294                                      rec->u.sutrs->buf);
295                         else
296                             yaz_log (LOG_LOG, "%d bytes:\n%s",
297                                      rec->u.sutrs->len,
298                                      rec->u.sutrs->buf);
299                         break;
300                     case Z_External_octet        :
301                         if (rec->u.octet_aligned->len > 170)
302                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
303                                      rec->u.octet_aligned->len,
304                                      rec->u.octet_aligned->buf);
305                         else
306                             yaz_log (LOG_LOG, "%d bytes\n%s",
307                                      rec->u.octet_aligned->len,
308                                      rec->u.octet_aligned->buf);
309                     }
310                 }
311             }
312         }
313     }
314     else
315     {
316         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
317                  rr->esr->taskSpecificParameters->which);
318         
319     }
320     return 0;
321 }
322
323 int ztest_delete (void *handle, bend_delete_rr *rr)
324 {
325     if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
326         rr->delete_status = Z_DeleteStatus_success;
327     else
328         rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
329     return 0;
330 }
331
332 /* Obsolete bend_search, never called because handler is registered */
333 bend_searchresult *bend_search(void *handle, bend_searchrequest *q, int *fd)
334 {
335     return 0;
336 }
337
338 /* Our sort handler really doesn't sort... */
339 int ztest_sort (void *handle, bend_sort_rr *rr)
340 {
341     rr->errcode = 0;
342     rr->sort_status = Z_SortStatus_success;
343     return 0;
344 }
345
346 static int atoin (const char *buf, int n)
347 {
348     int val = 0;
349     while (--n >= 0)
350     {
351         if (isdigit(*buf))
352             val = val*10 + (*buf - '0');
353         buf++;
354     }
355     return val;
356 }
357
358 char *marc_read(FILE *inf, ODR odr)
359 {
360     char length_str[5];
361     size_t size;
362     char *buf;
363
364     if (fread (length_str, 1, 5, inf) != 5)
365         return NULL;
366     size = atoin (length_str, 5);
367     if (size <= 6)
368         return NULL;
369     if (!(buf = (char*) odr_malloc (odr, size+1)))
370         return NULL;
371     if (fread (buf+5, 1, size-5, inf) != (size-5))
372     {
373         xfree (buf);
374         return NULL;
375     }
376     memcpy (buf, length_str, 5);
377     buf[size] = '\0';
378     return buf;
379 }
380
381 static char *dummy_database_record (int num, ODR odr)
382 {
383     FILE *inf = fopen ("dummy-records", "r");
384     char *buf = 0;
385
386     if (!inf)
387         return NULL;
388     while (--num >= 0)
389     {
390         if (num == 98)
391         {
392             buf = (char*) odr_malloc(odr, 2101);
393             assert(buf);
394             memset(buf, 'A', 2100);
395             buf[2100] = '\0';
396             break;
397         }
398         else
399             buf = marc_read (inf, odr);
400         if (!num || !buf)
401             break;
402     }
403     fclose(inf);
404     if (num < 0)
405         return 0;
406     return buf;
407 }
408
409 static Z_GenericRecord *dummy_grs_record (int num, ODR o)
410 {
411     FILE *f = fopen("dummy-grs", "r");
412     char line[512];
413     Z_GenericRecord *r = 0;
414     int n;
415
416     if (!f)
417         return 0;
418     while (fgets(line, 512, f))
419         if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
420         {
421             r = read_grs1(f, o);
422             break;
423         }
424     fclose(f);
425     return r;
426 }
427
428 bend_fetchresult *bend_fetch(void *handle, bend_fetchrequest *q, int *fd)
429 {
430     bend_fetchresult *r = (bend_fetchresult *)
431                         odr_malloc (q->stream, sizeof(*r));
432     char *cp;
433     r->errstring = 0;
434     r->last_in_set = 0;
435     r->basename = "DUMMY";
436     r->format = q->format;  
437     if (q->format == VAL_SUTRS)
438     {
439         char buf[100];
440
441         sprintf(buf, "This is dummy SUTRS record number %d\n", q->number);
442         r->len = strlen(buf);
443         r->record = (char *) odr_malloc (q->stream, r->len+1);
444         strcpy(r->record, buf);
445     }
446     else if (q->format == VAL_GRS1)
447     {
448         r->len = -1;
449         r->record = (char*) dummy_grs_record(q->number, q->stream);
450         if (!r->record)
451         {
452             r->errcode = 13;
453             return r;
454         }
455     }
456     else if ((cp = dummy_database_record(q->number, q->stream)))
457     {
458         r->len = strlen(cp);
459         r->record = cp;
460         r->format = VAL_USMARC;
461     }
462     else
463     {
464         r->errcode = 13;
465         return r;
466     }
467     r->errcode = 0;
468     return r;
469 }
470
471 /*
472  * silly dummy-scan what reads words from a file.
473  */
474 bend_scanresult *bend_scan(void *handle, bend_scanrequest *q, int *fd)
475 {
476     bend_scanresult *r = (bend_scanresult *)
477         odr_malloc (q->stream, sizeof(*r));
478     static FILE *f = 0;
479     static struct scan_entry list[200];
480     static char entries[200][80];
481     int hits[200];
482     char term[80], *p;
483     int i, pos;
484
485     r->errcode = 0;
486     r->errstring = 0;
487     r->entries = list;
488     r->status = BEND_SCAN_SUCCESS;
489     if (!f && !(f = fopen("dummy-words", "r")))
490     {
491         perror("dummy-words");
492         exit(1);
493     }
494     if (q->term->term->which != Z_Term_general)
495     {
496         r->errcode = 229; /* unsupported term type */
497         return r;
498     }
499     if (q->term->term->u.general->len >= 80)
500     {
501         r->errcode = 11; /* term too long */
502         return r;
503     }
504     if (q->num_entries > 200)
505     {
506         r->errcode = 31;
507         return r;
508     }
509     memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
510     term[q->term->term->u.general->len] = '\0';
511     for (p = term; *p; p++)
512         if (islower(*p))
513             *p = toupper(*p);
514
515     fseek(f, 0, SEEK_SET);
516     r->num_entries = 0;
517     for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
518         i++, pos < 199 ? pos++ : (pos = 0))
519     {
520         if (!r->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
521         {
522             if ((r->term_position = q->term_position) > i + 1)
523             {
524                 r->term_position = i + 1;
525                 r->status = BEND_SCAN_PARTIAL;
526             }
527             for (; r->num_entries < r->term_position; r->num_entries++)
528             {
529                 int po;
530
531                 po = pos - r->term_position + r->num_entries + 1; /* find pos */
532                 if (po < 0)
533                     po += 200;
534
535                 if (!strcmp (term, "SD") && r->num_entries == 2)
536                 {
537                     list[r->num_entries].term = entries[pos];
538                     list[r->num_entries].occurrences = -1;
539                     list[r->num_entries].errcode = 233;
540                     list[r->num_entries].errstring = "SD for Scan Term";
541                 }
542                 else
543                 {
544                     list[r->num_entries].term = entries[po];
545                     list[r->num_entries].occurrences = hits[po];
546                 }
547             }
548         }
549         else if (r->num_entries)
550         {
551             list[r->num_entries].term = entries[pos];
552             list[r->num_entries].occurrences = hits[pos];
553             r->num_entries++;
554         }
555         if (r->num_entries >= q->num_entries)
556             break;
557     }
558     if (feof(f))
559         r->status = BEND_SCAN_PARTIAL;
560     return r;
561 }
562
563 void bend_close(void *handle)
564 {
565     return;
566 }
567
568 int main(int argc, char **argv)
569 {
570     return statserv_main(argc, argv);
571 }