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