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