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