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