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