Added present service
[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
28 #include "EXTERN.h"
29 #include "perl.h"
30 #include "XSUB.h"
31 #include <yaz/backend.h>
32 #include <yaz/log.h>
33 #include <yaz/wrbuf.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #ifdef ASN_COMPILED
38 #include <yaz/ill.h>
39 #endif
40
41
42 typedef struct {
43         SV *handle;
44
45         SV *init_ref;
46         SV *close_ref;
47         SV *sort_ref;
48         SV *search_ref;
49         SV *fetch_ref;
50         SV *present_ref;
51         SV *esrequest_ref;
52         SV *delete_ref;
53         SV *scan_ref;
54 } Zfront_handle;
55
56 SV *init_ref = NULL;
57 SV *close_ref = NULL;
58 SV *sort_ref = NULL;
59 SV *search_ref = NULL;
60 SV *fetch_ref = NULL;
61 SV *present_ref = NULL;
62 SV *esrequest_ref = NULL;
63 SV *delete_ref = NULL;
64 SV *scan_ref = NULL;
65 int MAX_OID = 15;
66
67 static void oid2str(Odr_oid *o, WRBUF buf)
68 {
69     for (; *o >= 0; o++) {
70         char ibuf[16];
71         sprintf(ibuf, "%d", *o);
72         wrbuf_puts(buf, ibuf);
73         if (o[1] > 0)
74             wrbuf_putc(buf, '.');
75     }
76 }
77
78
79 static int rpn2pquery(Z_RPNStructure *s, WRBUF buf)
80 {
81     switch (s->which) {
82         case Z_RPNStructure_simple: {
83             Z_Operand *o = s->u.simple;
84
85             switch (o->which) {
86                 case Z_Operand_APT: {
87                     Z_AttributesPlusTerm *at = o->u.attributesPlusTerm;
88
89                     if (at->attributes) {
90                         int i;
91                         char ibuf[16];
92
93                         for (i = 0; i < at->attributes->num_attributes; i++) {
94                             wrbuf_puts(buf, "@attr ");
95                             if (at->attributes->attributes[i]->attributeSet) {
96                                 oid2str(at->attributes->attributes[i]->attributeSet, buf);
97                                 wrbuf_putc(buf, ' ');
98                             }
99                             sprintf(ibuf, "%d=", *at->attributes->attributes[i]->attributeType);
100                             assert(at->attributes->attributes[i]->which == Z_AttributeValue_numeric);
101                             wrbuf_puts(buf, ibuf);
102                             sprintf(ibuf, "%d ", *at->attributes->attributes[i]->value.numeric);
103                             wrbuf_puts(buf, ibuf);
104                         }
105                     }
106                     switch (at->term->which) {
107                         case Z_Term_general: {
108                             wrbuf_putc(buf, '"');
109                             wrbuf_write(buf, (char*) at->term->u.general->buf, at->term->u.general->len);
110                             wrbuf_puts(buf, "\" ");
111                             break;
112                         }
113                         default: abort();
114                     }
115                     break;
116                 }
117                 default: abort();
118             }
119             break;
120         }
121         case Z_RPNStructure_complex: {
122             Z_Complex *c = s->u.complex;
123
124             switch (c->roperator->which) {
125                 case Z_Operator_and: wrbuf_puts(buf, "@and "); break;
126                 case Z_Operator_or: wrbuf_puts(buf, "@or "); break;
127                 case Z_Operator_and_not: wrbuf_puts(buf, "@not "); break;
128                 case Z_Operator_prox: abort();
129                 default: abort();
130             }
131             if (!rpn2pquery(c->s1, buf))
132                 return 0;
133             if (!rpn2pquery(c->s2, buf))
134                 return 0;
135             break;
136         }
137         default: abort();
138     }
139     return 1;
140 }
141
142
143 WRBUF zquery2pquery(Z_Query *q)
144 {
145     WRBUF buf = wrbuf_alloc();
146
147     if (q->which != Z_Query_type_1 && q->which != Z_Query_type_101) 
148         return 0;
149     if (q->u.type_1->attributeSetId) {
150         /* Output attribute set ID */
151         wrbuf_puts(buf, "@attrset ");
152         oid2str(q->u.type_1->attributeSetId, buf);
153         wrbuf_putc(buf, ' ');
154     }
155     return rpn2pquery(q->u.type_1->RPNStructure, buf) ? buf : 0;
156 }
157
158
159 int bend_sort(void *handle, bend_sort_rr *rr)
160 {
161         HV *href;
162         AV *aref;
163         SV **temp;
164         SV *err_code;
165         SV *err_str;
166         SV *status;
167         STRLEN len;
168         char *ptr;
169         char *ODR_err_str;
170         char **input_setnames;
171         Zfront_handle *zhandle = (Zfront_handle *)handle;
172         int i;
173         
174         dSP;
175         ENTER;
176         SAVETMPS;
177         
178         aref = newAV();
179         input_setnames = rr->input_setnames;
180         for (i = 0; i < rr->num_input_setnames; i++)
181         {
182                 av_push(aref, newSVpv(*input_setnames++, 0));
183         }
184         href = newHV();
185         hv_store(href, "INPUT", 5, newRV( (SV*) aref), 0);
186         hv_store(href, "OUTPUT", 6, newSVpv(rr->output_setname, 0), 0);
187         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
188         hv_store(href, "STATUS", 6, newSViv(0), 0);
189
190         PUSHMARK(sp);
191
192         XPUSHs(sv_2mortal(newRV( (SV*) href)));
193
194         PUTBACK;
195
196         perl_call_sv(sort_ref, G_SCALAR | G_DISCARD);
197
198         SPAGAIN;
199
200         temp = hv_fetch(href, "ERR_CODE", 8, 1);
201         err_code = newSVsv(*temp);
202
203         temp = hv_fetch(href, "ERR_STR", 7, 1);
204         err_str = newSVsv(*temp);
205
206         temp = hv_fetch(href, "STATUS", 6, 1);
207         status = newSVsv(*temp);
208
209
210         
211
212         PUTBACK;
213         FREETMPS;
214         LEAVE;
215
216         hv_undef(href),
217         av_undef(aref);
218         rr->errcode = SvIV(err_code);
219         rr->sort_status = SvIV(status);
220         ptr = SvPV(err_str, len);
221         ODR_err_str = (char *)odr_malloc(rr->stream, len + 1);
222         strcpy(ODR_err_str, ptr);
223         rr->errstring = ODR_err_str;
224
225         sv_free(err_code);
226         sv_free(err_str);
227         sv_free(status);
228         
229         return 0;
230 }
231
232
233 int bend_search(void *handle, bend_search_rr *rr)
234 {
235         HV *href;
236         AV *aref;
237         SV **temp;
238         SV *hits;
239         SV *err_code;
240         SV *err_str;
241         char *ODR_errstr;
242         STRLEN len;
243         int i;
244         char **basenames;
245         int n;
246         WRBUF query;
247         char *ptr;
248         SV *point;
249         SV *ODR_point;
250         Zfront_handle *zhandle = (Zfront_handle *)handle;
251
252         dSP;
253         ENTER;
254         SAVETMPS;
255
256         aref = newAV();
257         basenames = rr->basenames;
258         for (i = 0; i < rr->num_bases; i++)
259         {
260                 av_push(aref, newSVpv(*basenames++, 0));
261         }
262         href = newHV();         
263         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
264         hv_store(href, "REPL_SET", 8, newSViv(rr->replace_set), 0);
265         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
266         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
267         hv_store(href, "HITS", 4, newSViv(0), 0);
268         hv_store(href, "DATABASES", 9, newRV( (SV*) aref), 0);
269         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
270         query = zquery2pquery(rr->query);
271         if (query)
272         {
273                 hv_store(href, "QUERY", 5, newSVpv((char *)query->buf, query->pos), 0);
274         }
275         else
276         {       
277                 rr->errcode = 108;
278         }
279         PUSHMARK(sp);
280         
281         XPUSHs(sv_2mortal(newRV( (SV*) href)));
282         
283         PUTBACK;
284
285         n = perl_call_sv(search_ref, G_SCALAR | G_DISCARD);
286
287         SPAGAIN;
288
289         temp = hv_fetch(href, "HITS", 4, 1);
290         hits = newSVsv(*temp);
291
292         temp = hv_fetch(href, "ERR_CODE", 8, 1);
293         err_code = newSVsv(*temp);
294
295         temp = hv_fetch(href, "ERR_STR", 7, 1);
296         err_str = newSVsv(*temp);
297
298         temp = hv_fetch(href, "HANDLE", 6, 1);
299         point = newSVsv(*temp);
300
301         PUTBACK;
302         FREETMPS;
303         LEAVE;
304         
305         hv_undef(href);
306         av_undef(aref);
307         rr->hits = SvIV(hits);
308         rr->errcode = SvIV(err_code);
309         ptr = SvPV(err_str, len);
310         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
311         strcpy(ODR_errstr, ptr);
312         rr->errstring = ODR_errstr;
313 /*      ODR_point = (SV *)odr_malloc(rr->stream, sizeof(*point));
314         memcpy(ODR_point, point, sizeof(*point));
315         zhandle->handle = ODR_point;*/
316         zhandle->handle = point;
317         handle = zhandle;
318         sv_free(hits);
319         sv_free(err_code);
320         sv_free(err_str);
321         sv_free( (SV*) aref);
322         sv_free( (SV*) href);
323         /*sv_free(point);*/
324         wrbuf_free(query, 1);
325         return 0;
326 }
327
328
329 WRBUF oid2dotted(int *oid)
330 {
331
332         WRBUF buf = wrbuf_alloc();
333         int dot = 0;
334
335         for (; *oid != -1 ; oid++)
336         {
337                 char ibuf[16];
338                 if (dot)
339                 {
340                         wrbuf_putc(buf, '.');
341                 }
342                 else
343                 {
344                         dot = 1;
345                 }
346                 sprintf(ibuf, "%d", *oid);
347                 wrbuf_puts(buf, ibuf);
348         }
349         return buf;
350 }
351                 
352
353 int dotted2oid(char *dotted, int *buffer)
354 {
355         int *oid;
356         char ibuf[16];
357         char *ptr;
358         int n = 0;
359
360         ptr = ibuf;
361         oid = buffer;
362         while (*dotted)
363         {
364                 if (*dotted == '.')
365                 {
366                         n++;
367                         if (n == MAX_OID)  /* Terminate if more than MAX_OID entries */
368                         {
369                                 *oid = -1;
370                                 return -1;
371                         }
372                         *ptr = 0;
373                         sscanf(ibuf, "%d", oid++);
374                         ptr = ibuf;
375                         dotted++;
376
377                 }
378                 else
379                 {
380                         *ptr++ = *dotted++;
381                 }
382         }
383         if (n < MAX_OID)
384         {
385                 *ptr = 0;
386                 sscanf(ibuf, "%d", oid++);
387         }
388         *oid = -1;
389         return 0;
390 }
391
392
393 int bend_fetch(void *handle, bend_fetch_rr *rr)
394 {
395         HV *href;
396         SV **temp;
397         SV *basename;
398         SV *record;
399         SV *last;
400         SV *err_code;
401         SV *err_string;
402         SV *sur_flag;
403         SV *point;
404         SV *rep_form;
405         char *ptr;
406         char *ODR_record;
407         char *ODR_basename;
408         char *ODR_errstr;
409         int *ODR_oid_buf;
410         WRBUF oid_dotted;
411         Zfront_handle *zhandle = (Zfront_handle *)handle;
412
413         Z_RecordComposition *composition;
414         Z_ElementSetNames *simple;
415         STRLEN length;
416         int oid;
417
418         dSP;
419         ENTER;
420         SAVETMPS;
421
422         rr->errcode = 0;
423         href = newHV();
424         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
425         temp = hv_store(href, "OFFSET", 6, newSViv(rr->number), 0);
426         oid_dotted = oid2dotted(rr->request_format_raw);
427         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
428         hv_store(href, "REP_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
429         hv_store(href, "BASENAME", 8, newSVpv("", 0), 0);
430         hv_store(href, "RECORD", 6, newSVpv("", 0), 0);
431         hv_store(href, "LAST", 4, newSViv(0), 0);
432         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
433         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
434         hv_store(href, "SUR_FLAG", 8, newSViv(0), 0);
435         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
436         if (rr->comp)
437         {
438                 composition = rr->comp;
439                 if (composition->which == Z_RecordComp_simple)
440                 {
441                         simple = composition->u.simple;
442                         if (simple->which == Z_ElementSetNames_generic)
443                         {
444                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
445                         } 
446                         else
447                         {
448                                 rr->errcode = 26;
449                         }
450                 }
451                 else
452                 {
453                         rr->errcode = 26;
454                 }
455         }
456
457         PUSHMARK(sp);
458
459         XPUSHs(sv_2mortal(newRV( (SV*) href)));
460
461         PUTBACK;
462         
463         perl_call_sv(fetch_ref, G_SCALAR | G_DISCARD);
464
465         SPAGAIN;
466
467         temp = hv_fetch(href, "BASENAME", 8, 1);
468         basename = newSVsv(*temp);
469
470         temp = hv_fetch(href, "RECORD", 6, 1);
471         record = newSVsv(*temp);
472
473         temp = hv_fetch(href, "LAST", 4, 1);
474         last = newSVsv(*temp);
475
476         temp = hv_fetch(href, "ERR_CODE", 8, 1);
477         err_code = newSVsv(*temp);
478
479         temp = hv_fetch(href, "ERR_STR", 7, 1),
480         err_string = newSVsv(*temp);
481
482         temp = hv_fetch(href, "SUR_FLAG", 8, 1);
483         sur_flag = newSVsv(*temp);
484
485         temp = hv_fetch(href, "REP_FORM", 8, 1);
486         rep_form = newSVsv(*temp);
487
488         temp = hv_fetch(href, "HANDLE", 6, 1);
489         point = newSVsv(*temp);
490
491         PUTBACK;
492         FREETMPS;
493         LEAVE;
494
495         hv_undef(href);
496         
497         ptr = SvPV(basename, length);
498         ODR_basename = (char *)odr_malloc(rr->stream, length + 1);
499         strcpy(ODR_basename, ptr);
500         rr->basename = ODR_basename;
501
502         ptr = SvPV(rep_form, length);
503         ODR_oid_buf = (int *)odr_malloc(rr->stream, (MAX_OID + 1) * sizeof(int));
504         if (dotted2oid(ptr, ODR_oid_buf) == -1)         /* Maximum number of OID elements exceeded */
505         {
506                 printf("Net::Z3950::SimpleServer: WARNING: OID structure too long, max length is %d\n", MAX_OID);
507         }
508         rr->output_format_raw = ODR_oid_buf;    
509         
510         ptr = SvPV(record, length);
511         ODR_record = (char *)odr_malloc(rr->stream, length + 1);
512         strcpy(ODR_record, ptr);
513         rr->record = ODR_record;
514         rr->len = length;
515
516         zhandle->handle = point;
517         handle = zhandle;
518         rr->last_in_set = SvIV(last);
519         
520         if (!(rr->errcode))
521         {
522                 rr->errcode = SvIV(err_code);
523                 ptr = SvPV(err_string, length);
524                 ODR_errstr = (char *)odr_malloc(rr->stream, length + 1);
525                 strcpy(ODR_errstr, ptr);
526                 rr->errstring = ODR_errstr;
527         }
528         rr->surrogate_flag = SvIV(sur_flag);
529
530         wrbuf_free(oid_dotted, 1);
531         sv_free((SV*) href);
532         sv_free(basename);
533         sv_free(record);
534         sv_free(last);
535         sv_free(err_string);
536         sv_free(err_code),
537         sv_free(sur_flag);
538         sv_free(rep_form);
539         
540         return 0;
541 }
542
543
544 int bend_present(void *handle, bend_present_rr *rr)
545 {
546
547         HV *href;
548         SV **temp;
549         SV *err_code;
550         SV *err_string;
551         SV *hits;
552         SV *point;
553         STRLEN len;
554         Z_RecordComposition *composition;
555         Z_ElementSetNames *simple;
556         char *ODR_errstr;
557         char *ptr;
558         Zfront_handle *zhandle = (Zfront_handle *)handle;
559
560 /*      WRBUF oid_dotted; */
561
562         dSP;
563         ENTER;
564         SAVETMPS;
565
566         href = newHV();
567         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
568         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
569         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
570         hv_store(href, "START", 5, newSViv(rr->start), 0);
571         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
572         hv_store(href, "NUMBER", 6, newSViv(rr->number), 0);
573         /*oid_dotted = oid2dotted(rr->request_format_raw);
574         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);*/
575         hv_store(href, "HITS", 4, newSViv(0), 0);
576         if (rr->comp)
577         {
578                 composition = rr->comp;
579                 if (composition->which == Z_RecordComp_simple)
580                 {
581                         simple = composition->u.simple;
582                         if (simple->which == Z_ElementSetNames_generic)
583                         {
584                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
585                         } 
586                         else
587                         {
588                                 rr->errcode = 26;
589                                 return 0;
590                         }
591                 }
592                 else
593                 {
594                         rr->errcode = 26;
595                         return 0;
596                 }
597         }
598
599         PUSHMARK(sp);
600         
601         XPUSHs(sv_2mortal(newRV( (SV*) href)));
602         
603         PUTBACK;
604         
605         perl_call_sv(present_ref, G_SCALAR | G_DISCARD);
606         
607         SPAGAIN;
608
609         temp = hv_fetch(href, "ERR_CODE", 8, 1);
610         err_code = newSVsv(*temp);
611
612         temp = hv_fetch(href, "ERR_STR", 7, 1);
613         err_string = newSVsv(*temp);
614
615         temp = hv_fetch(href, "HITS", 4, 1);
616         hits = newSVsv(*temp);
617
618         temp = hv_fetch(href, "HANDLE", 6, 1);
619         point = newSVsv(*temp);
620
621         PUTBACK;
622         FREETMPS;
623         LEAVE;
624         
625         hv_undef(href);
626         rr->errcode = SvIV(err_code);
627         rr->hits = SvIV(hits);
628
629         ptr = SvPV(err_string, len);
630         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
631         strcpy(ODR_errstr, ptr);
632         rr->errstring = ODR_errstr;
633 /*      wrbuf_free(oid_dotted, 1);*/
634         zhandle->handle = point;
635         handle = zhandle;
636         sv_free(err_code);
637         sv_free(err_string);
638         sv_free(hits);
639         sv_free( (SV*) href);
640
641         return 0;
642 }
643
644
645 int bend_esrequest(void *handle, bend_esrequest_rr *rr)
646 {
647         perl_call_sv(esrequest_ref, G_VOID | G_DISCARD | G_NOARGS);
648         return 0;
649 }
650
651
652 int bend_delete(void *handle, bend_delete_rr *rr)
653 {
654         perl_call_sv(delete_ref, G_VOID | G_DISCARD | G_NOARGS);
655         return 0;
656 }
657
658
659 int bend_scan(void *handle, bend_scan_rr *rr)
660 {
661         perl_call_sv(scan_ref, G_VOID | G_DISCARD | G_NOARGS);
662         return 0;
663 }
664
665
666 bend_initresult *bend_init(bend_initrequest *q)
667 {
668         bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
669         HV *href;
670         SV **temp;
671         SV *name;
672         SV *ver;
673         SV *err_str;
674         SV *status;
675         Zfront_handle *zhandle =  (Zfront_handle *) xmalloc (sizeof(*zhandle));
676         STRLEN len;
677         int n;
678         SV *handle;
679         /*char *name_ptr;
680         char *ver_ptr;*/
681         char *ptr;
682
683         dSP;
684         ENTER;
685         SAVETMPS;
686
687         /*q->bend_sort = bend_sort;*/
688         if (search_ref)
689         {
690                 q->bend_search = bend_search;
691         }
692         if (present_ref)
693         {
694                 q->bend_present = bend_present;
695         }
696         /*q->bend_esrequest = bend_esrequest;*/
697         /*q->bend_delete = bend_delete;*/
698         if (fetch_ref)
699         {
700                 q->bend_fetch = bend_fetch;
701         }
702         /*q->bend_scan = bend_scan;*/
703         href = newHV(); 
704         hv_store(href, "IMP_NAME", 8, newSVpv("", 0), 0);
705         hv_store(href, "IMP_VER", 7, newSVpv("", 0), 0);
706         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
707         hv_store(href, "PEER_NAME", 9, newSVpv(q->peer_name, 0), 0);
708         hv_store(href, "HANDLE", 6, newSVsv(&sv_undef), 0);
709
710         PUSHMARK(sp);   
711
712         XPUSHs(sv_2mortal(newRV( (SV*) href)));
713
714         PUTBACK;
715
716         if (init_ref != NULL)
717         {
718                 perl_call_sv(init_ref, G_SCALAR | G_DISCARD);
719         }
720
721         SPAGAIN;
722
723         temp = hv_fetch(href, "IMP_NAME", 8, 1);
724         name = newSVsv(*temp);
725
726         temp = hv_fetch(href, "IMP_VER", 7, 1);
727         ver = newSVsv(*temp);
728
729         temp = hv_fetch(href, "ERR_CODE", 8, 1);
730         status = newSVsv(*temp);
731
732         temp = hv_fetch(href, "HANDLE", 6, 1);
733         handle= newSVsv(*temp);
734
735         hv_undef(href);
736         PUTBACK;
737         FREETMPS;
738         LEAVE;
739         zhandle->handle = handle;
740         r->errcode = SvIV(status);
741         r->handle = zhandle;
742         ptr = SvPV(name, len);
743         q->implementation_name = (char *)xmalloc(len + 1);
744         strcpy(q->implementation_name, ptr);
745 /*      q->implementation_name = SvPV(name, len);*/
746         ptr = SvPV(ver, len);
747         q->implementation_version = (char *)xmalloc(len + 1);
748         strcpy(q->implementation_version, ptr);
749         
750         return r;
751 }
752
753
754 void bend_close(void *handle)
755 {
756         HV *href;
757         Zfront_handle *zhandle = (Zfront_handle *)handle;
758         SV **temp;
759
760         dSP;
761         ENTER;
762         SAVETMPS;
763
764         if (close_ref == NULL)
765         {
766                 return;
767         }
768
769         href = newHV();
770         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
771
772         PUSHMARK(sp);
773
774         XPUSHs(sv_2mortal(newRV((SV *)href)));
775
776         PUTBACK;
777         
778         perl_call_sv(close_ref, G_SCALAR | G_DISCARD);
779         
780         SPAGAIN;
781
782         PUTBACK;
783         FREETMPS;
784         LEAVE;
785
786         xfree(handle);
787         
788         return;
789 }
790
791
792 MODULE = Net::Z3950::SimpleServer       PACKAGE = Net::Z3950::SimpleServer
793
794 void
795 set_init_handler(arg)
796                 SV *arg
797         CODE:
798                 init_ref = newSVsv(arg);
799                 
800
801 void
802 set_close_handler(arg)
803                 SV *arg
804         CODE:
805                 close_ref = newSVsv(arg);
806
807
808 void
809 set_sort_handler(arg)
810                 SV *arg
811         CODE:
812                 sort_ref = newSVsv(arg);
813
814 void
815 set_search_handler(arg)
816                 SV *arg
817         CODE:
818                 search_ref = newSVsv(arg);
819
820
821 void
822 set_fetch_handler(arg)
823                 SV *arg
824         CODE:
825                 fetch_ref = newSVsv(arg);
826
827
828 void
829 set_present_handler(arg)
830                 SV *arg
831         CODE:
832                 present_ref = newSVsv(arg);
833
834
835 void
836 set_esrequest_handler(arg)
837                 SV *arg
838         CODE:
839                 esrequest_ref = newSVsv(arg);
840
841
842 void
843 set_delete_handler(arg)
844                 SV *arg
845         CODE:
846                 delete_ref = newSVsv(arg);
847
848
849 void
850 set_scan_handler(arg)
851                 SV *arg
852         CODE:
853                 scan_ref = newSVsv(arg);
854
855
856 int
857 start_server(...)
858         PREINIT:
859                 char **argv;
860                 char **argv_buf;
861                 char *ptr;
862                 int i;
863                 STRLEN len;
864         CODE:
865                 argv_buf = (char **)xmalloc((items + 1) * sizeof(char *));
866                 argv = argv_buf;
867                 for (i = 0; i < items; i++)
868                 {
869                         ptr = SvPV(ST(i), len);
870                         *argv_buf = (char *)xmalloc(len + 1);
871                         strcpy(*argv_buf++, ptr); 
872                 }
873                 *argv_buf = NULL;
874                 
875                 RETVAL = statserv_main(items, argv, bend_init, bend_close);
876         OUTPUT:
877                 RETVAL