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