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