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