Add MANIFEST.SKIP so it can tell Perl's build instructions not to
[simpleserver-moved-to-github.git] / SimpleServer.xs
1 /*
2  * Copyright (c) 2000, Index Data.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation, in whole or in part, for any purpose, is hereby granted,
6  * provided that:
7  *
8  * 1. This copyright and permission notice appear in all copies of the
9  * software and its documentation. Notices of copyright or attribution
10  * which appear at the beginning of any file must remain unchanged.
11  *
12  * 2. The name of Index Data or the individual authors may not be used to
13  * endorse or promote products derived from this software without specific
14  * prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
18  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
19  * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
20  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
21  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR
22  * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  */
26
27 /*$Log: SimpleServer.xs,v $
28 /*Revision 1.13  2002-02-28 11:21:57  mike
29 /*Add RPN structure to search-handler argument hash.
30 /*
31 /*Revision 1.12  2001/08/30 14:02:10  sondberg
32 /*Small changes.
33 /*
34 /*Revision 1.11  2001/08/30 13:15:11  sondberg
35 /*Corrected a memory leak, one more to go.
36 /*
37 /*Revision 1.10  2001/08/29 11:48:36  sondberg
38 /*Added routines
39 /*
40 /*      Net::Z3950::SimpleServer::ScanSuccess
41 /*      Net::Z3950::SimpleServer::ScanPartial
42 /*
43 /*and a bit of documentation.
44 /*
45 /*Revision 1.9  2001/08/24 14:00:20  sondberg
46 /*Added support for scan.
47 /*
48 /*Revision 1.8  2001/05/21 11:07:02  sondberg
49 /*Extended maximum numbers of GRS-1 elements. Should be done dynamically.
50 /*
51 /*Revision 1.7  2001/03/13 14:17:15  sondberg
52 /*Added support for GRS-1.
53 /**/
54
55
56 #include "EXTERN.h"
57 #include "perl.h"
58 #include "XSUB.h"
59 #include <yaz/backend.h>
60 #include <yaz/log.h>
61 #include <yaz/wrbuf.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <stdlib.h>
65 #include <ctype.h>
66 #define GRS_MAX_FIELDS 500 
67 #ifdef ASN_COMPILED
68 #include <yaz/ill.h>
69 #endif
70 #ifndef sv_undef                /* To fix the problem with Perl 5.6.0 */
71 #define sv_undef PL_sv_undef
72 #endif
73
74 typedef struct {
75         SV *handle;
76
77         SV *init_ref;
78         SV *close_ref;
79         SV *sort_ref;
80         SV *search_ref;
81         SV *fetch_ref;
82         SV *present_ref;
83         SV *esrequest_ref;
84         SV *delete_ref;
85         SV *scan_ref;
86 } Zfront_handle;
87
88 SV *init_ref = NULL;
89 SV *close_ref = NULL;
90 SV *sort_ref = NULL;
91 SV *search_ref = NULL;
92 SV *fetch_ref = NULL;
93 SV *present_ref = NULL;
94 SV *esrequest_ref = NULL;
95 SV *delete_ref = NULL;
96 SV *scan_ref = NULL;
97 int MAX_OID = 15;
98
99
100 Z_GenericRecord *read_grs1(char *str, ODR o)
101 {
102         int type, ivalue;
103         char line[512], *buf, *ptr, *original;
104         char value[512];
105         Z_GenericRecord *r = 0;
106
107         original = str;
108         for (;;)
109         {
110                 Z_TaggedElement *t;
111                 Z_ElementData *c;
112         
113                 ptr = strchr(str, '\n');
114                 if (!ptr) {
115                         return r;
116                 }
117                 strncpy(line, str, ptr - str);
118                 line[ptr - str] = 0;
119                 buf = line;
120                 str = ptr + 1;
121                 while (*buf && isspace(*buf))
122                         buf++;
123                 if (*buf == '}') {
124                         memmove(original, str, strlen(str));
125                         return r;
126                 }
127                 if (sscanf(buf, "(%d,%[^)])", &type, value) != 2)
128                 {
129                         yaz_log(LOG_WARN, "Bad data in '%s'", buf);
130                         return 0;
131                 }
132                 if (!type && *value == '0')
133                         return r;
134                 if (!(buf = strchr(buf, ')')))
135                         return 0;
136                 buf++;
137                 while (*buf && isspace(*buf))
138                         buf++;
139                 if (!*buf)
140                         return 0;
141                 if (!r)
142                 {
143                         r = (Z_GenericRecord *)odr_malloc(o, sizeof(*r));
144                         r->elements = (Z_TaggedElement **)
145                         odr_malloc(o, sizeof(Z_TaggedElement*) * GRS_MAX_FIELDS);
146                         r->num_elements = 0;
147                 }
148                 if (r->num_elements > GRS_MAX_FIELDS)
149                 {
150                         yaz_log(LOG_WARN, "Max number of GRS-1 elements exceeded [GRS_MAX_FIELDS=%d]", GRS_MAX_FIELDS);
151                         exit(0);
152                 }
153                 r->elements[r->num_elements] = t = (Z_TaggedElement *) odr_malloc(o, sizeof(Z_TaggedElement));
154                 t->tagType = (int *)odr_malloc(o, sizeof(int));
155                 *t->tagType = type;
156                 t->tagValue = (Z_StringOrNumeric *)
157                         odr_malloc(o, sizeof(Z_StringOrNumeric));
158                 if ((ivalue = atoi(value)))
159                 {
160                         t->tagValue->which = Z_StringOrNumeric_numeric;
161                         t->tagValue->u.numeric = (int *)odr_malloc(o, sizeof(int));
162                         *t->tagValue->u.numeric = ivalue;
163                 }
164                 else
165                 {
166                         t->tagValue->which = Z_StringOrNumeric_string;
167                         t->tagValue->u.string = (char *)odr_malloc(o, strlen(value)+1);
168                         strcpy(t->tagValue->u.string, value);
169                 }
170                 t->tagOccurrence = 0;
171                 t->metaData = 0;
172                 t->appliedVariant = 0;
173                 t->content = c = (Z_ElementData *)odr_malloc(o, sizeof(Z_ElementData));
174                 if (*buf == '{')
175                 {
176                         c->which = Z_ElementData_subtree;
177                         c->u.subtree = read_grs1(str, o);
178                 }
179                 else
180                 {
181                         c->which = Z_ElementData_string;
182 /*                      buf[strlen(buf)-1] = '\0';*/
183                         buf[strlen(buf)] = '\0';
184                         c->u.string = odr_strdup(o, buf);
185                 }
186                 r->num_elements++;
187         }
188 }
189
190
191
192
193 static void oid2str(Odr_oid *o, WRBUF buf)
194 {
195     for (; *o >= 0; o++) {
196         char ibuf[16];
197         sprintf(ibuf, "%d", *o);
198         wrbuf_puts(buf, ibuf);
199         if (o[1] > 0)
200             wrbuf_putc(buf, '.');
201     }
202 }
203
204
205 static int rpn2pquery(Z_RPNStructure *s, WRBUF buf)
206 {
207     switch (s->which) {
208         case Z_RPNStructure_simple: {
209             Z_Operand *o = s->u.simple;
210
211             switch (o->which) {
212                 case Z_Operand_APT: {
213                     Z_AttributesPlusTerm *at = o->u.attributesPlusTerm;
214
215                     if (at->attributes) {
216                         int i;
217                         char ibuf[16];
218
219                         for (i = 0; i < at->attributes->num_attributes; i++) {
220                             wrbuf_puts(buf, "@attr ");
221                             if (at->attributes->attributes[i]->attributeSet) {
222                                 oid2str(at->attributes->attributes[i]->attributeSet, buf);
223                                 wrbuf_putc(buf, ' ');
224                             }
225                             sprintf(ibuf, "%d=", *at->attributes->attributes[i]->attributeType);
226                             assert(at->attributes->attributes[i]->which == Z_AttributeValue_numeric);
227                             wrbuf_puts(buf, ibuf);
228                             sprintf(ibuf, "%d ", *at->attributes->attributes[i]->value.numeric);
229                             wrbuf_puts(buf, ibuf);
230                         }
231                     }
232                     switch (at->term->which) {
233                         case Z_Term_general: {
234                             wrbuf_putc(buf, '"');
235                             wrbuf_write(buf, (char*) at->term->u.general->buf, at->term->u.general->len);
236                             wrbuf_puts(buf, "\" ");
237                             break;
238                         }
239                         default: abort();
240                     }
241                     break;
242                 }
243                 default: abort();
244             }
245             break;
246         }
247         case Z_RPNStructure_complex: {
248             Z_Complex *c = s->u.complex;
249
250             switch (c->roperator->which) {
251                 case Z_Operator_and: wrbuf_puts(buf, "@and "); break;
252                 case Z_Operator_or: wrbuf_puts(buf, "@or "); break;
253                 case Z_Operator_and_not: wrbuf_puts(buf, "@not "); break;
254                 case Z_Operator_prox: abort();
255                 default: abort();
256             }
257             if (!rpn2pquery(c->s1, buf))
258                 return 0;
259             if (!rpn2pquery(c->s2, buf))
260                 return 0;
261             break;
262         }
263         default: abort();
264     }
265     return 1;
266 }
267
268
269 WRBUF zquery2pquery(Z_Query *q)
270 {
271     WRBUF buf = wrbuf_alloc();
272
273     if (q->which != Z_Query_type_1 && q->which != Z_Query_type_101) 
274         return 0;
275     if (q->u.type_1->attributeSetId) {
276         /* Output attribute set ID */
277         wrbuf_puts(buf, "@attrset ");
278         oid2str(q->u.type_1->attributeSetId, buf);
279         wrbuf_putc(buf, ' ');
280     }
281     return rpn2pquery(q->u.type_1->RPNStructure, buf) ? buf : 0;
282 }
283
284
285 /* Lifted verbatim from Net::Z3950 yazwrap/util.c */
286 #include <stdarg.h>
287 void fatal(char *fmt, ...)
288 {
289     va_list ap;
290
291     fprintf(stderr, "FATAL (yazwrap): ");
292     va_start(ap, fmt);
293     vfprintf(stderr, fmt, ap);
294     va_end(ap);
295     fprintf(stderr, "\n");
296     abort();
297 }
298
299
300 /* Lifted verbatim from Net::Z3950 yazwrap/receive.c */
301 /*
302  * Creates a new Perl object of type `class'; the newly-created scalar
303  * that is a reference to the blessed thingy `referent' is returned.
304  */
305 static SV *newObject(char *class, SV *referent)
306 {
307     HV *stash;
308     SV *sv;
309
310     sv = newRV_noinc((SV*) referent);
311     stash = gv_stashpv(class, 0);
312     if (stash == 0)
313         fatal("attempt to create object of undefined class '%s'", class);
314     /*assert(stash != 0);*/
315     sv_bless(sv, stash);
316     return sv;
317 }
318
319
320 /* Lifted verbatim from Net::Z3950 yazwrap/receive.c */
321 static void setMember(HV *hv, char *name, SV *val)
322 {
323     /* We don't increment `val's reference count -- I think this is
324      * right because it's created with a refcount of 1, and in fact
325      * the reference via this hash is the only reference to it in
326      * general.
327      */
328     if (!hv_store(hv, name, (U32) strlen(name), val, (U32) 0))
329         fatal("couldn't store member in hash");
330 }
331
332
333 /* Lifted verbatim from Net::Z3950 yazwrap/receive.c */
334 static SV *translateOID(Odr_oid *x)
335 {
336     /* Yaz represents an OID by an int array terminated by a negative
337      * value, typically -1; we represent it as a reference to a
338      * blessed scalar string of "."-separated elements.
339      */
340     char buf[1000];
341     int i;
342
343     *buf = '\0';
344     for (i = 0; x[i] >= 0; i++) {
345         sprintf(buf + strlen(buf), "%d", (int) x[i]);
346         if (x[i+1] >- 0)
347             strcat(buf, ".");
348     }
349
350     /*
351      * ### We'd like to return a blessed scalar (string) here, but of
352      *  course you can't do that in Perl: only references can be
353      *  blessed, so we'd have to return a _reference_ to a string, and
354      *  bless _that_.  Better to do without the blessing, I think.
355      */
356     if (1) {
357         return newSVpv(buf, 0);
358     } else {
359         return newObject("Net::Z3950::APDU::OID", newSVpv(buf, 0));
360     }
361 }
362
363
364 static SV *rpn2perl(Z_RPNStructure *s)
365 {
366     SV *sv;
367     HV *hv;
368     AV *av;
369
370     switch (s->which) {
371     case Z_RPNStructure_simple: {
372         Z_Operand *o = s->u.simple;
373         Z_AttributesPlusTerm *at;
374         if (o->which != Z_Operand_APT)
375             fatal("can't handle RPN simples other than APT");
376         at = o->u.attributesPlusTerm;
377         if (at->term->which != Z_Term_general)
378             fatal("can't handle RPN terms other than general");
379
380         sv = newObject("Net::Z3950::RPN::Term", (SV*) (hv = newHV()));
381         if (at->attributes) {
382             int i;
383             SV *attrs = newObject("Net::Z3950::RPN::Attributes",
384                                   (SV*) (av = newAV()));
385             for (i = 0; i < at->attributes->num_attributes; i++) {
386                 Z_AttributeElement *elem = at->attributes->attributes[i];
387                 HV *hv2;
388                 SV *tmp = newObject("Net::Z3950::RPN::Attribute",
389                                     (SV*) (hv2 = newHV()));
390                 if (elem->attributeSet)
391                     setMember(hv2, "attributeSet",
392                               translateOID(elem->attributeSet));
393                 setMember(hv2, "attributeType",
394                           newSViv(*elem->attributeType));
395                 assert(elem->which == Z_AttributeValue_numeric);
396                 setMember(hv2, "attributeValue",
397                           newSViv(*elem->value.numeric));
398                 av_push(av, tmp);
399             }
400             setMember(hv, "attributes", attrs);
401         }
402         setMember(hv, "term", newSVpv((char*) at->term->u.general->buf,
403                                       at->term->u.general->len));
404         return sv;
405     }
406     case Z_RPNStructure_complex: {
407         SV *tmp;
408         Z_Complex *c = s->u.complex;
409         char *type = 0;         /* vacuous assignment satisfies gcc -Wall */
410         switch (c->roperator->which) {
411         case Z_Operator_and:     type = "Net::Z3950::RPN::And"; break;
412         case Z_Operator_or:      type = "Net::Z3950::RPN::Or"; break;
413         case Z_Operator_and_not: type = "Net::Z3950::RPN::AndNot"; break;
414         case Z_Operator_prox:    fatal("proximity not yet supported");
415         default: fatal("unknown RPN operator %d", (int) c->roperator->which);
416         }
417         sv = newObject(type, (SV*) (av = newAV()));
418         if ((tmp = rpn2perl(c->s1)) == 0)
419             return 0;
420         av_push(av, tmp);
421         if ((tmp = rpn2perl(c->s2)) == 0)
422             return 0;
423         av_push(av, tmp);
424         return sv;
425     }
426     default: fatal("unknown RPN node type %d", (int) s->which);
427     }
428
429     return 0;
430 }
431
432
433 static SV *zquery2perl(Z_Query *q)
434 {
435     SV *sv;
436     HV *hv;
437
438     if (q->which != Z_Query_type_1 && q->which != Z_Query_type_101) 
439         return 0;
440     sv = newObject("Net::Z3950::APDU::Query", (SV*) (hv = newHV()));
441     if (q->u.type_1->attributeSetId)
442         setMember(hv, "attributeSet",
443                   translateOID(q->u.type_1->attributeSetId));
444     setMember(hv, "query", rpn2perl(q->u.type_1->RPNStructure));
445     return sv;
446 }
447
448
449 int bend_sort(void *handle, bend_sort_rr *rr)
450 {
451         HV *href;
452         AV *aref;
453         SV **temp;
454         SV *err_code;
455         SV *err_str;
456         SV *status;
457         STRLEN len;
458         char *ptr;
459         char *ODR_err_str;
460         char **input_setnames;
461         Zfront_handle *zhandle = (Zfront_handle *)handle;
462         int i;
463         
464         dSP;
465         ENTER;
466         SAVETMPS;
467         
468         aref = newAV();
469         input_setnames = rr->input_setnames;
470         for (i = 0; i < rr->num_input_setnames; i++)
471         {
472                 av_push(aref, newSVpv(*input_setnames++, 0));
473         }
474         href = newHV();
475         hv_store(href, "INPUT", 5, newRV( (SV*) aref), 0);
476         hv_store(href, "OUTPUT", 6, newSVpv(rr->output_setname, 0), 0);
477         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
478         hv_store(href, "STATUS", 6, newSViv(0), 0);
479
480         PUSHMARK(sp);
481
482         XPUSHs(sv_2mortal(newRV( (SV*) href)));
483
484         PUTBACK;
485
486         perl_call_sv(sort_ref, G_SCALAR | G_DISCARD);
487
488         SPAGAIN;
489
490         temp = hv_fetch(href, "ERR_CODE", 8, 1);
491         err_code = newSVsv(*temp);
492
493         temp = hv_fetch(href, "ERR_STR", 7, 1);
494         err_str = newSVsv(*temp);
495
496         temp = hv_fetch(href, "STATUS", 6, 1);
497         status = newSVsv(*temp);
498
499
500         
501
502         PUTBACK;
503         FREETMPS;
504         LEAVE;
505
506         hv_undef(href),
507         av_undef(aref);
508         rr->errcode = SvIV(err_code);
509         rr->sort_status = SvIV(status);
510         ptr = SvPV(err_str, len);
511         ODR_err_str = (char *)odr_malloc(rr->stream, len + 1);
512         strcpy(ODR_err_str, ptr);
513         rr->errstring = ODR_err_str;
514
515         sv_free(err_code);
516         sv_free(err_str);
517         sv_free(status);
518         
519         return 0;
520 }
521
522
523 int bend_search(void *handle, bend_search_rr *rr)
524 {
525         HV *href;
526         AV *aref;
527         SV **temp;
528         SV *hits;
529         SV *err_code;
530         SV *err_str;
531         char *ODR_errstr;
532         STRLEN len;
533         int i;
534         char **basenames;
535         int n;
536         WRBUF query;
537         char *ptr;
538         SV *point;
539         SV *ODR_point;
540         Zfront_handle *zhandle = (Zfront_handle *)handle;
541
542         dSP;
543         ENTER;
544         SAVETMPS;
545
546         aref = newAV();
547         basenames = rr->basenames;
548         for (i = 0; i < rr->num_bases; i++)
549         {
550                 av_push(aref, newSVpv(*basenames++, 0));
551         }
552         href = newHV();         
553         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
554         hv_store(href, "REPL_SET", 8, newSViv(rr->replace_set), 0);
555         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
556         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
557         hv_store(href, "HITS", 4, newSViv(0), 0);
558         hv_store(href, "DATABASES", 9, newRV( (SV*) aref), 0);
559         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
560         hv_store(href, "PID", 3, newSViv(getpid()), 0);
561         hv_store(href, "RPN", 3, zquery2perl(rr->query), 0);
562         query = zquery2pquery(rr->query);
563         if (query)
564         {
565                 hv_store(href, "QUERY", 5, newSVpv((char *)query->buf, query->pos), 0);
566         }
567         else
568         {       
569                 rr->errcode = 108;
570         }
571         PUSHMARK(sp);
572         
573         XPUSHs(sv_2mortal(newRV( (SV*) href)));
574         
575         PUTBACK;
576
577         n = perl_call_sv(search_ref, G_SCALAR | G_DISCARD);
578
579         SPAGAIN;
580
581         temp = hv_fetch(href, "HITS", 4, 1);
582         hits = newSVsv(*temp);
583
584         temp = hv_fetch(href, "ERR_CODE", 8, 1);
585         err_code = newSVsv(*temp);
586
587         temp = hv_fetch(href, "ERR_STR", 7, 1);
588         err_str = newSVsv(*temp);
589
590         temp = hv_fetch(href, "HANDLE", 6, 1);
591         point = newSVsv(*temp);
592
593         PUTBACK;
594         FREETMPS;
595         LEAVE;
596         
597         hv_undef(href);
598         av_undef(aref);
599         rr->hits = SvIV(hits);
600         rr->errcode = SvIV(err_code);
601         ptr = SvPV(err_str, len);
602         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
603         strcpy(ODR_errstr, ptr);
604         rr->errstring = ODR_errstr;
605 /*      ODR_point = (SV *)odr_malloc(rr->stream, sizeof(*point));
606         memcpy(ODR_point, point, sizeof(*point));
607         zhandle->handle = ODR_point;*/
608         zhandle->handle = point;
609         handle = zhandle;
610         sv_free(hits);
611         sv_free(err_code);
612         sv_free(err_str);
613         sv_free( (SV*) aref);
614         sv_free( (SV*) href);
615         /*sv_free(point);*/
616         wrbuf_free(query, 1);
617         return 0;
618 }
619
620
621 /* ### this is worryingly similar to oid2str() */
622 WRBUF oid2dotted(int *oid)
623 {
624
625         WRBUF buf = wrbuf_alloc();
626         int dot = 0;
627
628         for (; *oid != -1 ; oid++)
629         {
630                 char ibuf[16];
631                 if (dot)
632                 {
633                         wrbuf_putc(buf, '.');
634                 }
635                 else
636                 {
637                         dot = 1;
638                 }
639                 sprintf(ibuf, "%d", *oid);
640                 wrbuf_puts(buf, ibuf);
641         }
642         return buf;
643 }
644                 
645
646 int dotted2oid(char *dotted, int *buffer)
647 {
648         int *oid;
649         char ibuf[16];
650         char *ptr;
651         int n = 0;
652
653         ptr = ibuf;
654         oid = buffer;
655         while (*dotted)
656         {
657                 if (*dotted == '.')
658                 {
659                         n++;
660                         if (n == MAX_OID)  /* Terminate if more than MAX_OID entries */
661                         {
662                                 *oid = -1;
663                                 return -1;
664                         }
665                         *ptr = 0;
666                         sscanf(ibuf, "%d", oid++);
667                         ptr = ibuf;
668                         dotted++;
669
670                 }
671                 else
672                 {
673                         *ptr++ = *dotted++;
674                 }
675         }
676         if (n < MAX_OID)
677         {
678                 *ptr = 0;
679                 sscanf(ibuf, "%d", oid++);
680         }
681         *oid = -1;
682         return 0;
683 }
684
685
686 int bend_fetch(void *handle, bend_fetch_rr *rr)
687 {
688         HV *href;
689         SV **temp;
690         SV *basename;
691         SV *record;
692         SV *last;
693         SV *err_code;
694         SV *err_string;
695         SV *sur_flag;
696         SV *point;
697         SV *rep_form;
698         char *ptr;
699         char *ODR_record;
700         char *ODR_basename;
701         char *ODR_errstr;
702         int *ODR_oid_buf;
703         oident *oid;
704         WRBUF oid_dotted;
705         Zfront_handle *zhandle = (Zfront_handle *)handle;
706
707         Z_RecordComposition *composition;
708         Z_ElementSetNames *simple;
709         STRLEN length;
710
711         dSP;
712         ENTER;
713         SAVETMPS;
714
715         rr->errcode = 0;
716         href = newHV();
717         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
718         temp = hv_store(href, "OFFSET", 6, newSViv(rr->number), 0);
719         oid_dotted = oid2dotted(rr->request_format_raw);
720         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
721         hv_store(href, "REP_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
722         hv_store(href, "BASENAME", 8, newSVpv("", 0), 0);
723         hv_store(href, "RECORD", 6, newSVpv("", 0), 0);
724         hv_store(href, "LAST", 4, newSViv(0), 0);
725         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
726         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
727         hv_store(href, "SUR_FLAG", 8, newSViv(0), 0);
728         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
729         hv_store(href, "PID", 3, newSViv(getpid()), 0);
730         if (rr->comp)
731         {
732                 composition = rr->comp;
733                 if (composition->which == Z_RecordComp_simple)
734                 {
735                         simple = composition->u.simple;
736                         if (simple->which == Z_ElementSetNames_generic)
737                         {
738                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
739                         } 
740                         else
741                         {
742                                 rr->errcode = 26;
743                         }
744                 }
745                 else
746                 {
747                         rr->errcode = 26;
748                 }
749         }
750
751         PUSHMARK(sp);
752
753         XPUSHs(sv_2mortal(newRV( (SV*) href)));
754
755         PUTBACK;
756         
757         perl_call_sv(fetch_ref, G_SCALAR | G_DISCARD);
758
759         SPAGAIN;
760
761         temp = hv_fetch(href, "BASENAME", 8, 1);
762         basename = newSVsv(*temp);
763
764         temp = hv_fetch(href, "RECORD", 6, 1);
765         record = newSVsv(*temp);
766
767         temp = hv_fetch(href, "LAST", 4, 1);
768         last = newSVsv(*temp);
769
770         temp = hv_fetch(href, "ERR_CODE", 8, 1);
771         err_code = newSVsv(*temp);
772
773         temp = hv_fetch(href, "ERR_STR", 7, 1),
774         err_string = newSVsv(*temp);
775
776         temp = hv_fetch(href, "SUR_FLAG", 8, 1);
777         sur_flag = newSVsv(*temp);
778
779         temp = hv_fetch(href, "REP_FORM", 8, 1);
780         rep_form = newSVsv(*temp);
781
782         temp = hv_fetch(href, "HANDLE", 6, 1);
783         point = newSVsv(*temp);
784
785         PUTBACK;
786         FREETMPS;
787         LEAVE;
788
789         hv_undef(href);
790         
791         ptr = SvPV(basename, length);
792         ODR_basename = (char *)odr_malloc(rr->stream, length + 1);
793         strcpy(ODR_basename, ptr);
794         rr->basename = ODR_basename;
795
796         ptr = SvPV(rep_form, length);
797         ODR_oid_buf = (int *)odr_malloc(rr->stream, (MAX_OID + 1) * sizeof(int));
798         if (dotted2oid(ptr, ODR_oid_buf) == -1)         /* Maximum number of OID elements exceeded */
799         {
800                 printf("Net::Z3950::SimpleServer: WARNING: OID structure too long, max length is %d\n", MAX_OID);
801         }
802         rr->output_format_raw = ODR_oid_buf;    
803         
804         ptr = SvPV(record, length);
805         oid = oid_getentbyoid(ODR_oid_buf);
806         if (oid->value == VAL_GRS1)             /* Treat GRS-1 records separately */
807         {
808                 rr->record = (char *) read_grs1(ptr, rr->stream);
809                 rr->len = -1;
810         }
811         else
812         {
813                 ODR_record = (char *)odr_malloc(rr->stream, length + 1);
814                 strcpy(ODR_record, ptr);
815                 rr->record = ODR_record;
816                 rr->len = length;
817         }
818         zhandle->handle = point;
819         handle = zhandle;
820         rr->last_in_set = SvIV(last);
821         
822         if (!(rr->errcode))
823         {
824                 rr->errcode = SvIV(err_code);
825                 ptr = SvPV(err_string, length);
826                 ODR_errstr = (char *)odr_malloc(rr->stream, length + 1);
827                 strcpy(ODR_errstr, ptr);
828                 rr->errstring = ODR_errstr;
829         }
830         rr->surrogate_flag = SvIV(sur_flag);
831
832         wrbuf_free(oid_dotted, 1);
833         sv_free((SV*) href);
834         sv_free(basename);
835         sv_free(record);
836         sv_free(last);
837         sv_free(err_string);
838         sv_free(err_code),
839         sv_free(sur_flag);
840         sv_free(rep_form);
841         
842         return 0;
843 }
844
845
846 int bend_present(void *handle, bend_present_rr *rr)
847 {
848
849         HV *href;
850         SV **temp;
851         SV *err_code;
852         SV *err_string;
853         SV *hits;
854         SV *point;
855         STRLEN len;
856         Z_RecordComposition *composition;
857         Z_ElementSetNames *simple;
858         char *ODR_errstr;
859         char *ptr;
860         Zfront_handle *zhandle = (Zfront_handle *)handle;
861
862 /*      WRBUF oid_dotted; */
863
864         dSP;
865         ENTER;
866         SAVETMPS;
867
868         href = newHV();
869         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
870         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
871         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
872         hv_store(href, "START", 5, newSViv(rr->start), 0);
873         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
874         hv_store(href, "NUMBER", 6, newSViv(rr->number), 0);
875         /*oid_dotted = oid2dotted(rr->request_format_raw);
876         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);*/
877         hv_store(href, "HITS", 4, newSViv(0), 0);
878         hv_store(href, "PID", 3, newSViv(getpid()), 0);
879         if (rr->comp)
880         {
881                 composition = rr->comp;
882                 if (composition->which == Z_RecordComp_simple)
883                 {
884                         simple = composition->u.simple;
885                         if (simple->which == Z_ElementSetNames_generic)
886                         {
887                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
888                         } 
889                         else
890                         {
891                                 rr->errcode = 26;
892                                 return 0;
893                         }
894                 }
895                 else
896                 {
897                         rr->errcode = 26;
898                         return 0;
899                 }
900         }
901
902         PUSHMARK(sp);
903         
904         XPUSHs(sv_2mortal(newRV( (SV*) href)));
905         
906         PUTBACK;
907         
908         perl_call_sv(present_ref, G_SCALAR | G_DISCARD);
909         
910         SPAGAIN;
911
912         temp = hv_fetch(href, "ERR_CODE", 8, 1);
913         err_code = newSVsv(*temp);
914
915         temp = hv_fetch(href, "ERR_STR", 7, 1);
916         err_string = newSVsv(*temp);
917
918         temp = hv_fetch(href, "HITS", 4, 1);
919         hits = newSVsv(*temp);
920
921         temp = hv_fetch(href, "HANDLE", 6, 1);
922         point = newSVsv(*temp);
923
924         PUTBACK;
925         FREETMPS;
926         LEAVE;
927         
928         hv_undef(href);
929         rr->errcode = SvIV(err_code);
930         rr->hits = SvIV(hits);
931
932         ptr = SvPV(err_string, len);
933         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
934         strcpy(ODR_errstr, ptr);
935         rr->errstring = ODR_errstr;
936 /*      wrbuf_free(oid_dotted, 1);*/
937         zhandle->handle = point;
938         handle = zhandle;
939         sv_free(err_code);
940         sv_free(err_string);
941         sv_free(hits);
942         sv_free( (SV*) href);
943
944         return 0;
945 }
946
947
948 int bend_esrequest(void *handle, bend_esrequest_rr *rr)
949 {
950         perl_call_sv(esrequest_ref, G_VOID | G_DISCARD | G_NOARGS);
951         return 0;
952 }
953
954
955 int bend_delete(void *handle, bend_delete_rr *rr)
956 {
957         perl_call_sv(delete_ref, G_VOID | G_DISCARD | G_NOARGS);
958         return 0;
959 }
960
961
962 int bend_scan(void *handle, bend_scan_rr *rr)
963 {
964         HV *href;
965         AV *aref;
966         AV *list;
967         AV *entries;
968         HV *scan_item;
969         struct scan_entry *scan_list;
970         struct scan_entry *buffer;
971         int *step_size = rr->step_size;
972         int i;
973         char **basenames;
974         SV **temp;
975         SV *err_code = sv_newmortal();
976         SV *err_str = sv_newmortal();
977         SV *point = sv_newmortal();
978         SV *status = sv_newmortal();
979         SV *number = sv_newmortal();
980         char *ptr;
981         char *ODR_errstr;
982         STRLEN len;
983         int term_len;
984         SV *term_tmp;
985         SV *entries_ref;
986         
987         Zfront_handle *zhandle = (Zfront_handle *)handle;
988
989         dSP;
990         ENTER;
991         SAVETMPS;
992         href = newHV();
993         list = newAV();
994         if (rr->term->term->which == Z_Term_general)
995         {
996                 term_len = rr->term->term->u.general->len;
997                 hv_store(href, "TERM", 4, newSVpv(rr->term->term->u.general->buf, term_len), 0);
998         } else {
999                 rr->errcode = 229;      /* Unsupported term type */
1000                 return 0;
1001         }
1002         hv_store(href, "STEP", 4, newSViv(*step_size), 0);
1003         hv_store(href, "NUMBER", 6, newSViv(rr->num_entries), 0);
1004         hv_store(href, "POS", 3, newSViv(rr->term_position), 0);
1005         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
1006         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
1007         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
1008         hv_store(href, "STATUS", 6, newSViv(BEND_SCAN_SUCCESS), 0);
1009         hv_store(href, "ENTRIES", 7, newRV((SV *) list), 0);
1010         aref = newAV();
1011         basenames = rr->basenames;
1012         for (i = 0; i < rr->num_bases; i++)
1013         {
1014                 av_push(aref, newSVpv(*basenames++, 0));
1015         }
1016         hv_store(href, "DATABASES", 9, newRV( (SV*) aref), 0);
1017
1018         PUSHMARK(sp);
1019
1020         XPUSHs(sv_2mortal(newRV( (SV*) href)));
1021
1022         PUTBACK;
1023
1024         perl_call_sv(scan_ref, G_SCALAR | G_DISCARD);
1025
1026         SPAGAIN;
1027
1028         temp = hv_fetch(href, "ERR_CODE", 8, 1);
1029         err_code = newSVsv(*temp);
1030
1031         temp = hv_fetch(href, "ERR_STR", 7, 1);
1032         err_str = newSVsv(*temp);
1033
1034         temp = hv_fetch(href, "HANDLE", 6, 1);
1035         point = newSVsv(*temp);
1036
1037         temp = hv_fetch(href, "STATUS", 6, 1);
1038         status = newSVsv(*temp);
1039         
1040         temp = hv_fetch(href, "NUMBER", 6, 1);
1041         number = newSVsv(*temp);
1042
1043         temp = hv_fetch(href, "ENTRIES", 7, 1);
1044         entries_ref = newSVsv(*temp);
1045
1046         PUTBACK;
1047         FREETMPS;
1048         LEAVE;
1049
1050         ptr = SvPV(err_str, len);
1051         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
1052         strcpy(ODR_errstr, ptr);
1053         rr->errstring = ODR_errstr;
1054         rr->errcode = SvIV(err_code);
1055         rr->num_entries = SvIV(number);
1056         rr->status = SvIV(status);
1057         scan_list = (struct scan_entry *) odr_malloc (rr->stream, rr->num_entries * sizeof(*scan_list));
1058         buffer = scan_list;
1059         entries = (AV *)SvRV(entries_ref);
1060         for (i = 0; i < rr->num_entries; i++)
1061         {
1062                 scan_item = (HV *)SvRV(sv_2mortal(av_shift(entries)));
1063                 temp = hv_fetch(scan_item, "TERM", 4, 1);
1064                 ptr = SvPV(*temp, len);
1065                 buffer->term = (char *) odr_malloc (rr->stream, len + 1); 
1066                 strcpy(buffer->term, ptr);
1067                 temp = hv_fetch(scan_item, "OCCURRENCE", 10, 1); 
1068                 buffer->occurrences = SvIV(*temp);
1069                 buffer++;
1070                 hv_undef(scan_item);
1071         }
1072         rr->entries = scan_list;
1073         zhandle->handle = point;
1074         handle = zhandle;
1075         sv_free(err_code);
1076         sv_free(err_str);
1077         sv_free(status);
1078         sv_free(number);
1079         hv_undef(href);
1080         sv_free((SV *)href);
1081         av_undef(aref);
1082         sv_free((SV *)aref);
1083         av_undef(list);
1084         sv_free((SV *)list);
1085         av_undef(entries);
1086         /*sv_free((SV *)entries);*/
1087         sv_free(entries_ref);
1088
1089         return 0;
1090 }
1091
1092
1093 bend_initresult *bend_init(bend_initrequest *q)
1094 {
1095         bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
1096         HV *href;
1097         SV **temp;
1098         SV *name;
1099         SV *ver;
1100         SV *err_str;
1101         SV *status;
1102         Zfront_handle *zhandle =  (Zfront_handle *) xmalloc (sizeof(*zhandle));
1103         STRLEN len;
1104         int n;
1105         SV *handle;
1106         /*char *name_ptr;
1107         char *ver_ptr;*/
1108         char *ptr;
1109
1110         dSP;
1111         ENTER;
1112         SAVETMPS;
1113
1114         /*q->bend_sort = bend_sort;*/
1115         if (search_ref)
1116         {
1117                 q->bend_search = bend_search;
1118         }
1119         if (present_ref)
1120         {
1121                 q->bend_present = bend_present;
1122         }
1123         /*q->bend_esrequest = bend_esrequest;*/
1124         /*q->bend_delete = bend_delete;*/
1125         if (fetch_ref)
1126         {
1127                 q->bend_fetch = bend_fetch;
1128         }
1129         if (scan_ref)
1130         {
1131                 q->bend_scan = bend_scan;
1132         }
1133         href = newHV(); 
1134         hv_store(href, "IMP_NAME", 8, newSVpv("", 0), 0);
1135         hv_store(href, "IMP_VER", 7, newSVpv("", 0), 0);
1136         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
1137         hv_store(href, "PEER_NAME", 9, newSVpv(q->peer_name, 0), 0);
1138         hv_store(href, "HANDLE", 6, newSVsv(&sv_undef), 0);
1139         hv_store(href, "PID", 3, newSViv(getpid()), 0);
1140
1141         PUSHMARK(sp);   
1142
1143         XPUSHs(sv_2mortal(newRV( (SV*) href)));
1144
1145         PUTBACK;
1146
1147         if (init_ref != NULL)
1148         {
1149                 perl_call_sv(init_ref, G_SCALAR | G_DISCARD);
1150         }
1151
1152         SPAGAIN;
1153
1154         temp = hv_fetch(href, "IMP_NAME", 8, 1);
1155         name = newSVsv(*temp);
1156
1157         temp = hv_fetch(href, "IMP_VER", 7, 1);
1158         ver = newSVsv(*temp);
1159
1160         temp = hv_fetch(href, "ERR_CODE", 8, 1);
1161         status = newSVsv(*temp);
1162
1163         temp = hv_fetch(href, "HANDLE", 6, 1);
1164         handle= newSVsv(*temp);
1165
1166         hv_undef(href);
1167         PUTBACK;
1168         FREETMPS;
1169         LEAVE;
1170         zhandle->handle = handle;
1171         r->errcode = SvIV(status);
1172         r->handle = zhandle;
1173         ptr = SvPV(name, len);
1174         q->implementation_name = (char *)xmalloc(len + 1);
1175         strcpy(q->implementation_name, ptr);
1176 /*      q->implementation_name = SvPV(name, len);*/
1177         ptr = SvPV(ver, len);
1178         q->implementation_version = (char *)xmalloc(len + 1);
1179         strcpy(q->implementation_version, ptr);
1180         
1181         return r;
1182 }
1183
1184
1185 void bend_close(void *handle)
1186 {
1187         HV *href;
1188         Zfront_handle *zhandle = (Zfront_handle *)handle;
1189         SV **temp;
1190
1191         dSP;
1192         ENTER;
1193         SAVETMPS;
1194
1195         if (close_ref == NULL)
1196         {
1197                 return;
1198         }
1199
1200         href = newHV();
1201         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
1202
1203         PUSHMARK(sp);
1204
1205         XPUSHs(sv_2mortal(newRV((SV *)href)));
1206
1207         PUTBACK;
1208         
1209         perl_call_sv(close_ref, G_SCALAR | G_DISCARD);
1210         
1211         SPAGAIN;
1212
1213         PUTBACK;
1214         FREETMPS;
1215         LEAVE;
1216
1217         xfree(handle);
1218         
1219         return;
1220 }
1221
1222
1223 MODULE = Net::Z3950::SimpleServer       PACKAGE = Net::Z3950::SimpleServer
1224
1225 void
1226 set_init_handler(arg)
1227                 SV *arg
1228         CODE:
1229                 init_ref = newSVsv(arg);
1230                 
1231
1232 void
1233 set_close_handler(arg)
1234                 SV *arg
1235         CODE:
1236                 close_ref = newSVsv(arg);
1237
1238
1239 void
1240 set_sort_handler(arg)
1241                 SV *arg
1242         CODE:
1243                 sort_ref = newSVsv(arg);
1244
1245 void
1246 set_search_handler(arg)
1247                 SV *arg
1248         CODE:
1249                 search_ref = newSVsv(arg);
1250
1251
1252 void
1253 set_fetch_handler(arg)
1254                 SV *arg
1255         CODE:
1256                 fetch_ref = newSVsv(arg);
1257
1258
1259 void
1260 set_present_handler(arg)
1261                 SV *arg
1262         CODE:
1263                 present_ref = newSVsv(arg);
1264
1265
1266 void
1267 set_esrequest_handler(arg)
1268                 SV *arg
1269         CODE:
1270                 esrequest_ref = newSVsv(arg);
1271
1272
1273 void
1274 set_delete_handler(arg)
1275                 SV *arg
1276         CODE:
1277                 delete_ref = newSVsv(arg);
1278
1279
1280 void
1281 set_scan_handler(arg)
1282                 SV *arg
1283         CODE:
1284                 scan_ref = newSVsv(arg);
1285
1286
1287 int
1288 start_server(...)
1289         PREINIT:
1290                 char **argv;
1291                 char **argv_buf;
1292                 char *ptr;
1293                 int i;
1294                 STRLEN len;
1295         CODE:
1296                 argv_buf = (char **)xmalloc((items + 1) * sizeof(char *));
1297                 argv = argv_buf;
1298                 for (i = 0; i < items; i++)
1299                 {
1300                         ptr = SvPV(ST(i), len);
1301                         *argv_buf = (char *)xmalloc(len + 1);
1302                         strcpy(*argv_buf++, ptr); 
1303                 }
1304                 *argv_buf = NULL;
1305                 
1306                 RETVAL = statserv_main(items, argv, bend_init, bend_close);
1307         OUTPUT:
1308                 RETVAL
1309
1310
1311 int
1312 ScanSuccess()
1313         CODE:
1314                 RETVAL = BEND_SCAN_SUCCESS;
1315         OUTPUT:
1316                 RETVAL
1317
1318 int
1319 ScanPartial()
1320         CODE:
1321                 RETVAL = BEND_SCAN_PARTIAL;
1322         OUTPUT:
1323                 RETVAL
1324
1325