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