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