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