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