7374c3f3b13e25f05866cf01e1622d07be63828c
[yaz-moved-to-github.git] / ztest / ztest.c
1 /*
2  * Copyright (c) 1995-2002, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: ztest.c,v 1.48 2002-01-17 23:22:40 adam Exp $
6  */
7
8 /*
9  * Demonstration of simple server
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15
16 #include <yaz/backend.h>
17 #include <yaz/log.h>
18
19 #if YAZ_MODULE_ill
20 #include <yaz/ill.h>
21 #endif
22
23 Z_GenericRecord *read_grs1(FILE *f, ODR o);
24
25 int ztest_search (void *handle, bend_search_rr *rr);
26 int ztest_sort (void *handle, bend_sort_rr *rr);
27 int ztest_present (void *handle, bend_present_rr *rr);
28 int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
29 int ztest_delete (void *handle, bend_delete_rr *rr);
30
31 int ztest_search (void *handle, bend_search_rr *rr)
32 {
33     if (rr->num_bases != 1)
34     {
35         rr->errcode = 23;
36         return 0;
37     }
38     if (strcmp (rr->basenames[0], "Default"))
39     {
40         rr->errcode = 109;
41         rr->errstring = rr->basenames[0];
42         return 0;
43     }
44     rr->hits = rand() % 22;
45     return 0;
46 }
47
48 int ztest_present (void *handle, bend_present_rr *rr)
49 {
50     return 0;
51 }
52
53 int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
54 {
55     /* user-defined handle - created in bend_init */
56     int *counter = (int*) handle;  
57
58     yaz_log(LOG_LOG, "ESRequest no %d", *counter);
59
60     (*counter)++;
61
62     if (rr->esr->packageName)
63         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
64     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
65
66
67     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
68
69     if (!rr->esr->taskSpecificParameters)
70     {
71         yaz_log (LOG_WARN, "No task specific parameters");
72     }
73     else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
74     {
75         Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
76         yaz_log (LOG_LOG, "Received ItemOrder");
77         if (it->which == Z_IOItemOrder_esRequest)
78         {
79             Z_IORequest *ir = it->u.esRequest;
80             Z_IOOriginPartToKeep *k = ir->toKeep;
81             Z_IOOriginPartNotToKeep *n = ir->notToKeep;
82             
83             if (k && k->contact)
84             {
85                 if (k->contact->name)
86                     yaz_log(LOG_LOG, "contact name %s", k->contact->name);
87                 if (k->contact->phone)
88                     yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
89                 if (k->contact->email)
90                     yaz_log(LOG_LOG, "contact email %s", k->contact->email);
91             }
92             if (k->addlBilling)
93             {
94                 yaz_log(LOG_LOG, "Billing info (not shown)");
95             }
96             
97             if (n->resultSetItem)
98             {
99                 yaz_log(LOG_LOG, "resultsetItem");
100                 yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
101                 yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
102             }
103 #if YAZ_MODULE_ill
104             if (n->itemRequest)
105             {
106                 Z_External *r = (Z_External*) n->itemRequest;
107                 ILL_ItemRequest *item_req = 0;
108                 ILL_APDU *ill_apdu = 0;
109                 if (r->direct_reference)
110                 {
111                     oident *ent = oid_getentbyoid(r->direct_reference);
112                     if (ent)
113                         yaz_log(LOG_LOG, "OID %s", ent->desc);
114                     if (ent && ent->value == VAL_TEXT_XML)
115                     {
116                         yaz_log (LOG_LOG, "ILL XML request");
117                         if (r->which == Z_External_octet)
118                             yaz_log (LOG_LOG, "%.*s", r->u.octet_aligned->len,
119                                      r->u.octet_aligned->buf); 
120                     }
121                     if (ent && ent->value == VAL_ISO_ILL_1)
122                     {
123                         yaz_log (LOG_LOG, "Decode ItemRequest begin");
124                         if (r->which == ODR_EXTERNAL_single)
125                         {
126                             odr_setbuf(rr->decode,
127                                        (char *) r->u.single_ASN1_type->buf,
128                                        r->u.single_ASN1_type->len, 0);
129                             
130                             if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
131                             {
132                                 yaz_log (LOG_LOG,
133                                     "Couldn't decode ItemRequest %s near %d",
134                                        odr_errmsg(odr_geterror(rr->decode)),
135                                        odr_offset(rr->decode));
136 #if 0
137                                 yaz_log(LOG_LOG, "PDU dump:");
138                                 odr_dumpBER(yaz_log_file(),
139                                      r->u.single_ASN1_type->buf,
140                                      r->u.single_ASN1_type->len);
141 #endif
142                             }
143                             else
144                                 yaz_log(LOG_LOG, "Decode ItemRequest OK");
145                             if (rr->print)
146                             {
147                                 ill_ItemRequest (rr->print, &item_req, 0,
148                                     "ItemRequest");
149                                 odr_reset (rr->print);
150                             }
151                         }
152                         if (!item_req && r->which == ODR_EXTERNAL_single)
153                         {
154                             yaz_log (LOG_LOG, "Decode ILL APDU begin");
155                             odr_setbuf(rr->decode,
156                                        (char*) r->u.single_ASN1_type->buf,
157                                        r->u.single_ASN1_type->len, 0);
158                             
159                             if (!ill_APDU (rr->decode, &ill_apdu, 0, 0))
160                             {
161                                 yaz_log (LOG_LOG,
162                                     "Couldn't decode ILL APDU %s near %d",
163                                        odr_errmsg(odr_geterror(rr->decode)),
164                                        odr_offset(rr->decode));
165                                 yaz_log(LOG_LOG, "PDU dump:");
166                                 odr_dumpBER(yaz_log_file(),
167                                      (char *) r->u.single_ASN1_type->buf,
168                                      r->u.single_ASN1_type->len);
169                             }
170                             else
171                                 yaz_log(LOG_LOG, "Decode ILL APDU OK");
172                             if (rr->print)
173                             {
174                                 ill_APDU (rr->print, &ill_apdu, 0,
175                                     "ILL APDU");
176                                 odr_reset (rr->print);
177                             }
178                         }
179                     }
180                 }
181                 if (item_req)
182                 {
183                     yaz_log (LOG_LOG, "ILL protocol version = %d",
184                              *item_req->protocol_version_num);
185                 }
186             }
187 #endif
188             if (k)
189             {
190
191                 Z_External *ext = (Z_External *)
192                     odr_malloc (rr->stream, sizeof(*ext));
193                 Z_IUOriginPartToKeep *keep = (Z_IUOriginPartToKeep *)
194                     odr_malloc (rr->stream, sizeof(*keep));
195                 Z_IOTargetPart *targetPart = (Z_IOTargetPart *)
196                     odr_malloc (rr->stream, sizeof(*targetPart));
197
198                 rr->taskPackage = (Z_TaskPackage *)
199                     odr_malloc (rr->stream, sizeof(*rr->taskPackage));
200                 rr->taskPackage->packageType =
201                     odr_oiddup (rr->stream, rr->esr->packageType);
202                 rr->taskPackage->packageName = 0;
203                 rr->taskPackage->userId = 0;
204                 rr->taskPackage->retentionTime = 0;
205                 rr->taskPackage->permissions = 0;
206                 rr->taskPackage->description = 0;
207                 rr->taskPackage->targetReference = (Odr_oct *)
208                     odr_malloc (rr->stream, sizeof(Odr_oct));
209                 rr->taskPackage->targetReference->buf =
210                     (unsigned char *) odr_strdup (rr->stream, "911");
211                 rr->taskPackage->targetReference->len =
212                     rr->taskPackage->targetReference->size =
213                     strlen((char *) (rr->taskPackage->targetReference->buf));
214                 rr->taskPackage->creationDateTime = 0;
215                 rr->taskPackage->taskStatus = odr_intdup(rr->stream, 0);
216                 rr->taskPackage->packageDiagnostics = 0;
217                 rr->taskPackage->taskSpecificParameters = ext;
218
219                 ext->direct_reference =
220                     odr_oiddup (rr->stream, rr->esr->packageType);
221                 ext->indirect_reference = 0;
222                 ext->descriptor = 0;
223                 ext->which = Z_External_itemOrder;
224                 ext->u.itemOrder = (Z_ItemOrder *)
225                     odr_malloc (rr->stream, sizeof(*ext->u.update));
226                 ext->u.itemOrder->which = Z_IOItemOrder_taskPackage;
227                 ext->u.itemOrder->u.taskPackage =  (Z_IOTaskPackage *)
228                     odr_malloc (rr->stream, sizeof(Z_IOTaskPackage));
229                 ext->u.itemOrder->u.taskPackage->originPart = k;
230                 ext->u.itemOrder->u.taskPackage->targetPart = targetPart;
231
232                 targetPart->itemRequest = 0;
233                 targetPart->statusOrErrorReport = 0;
234                 targetPart->auxiliaryStatus = 0;
235             }
236         }
237     }
238     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
239     {
240         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
241         yaz_log (LOG_LOG, "Received DB Update");
242         if (up->which == Z_IUUpdate_esRequest)
243         {
244             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
245             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
246             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
247             
248             yaz_log (LOG_LOG, "action");
249             if (toKeep->action)
250             {
251                 switch (*toKeep->action)
252                 {
253                 case Z_IUOriginPartToKeep_recordInsert:
254                     yaz_log (LOG_LOG, " recordInsert");
255                     break;
256                 case Z_IUOriginPartToKeep_recordReplace:
257                     yaz_log (LOG_LOG, " recordReplace");
258                     break;
259                 case Z_IUOriginPartToKeep_recordDelete:
260                     yaz_log (LOG_LOG, " recordDelete");
261                     break;
262                 case Z_IUOriginPartToKeep_elementUpdate:
263                     yaz_log (LOG_LOG, " elementUpdate");
264                     break;
265                 case Z_IUOriginPartToKeep_specialUpdate:
266                     yaz_log (LOG_LOG, " specialUpdate");
267                     break;
268                 default:
269                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
270                 }
271             }
272             if (toKeep->databaseName)
273             {
274                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
275                 if (!strcmp(toKeep->databaseName, "fault"))
276                 {
277                     rr->errcode = 109;
278                     rr->errstring = toKeep->databaseName;
279                 }
280                 if (!strcmp(toKeep->databaseName, "accept"))
281                     rr->errcode = -1;
282             }
283             if (toKeep)
284             {
285                 Z_External *ext = (Z_External *)
286                     odr_malloc (rr->stream, sizeof(*ext));
287                 Z_IUOriginPartToKeep *keep = (Z_IUOriginPartToKeep *)
288                     odr_malloc (rr->stream, sizeof(*keep));
289                 Z_IUTargetPart *targetPart = (Z_IUTargetPart *)
290                     odr_malloc (rr->stream, sizeof(*targetPart));
291
292                 rr->taskPackage = (Z_TaskPackage *)
293                     odr_malloc (rr->stream, sizeof(*rr->taskPackage));
294                 rr->taskPackage->packageType =
295                     odr_oiddup (rr->stream, rr->esr->packageType);
296                 rr->taskPackage->packageName = 0;
297                 rr->taskPackage->userId = 0;
298                 rr->taskPackage->retentionTime = 0;
299                 rr->taskPackage->permissions = 0;
300                 rr->taskPackage->description = 0;
301                 rr->taskPackage->targetReference = (Odr_oct *)
302                     odr_malloc (rr->stream, sizeof(Odr_oct));
303                 rr->taskPackage->targetReference->buf =
304                     (unsigned char *) odr_strdup (rr->stream, "123");
305                 rr->taskPackage->targetReference->len =
306                     rr->taskPackage->targetReference->size =
307                     strlen((char *) (rr->taskPackage->targetReference->buf));
308                 rr->taskPackage->creationDateTime = 0;
309                 rr->taskPackage->taskStatus = odr_intdup(rr->stream, 0);
310                 rr->taskPackage->packageDiagnostics = 0;
311                 rr->taskPackage->taskSpecificParameters = ext;
312
313                 ext->direct_reference =
314                     odr_oiddup (rr->stream, rr->esr->packageType);
315                 ext->indirect_reference = 0;
316                 ext->descriptor = 0;
317                 ext->which = Z_External_update;
318                 ext->u.update = (Z_IUUpdate *)
319                     odr_malloc (rr->stream, sizeof(*ext->u.update));
320                 ext->u.update->which = Z_IUUpdate_taskPackage;
321                 ext->u.update->u.taskPackage =  (Z_IUUpdateTaskPackage *)
322                     odr_malloc (rr->stream, sizeof(Z_IUUpdateTaskPackage));
323                 ext->u.update->u.taskPackage->originPart = keep;
324                 ext->u.update->u.taskPackage->targetPart = targetPart;
325
326                 keep->action = (int *) odr_malloc (rr->stream, sizeof(int));
327                 *keep->action = *toKeep->action;
328                 keep->databaseName =
329                     odr_strdup (rr->stream, toKeep->databaseName);
330                 keep->schema = 0;
331                 keep->elementSetName = 0;
332                 keep->actionQualifier = 0;
333
334                 targetPart->updateStatus = odr_intdup (rr->stream, 1);
335                 targetPart->num_globalDiagnostics = 0;
336                 targetPart->globalDiagnostics = (Z_DiagRec **) odr_nullval();
337                 targetPart->num_taskPackageRecords = 0;
338                 targetPart->taskPackageRecords =
339                     (Z_IUTaskPackageRecordStructure **) odr_nullval();
340             }
341             if (notToKeep)
342             {
343                 int i;
344                 for (i = 0; i < notToKeep->num; i++)
345                 {
346                     Z_External *rec = notToKeep->elements[i]->record;
347
348                     if (rec->direct_reference)
349                     {
350                         struct oident *oident;
351                         oident = oid_getentbyoid(rec->direct_reference);
352                         if (oident)
353                             yaz_log (LOG_LOG, "record %d type %s", i,
354                                      oident->desc);
355                     }
356                     switch (rec->which)
357                     {
358                     case Z_External_sutrs:
359                         if (rec->u.octet_aligned->len > 170)
360                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
361                                      rec->u.sutrs->len,
362                                      rec->u.sutrs->buf);
363                         else
364                             yaz_log (LOG_LOG, "%d bytes:\n%s",
365                                      rec->u.sutrs->len,
366                                      rec->u.sutrs->buf);
367                         break;
368                     case Z_External_octet        :
369                         if (rec->u.octet_aligned->len > 170)
370                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
371                                      rec->u.octet_aligned->len,
372                                      rec->u.octet_aligned->buf);
373                         else
374                             yaz_log (LOG_LOG, "%d bytes\n%s",
375                                      rec->u.octet_aligned->len,
376                                      rec->u.octet_aligned->buf);
377                     }
378                 }
379             }
380         }
381     }
382     else
383     {
384         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
385                  rr->esr->taskSpecificParameters->which);
386         
387     }
388     return 0;
389 }
390
391 int ztest_delete (void *handle, bend_delete_rr *rr)
392 {
393     if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
394         rr->delete_status = Z_DeleteStatus_success;
395     else
396         rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
397     return 0;
398 }
399
400 /* Our sort handler really doesn't sort... */
401 int ztest_sort (void *handle, bend_sort_rr *rr)
402 {
403     rr->errcode = 0;
404     rr->sort_status = Z_SortStatus_success;
405     return 0;
406 }
407
408 static int atoin (const char *buf, int n)
409 {
410     int val = 0;
411     while (--n >= 0)
412     {
413         if (isdigit(*buf))
414             val = val*10 + (*buf - '0');
415         buf++;
416     }
417     return val;
418 }
419
420 char *marc_read(FILE *inf, ODR odr)
421 {
422     char length_str[5];
423     size_t size;
424     char *buf;
425
426     if (fread (length_str, 1, 5, inf) != 5)
427         return NULL;
428     size = atoin (length_str, 5);
429     if (size <= 6)
430         return NULL;
431     if (!(buf = (char*) odr_malloc (odr, size+1)))
432         return NULL;
433     if (fread (buf+5, 1, size-5, inf) != (size-5))
434     {
435         xfree (buf);
436         return NULL;
437     }
438     memcpy (buf, length_str, 5);
439     buf[size] = '\0';
440     return buf;
441 }
442
443 static char *dummy_database_record (int num, ODR odr)
444 {
445     FILE *inf = fopen ("dummy-records", "r");
446     char *buf = 0;
447
448     if (!inf)
449         return NULL;
450     if (num == 98) 
451     {   /* this will generate a very bad MARC record (testing only) */
452         buf = (char*) odr_malloc(odr, 2101);
453         memset(buf, '7', 2100);
454         buf[2100] = '\0';
455     }
456     else
457     {
458         /* OK, try to get proper MARC records from the file */
459         while (--num >= 0)
460         {
461             buf = marc_read (inf, odr);
462             if (!buf)
463                 break;
464         }
465     }
466     fclose(inf);
467     return buf;
468 }
469
470 static Z_GenericRecord *dummy_grs_record (int num, ODR o)
471 {
472     FILE *f = fopen("dummy-grs", "r");
473     char line[512];
474     Z_GenericRecord *r = 0;
475     int n;
476
477     if (!f)
478         return 0;
479     while (fgets(line, 512, f))
480         if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
481         {
482             r = read_grs1(f, o);
483             break;
484         }
485     fclose(f);
486     return r;
487 }
488
489 int ztest_fetch(void *handle, bend_fetch_rr *r)
490 {
491     char *cp;
492     r->errstring = 0;
493     r->last_in_set = 0;
494     r->basename = "DUMMY";
495     r->output_format = r->request_format;  
496     if (r->request_format == VAL_SUTRS)
497     {
498 #if 0
499 /* this section returns a huge record (for testing non-blocking write, etc) */
500         r->len = 980000;
501         r->record = odr_malloc (r->stream, r->len);
502         memset (r->record, 'x', r->len);
503 #else
504 /* this section returns a small record */
505         char buf[100];
506
507         sprintf(buf, "This is dummy SUTRS record number %d\n", r->number);
508
509         r->len = strlen(buf);
510         r->record = (char *) odr_malloc (r->stream, r->len+1);
511         strcpy(r->record, buf);
512 #endif
513     }
514     else if (r->request_format == VAL_GRS1)
515     {
516         r->len = -1;
517         r->record = (char*) dummy_grs_record(r->number, r->stream);
518         if (!r->record)
519         {
520             r->errcode = 13;
521             return 0;
522         }
523     }
524     else if ((cp = dummy_database_record(r->number, r->stream)))
525     {
526         r->len = strlen(cp);
527         r->record = cp;
528         r->output_format = VAL_USMARC;
529     }
530     else
531     {
532         r->errcode = 13;
533         return 0;
534     }
535     r->errcode = 0;
536     return 0;
537 }
538
539 /*
540  * silly dummy-scan what reads words from a file.
541  */
542 int ztest_scan(void *handle, bend_scan_rr *q)
543 {
544     static FILE *f = 0;
545     static struct scan_entry list[200];
546     static char entries[200][80];
547     int hits[200];
548     char term[80], *p;
549     int i, pos;
550     int term_position_req = q->term_position;
551     int num_entries_req = q->num_entries;
552
553     q->errcode = 0;
554     q->errstring = 0;
555     q->entries = list;
556     q->status = BEND_SCAN_SUCCESS;
557     if (!f && !(f = fopen("dummy-words", "r")))
558     {
559         perror("dummy-words");
560         exit(1);
561     }
562     if (q->term->term->which != Z_Term_general)
563     {
564         q->errcode = 229; /* unsupported term type */
565         return 0;
566     }
567     if (*q->step_size != 0)
568     {
569         q->errcode = 205; /*Only zero step size supported for Scan */
570         return 0;
571     }
572     if (q->term->term->u.general->len >= 80)
573     {
574         q->errcode = 11; /* term too long */
575         return 0;
576     }
577     if (q->num_entries > 200)
578     {
579         q->errcode = 31;
580         return 0;
581     }
582     memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
583     term[q->term->term->u.general->len] = '\0';
584     for (p = term; *p; p++)
585         if (islower(*p))
586             *p = toupper(*p);
587
588     fseek(f, 0, SEEK_SET);
589     q->num_entries = 0;
590
591     for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
592         i++, pos < 199 ? pos++ : (pos = 0))
593     {
594         if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
595         {
596             if ((q->term_position = term_position_req) > i + 1)
597             {
598                 q->term_position = i + 1;
599                 q->status = BEND_SCAN_PARTIAL;
600             }
601             for (; q->num_entries < q->term_position; q->num_entries++)
602             {
603                 int po;
604
605                 po = pos - q->term_position + q->num_entries+1; /* find pos */
606                 if (po < 0)
607                     po += 200;
608
609                 if (!strcmp (term, "SD") && q->num_entries == 2)
610                 {
611                     list[q->num_entries].term = entries[pos];
612                     list[q->num_entries].occurrences = -1;
613                     list[q->num_entries].errcode = 233;
614                     list[q->num_entries].errstring = "SD for Scan Term";
615                 }
616                 else
617                 {
618                     list[q->num_entries].term = entries[po];
619                     list[q->num_entries].occurrences = hits[po];
620                 }
621             }
622         }
623         else if (q->num_entries)
624         {
625             list[q->num_entries].term = entries[pos];
626             list[q->num_entries].occurrences = hits[pos];
627             q->num_entries++;
628         }
629         if (q->num_entries >= num_entries_req)
630             break;
631     }
632     if (feof(f))
633         q->status = BEND_SCAN_PARTIAL;
634     return 0;
635 }
636
637 bend_initresult *bend_init(bend_initrequest *q)
638 {
639     bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
640     int *counter = (int *) xmalloc (sizeof(int));
641
642     *counter = 0;
643     r->errcode = 0;
644     r->errstring = 0;
645     r->handle = counter;         /* user handle, in this case a simple int */
646     q->bend_sort = ztest_sort;              /* register sort handler */
647     q->bend_search = ztest_search;          /* register search handler */
648     q->bend_present = ztest_present;        /* register present handle */
649     q->bend_esrequest = ztest_esrequest;
650     q->bend_delete = ztest_delete;
651     q->bend_fetch = ztest_fetch;
652     q->bend_scan = ztest_scan;
653     return r;
654 }
655
656 void bend_close(void *handle)
657 {
658     xfree (handle);              /* release our user-defined handle */
659     return;
660 }
661
662 int main(int argc, char **argv)
663 {
664     return statserv_main(argc, argv, bend_init, bend_close);
665 }