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