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