Added routines
[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.10  2001-08-29 11:48:36  sondberg
29 /*Added routines
30 /*
31 /*      Net::Z3950::SimpleServer::ScanSuccess
32 /*      Net::Z3950::SimpleServer::ScanPartial
33 /*
34 /*and a bit of documentation.
35 /*
36 /*Revision 1.9  2001/08/24 14:00:20  sondberg
37 /*Added support for scan.
38 /*
39 /*Revision 1.8  2001/05/21 11:07:02  sondberg
40 /*Extended maximum numbers of GRS-1 elements. Should be done dynamically.
41 /*
42 /*Revision 1.7  2001/03/13 14:17:15  sondberg
43 /*Added support for GRS-1.
44 /**/
45
46
47 #include "EXTERN.h"
48 #include "perl.h"
49 #include "XSUB.h"
50 #include <yaz/backend.h>
51 #include <yaz/log.h>
52 #include <yaz/wrbuf.h>
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include <ctype.h>
57 #define GRS_MAX_FIELDS 500 
58 #ifdef ASN_COMPILED
59 #include <yaz/ill.h>
60 #endif
61 #ifndef sv_undef                /* To fix the problem with Perl 5.6.0 */
62 #define sv_undef PL_sv_undef
63 #endif
64
65 typedef struct {
66         SV *handle;
67
68         SV *init_ref;
69         SV *close_ref;
70         SV *sort_ref;
71         SV *search_ref;
72         SV *fetch_ref;
73         SV *present_ref;
74         SV *esrequest_ref;
75         SV *delete_ref;
76         SV *scan_ref;
77 } Zfront_handle;
78
79 SV *init_ref = NULL;
80 SV *close_ref = NULL;
81 SV *sort_ref = NULL;
82 SV *search_ref = NULL;
83 SV *fetch_ref = NULL;
84 SV *present_ref = NULL;
85 SV *esrequest_ref = NULL;
86 SV *delete_ref = NULL;
87 SV *scan_ref = NULL;
88 int MAX_OID = 15;
89
90
91 Z_GenericRecord *read_grs1(char *str, ODR o)
92 {
93         int type, ivalue;
94         char line[512], *buf, *ptr, *original;
95         char value[512];
96         Z_GenericRecord *r = 0;
97
98         original = str;
99         for (;;)
100         {
101                 Z_TaggedElement *t;
102                 Z_ElementData *c;
103         
104                 ptr = strchr(str, '\n');
105                 if (!ptr) {
106                         return r;
107                 }
108                 strncpy(line, str, ptr - str);
109                 line[ptr - str] = 0;
110                 buf = line;
111                 str = ptr + 1;
112                 while (*buf && isspace(*buf))
113                         buf++;
114                 if (*buf == '}') {
115                         memmove(original, str, strlen(str));
116                         return r;
117                 }
118                 if (sscanf(buf, "(%d,%[^)])", &type, value) != 2)
119                 {
120                         yaz_log(LOG_WARN, "Bad data in '%s'", buf);
121                         return 0;
122                 }
123                 if (!type && *value == '0')
124                         return r;
125                 if (!(buf = strchr(buf, ')')))
126                         return 0;
127                 buf++;
128                 while (*buf && isspace(*buf))
129                         buf++;
130                 if (!*buf)
131                         return 0;
132                 if (!r)
133                 {
134                         r = (Z_GenericRecord *)odr_malloc(o, sizeof(*r));
135                         r->elements = (Z_TaggedElement **)
136                         odr_malloc(o, sizeof(Z_TaggedElement*) * GRS_MAX_FIELDS);
137                         r->num_elements = 0;
138                 }
139                 if (r->num_elements > GRS_MAX_FIELDS)
140                 {
141                         yaz_log(LOG_WARN, "Max number of GRS-1 elements exceeded [GRS_MAX_FIELDS=%d]", GRS_MAX_FIELDS);
142                         exit(0);
143                 }
144                 r->elements[r->num_elements] = t = (Z_TaggedElement *) odr_malloc(o, sizeof(Z_TaggedElement));
145                 t->tagType = (int *)odr_malloc(o, sizeof(int));
146                 *t->tagType = type;
147                 t->tagValue = (Z_StringOrNumeric *)
148                         odr_malloc(o, sizeof(Z_StringOrNumeric));
149                 if ((ivalue = atoi(value)))
150                 {
151                         t->tagValue->which = Z_StringOrNumeric_numeric;
152                         t->tagValue->u.numeric = (int *)odr_malloc(o, sizeof(int));
153                         *t->tagValue->u.numeric = ivalue;
154                 }
155                 else
156                 {
157                         t->tagValue->which = Z_StringOrNumeric_string;
158                         t->tagValue->u.string = (char *)odr_malloc(o, strlen(value)+1);
159                         strcpy(t->tagValue->u.string, value);
160                 }
161                 t->tagOccurrence = 0;
162                 t->metaData = 0;
163                 t->appliedVariant = 0;
164                 t->content = c = (Z_ElementData *)odr_malloc(o, sizeof(Z_ElementData));
165                 if (*buf == '{')
166                 {
167                         c->which = Z_ElementData_subtree;
168                         c->u.subtree = read_grs1(str, o);
169                 }
170                 else
171                 {
172                         c->which = Z_ElementData_string;
173 /*                      buf[strlen(buf)-1] = '\0';*/
174                         buf[strlen(buf)] = '\0';
175                         c->u.string = odr_strdup(o, buf);
176                 }
177                 r->num_elements++;
178         }
179 }
180
181
182
183
184 static void oid2str(Odr_oid *o, WRBUF buf)
185 {
186     for (; *o >= 0; o++) {
187         char ibuf[16];
188         sprintf(ibuf, "%d", *o);
189         wrbuf_puts(buf, ibuf);
190         if (o[1] > 0)
191             wrbuf_putc(buf, '.');
192     }
193 }
194
195
196 static int rpn2pquery(Z_RPNStructure *s, WRBUF buf)
197 {
198     switch (s->which) {
199         case Z_RPNStructure_simple: {
200             Z_Operand *o = s->u.simple;
201
202             switch (o->which) {
203                 case Z_Operand_APT: {
204                     Z_AttributesPlusTerm *at = o->u.attributesPlusTerm;
205
206                     if (at->attributes) {
207                         int i;
208                         char ibuf[16];
209
210                         for (i = 0; i < at->attributes->num_attributes; i++) {
211                             wrbuf_puts(buf, "@attr ");
212                             if (at->attributes->attributes[i]->attributeSet) {
213                                 oid2str(at->attributes->attributes[i]->attributeSet, buf);
214                                 wrbuf_putc(buf, ' ');
215                             }
216                             sprintf(ibuf, "%d=", *at->attributes->attributes[i]->attributeType);
217                             assert(at->attributes->attributes[i]->which == Z_AttributeValue_numeric);
218                             wrbuf_puts(buf, ibuf);
219                             sprintf(ibuf, "%d ", *at->attributes->attributes[i]->value.numeric);
220                             wrbuf_puts(buf, ibuf);
221                         }
222                     }
223                     switch (at->term->which) {
224                         case Z_Term_general: {
225                             wrbuf_putc(buf, '"');
226                             wrbuf_write(buf, (char*) at->term->u.general->buf, at->term->u.general->len);
227                             wrbuf_puts(buf, "\" ");
228                             break;
229                         }
230                         default: abort();
231                     }
232                     break;
233                 }
234                 default: abort();
235             }
236             break;
237         }
238         case Z_RPNStructure_complex: {
239             Z_Complex *c = s->u.complex;
240
241             switch (c->roperator->which) {
242                 case Z_Operator_and: wrbuf_puts(buf, "@and "); break;
243                 case Z_Operator_or: wrbuf_puts(buf, "@or "); break;
244                 case Z_Operator_and_not: wrbuf_puts(buf, "@not "); break;
245                 case Z_Operator_prox: abort();
246                 default: abort();
247             }
248             if (!rpn2pquery(c->s1, buf))
249                 return 0;
250             if (!rpn2pquery(c->s2, buf))
251                 return 0;
252             break;
253         }
254         default: abort();
255     }
256     return 1;
257 }
258
259
260 WRBUF zquery2pquery(Z_Query *q)
261 {
262     WRBUF buf = wrbuf_alloc();
263
264     if (q->which != Z_Query_type_1 && q->which != Z_Query_type_101) 
265         return 0;
266     if (q->u.type_1->attributeSetId) {
267         /* Output attribute set ID */
268         wrbuf_puts(buf, "@attrset ");
269         oid2str(q->u.type_1->attributeSetId, buf);
270         wrbuf_putc(buf, ' ');
271     }
272     return rpn2pquery(q->u.type_1->RPNStructure, buf) ? buf : 0;
273 }
274
275
276 int bend_sort(void *handle, bend_sort_rr *rr)
277 {
278         HV *href;
279         AV *aref;
280         SV **temp;
281         SV *err_code;
282         SV *err_str;
283         SV *status;
284         STRLEN len;
285         char *ptr;
286         char *ODR_err_str;
287         char **input_setnames;
288         Zfront_handle *zhandle = (Zfront_handle *)handle;
289         int i;
290         
291         dSP;
292         ENTER;
293         SAVETMPS;
294         
295         aref = newAV();
296         input_setnames = rr->input_setnames;
297         for (i = 0; i < rr->num_input_setnames; i++)
298         {
299                 av_push(aref, newSVpv(*input_setnames++, 0));
300         }
301         href = newHV();
302         hv_store(href, "INPUT", 5, newRV( (SV*) aref), 0);
303         hv_store(href, "OUTPUT", 6, newSVpv(rr->output_setname, 0), 0);
304         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
305         hv_store(href, "STATUS", 6, newSViv(0), 0);
306
307         PUSHMARK(sp);
308
309         XPUSHs(sv_2mortal(newRV( (SV*) href)));
310
311         PUTBACK;
312
313         perl_call_sv(sort_ref, G_SCALAR | G_DISCARD);
314
315         SPAGAIN;
316
317         temp = hv_fetch(href, "ERR_CODE", 8, 1);
318         err_code = newSVsv(*temp);
319
320         temp = hv_fetch(href, "ERR_STR", 7, 1);
321         err_str = newSVsv(*temp);
322
323         temp = hv_fetch(href, "STATUS", 6, 1);
324         status = newSVsv(*temp);
325
326
327         
328
329         PUTBACK;
330         FREETMPS;
331         LEAVE;
332
333         hv_undef(href),
334         av_undef(aref);
335         rr->errcode = SvIV(err_code);
336         rr->sort_status = SvIV(status);
337         ptr = SvPV(err_str, len);
338         ODR_err_str = (char *)odr_malloc(rr->stream, len + 1);
339         strcpy(ODR_err_str, ptr);
340         rr->errstring = ODR_err_str;
341
342         sv_free(err_code);
343         sv_free(err_str);
344         sv_free(status);
345         
346         return 0;
347 }
348
349
350 int bend_search(void *handle, bend_search_rr *rr)
351 {
352         HV *href;
353         AV *aref;
354         SV **temp;
355         SV *hits;
356         SV *err_code;
357         SV *err_str;
358         char *ODR_errstr;
359         STRLEN len;
360         int i;
361         char **basenames;
362         int n;
363         WRBUF query;
364         char *ptr;
365         SV *point;
366         SV *ODR_point;
367         Zfront_handle *zhandle = (Zfront_handle *)handle;
368
369         dSP;
370         ENTER;
371         SAVETMPS;
372
373         aref = newAV();
374         basenames = rr->basenames;
375         for (i = 0; i < rr->num_bases; i++)
376         {
377                 av_push(aref, newSVpv(*basenames++, 0));
378         }
379         href = newHV();         
380         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
381         hv_store(href, "REPL_SET", 8, newSViv(rr->replace_set), 0);
382         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
383         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
384         hv_store(href, "HITS", 4, newSViv(0), 0);
385         hv_store(href, "DATABASES", 9, newRV( (SV*) aref), 0);
386         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
387         hv_store(href, "PID", 3, newSViv(getpid()), 0);
388         query = zquery2pquery(rr->query);
389         if (query)
390         {
391                 hv_store(href, "QUERY", 5, newSVpv((char *)query->buf, query->pos), 0);
392         }
393         else
394         {       
395                 rr->errcode = 108;
396         }
397         PUSHMARK(sp);
398         
399         XPUSHs(sv_2mortal(newRV( (SV*) href)));
400         
401         PUTBACK;
402
403         n = perl_call_sv(search_ref, G_SCALAR | G_DISCARD);
404
405         SPAGAIN;
406
407         temp = hv_fetch(href, "HITS", 4, 1);
408         hits = newSVsv(*temp);
409
410         temp = hv_fetch(href, "ERR_CODE", 8, 1);
411         err_code = newSVsv(*temp);
412
413         temp = hv_fetch(href, "ERR_STR", 7, 1);
414         err_str = newSVsv(*temp);
415
416         temp = hv_fetch(href, "HANDLE", 6, 1);
417         point = newSVsv(*temp);
418
419         PUTBACK;
420         FREETMPS;
421         LEAVE;
422         
423         hv_undef(href);
424         av_undef(aref);
425         rr->hits = SvIV(hits);
426         rr->errcode = SvIV(err_code);
427         ptr = SvPV(err_str, len);
428         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
429         strcpy(ODR_errstr, ptr);
430         rr->errstring = ODR_errstr;
431 /*      ODR_point = (SV *)odr_malloc(rr->stream, sizeof(*point));
432         memcpy(ODR_point, point, sizeof(*point));
433         zhandle->handle = ODR_point;*/
434         zhandle->handle = point;
435         handle = zhandle;
436         sv_free(hits);
437         sv_free(err_code);
438         sv_free(err_str);
439         sv_free( (SV*) aref);
440         sv_free( (SV*) href);
441         /*sv_free(point);*/
442         wrbuf_free(query, 1);
443         return 0;
444 }
445
446
447 WRBUF oid2dotted(int *oid)
448 {
449
450         WRBUF buf = wrbuf_alloc();
451         int dot = 0;
452
453         for (; *oid != -1 ; oid++)
454         {
455                 char ibuf[16];
456                 if (dot)
457                 {
458                         wrbuf_putc(buf, '.');
459                 }
460                 else
461                 {
462                         dot = 1;
463                 }
464                 sprintf(ibuf, "%d", *oid);
465                 wrbuf_puts(buf, ibuf);
466         }
467         return buf;
468 }
469                 
470
471 int dotted2oid(char *dotted, int *buffer)
472 {
473         int *oid;
474         char ibuf[16];
475         char *ptr;
476         int n = 0;
477
478         ptr = ibuf;
479         oid = buffer;
480         while (*dotted)
481         {
482                 if (*dotted == '.')
483                 {
484                         n++;
485                         if (n == MAX_OID)  /* Terminate if more than MAX_OID entries */
486                         {
487                                 *oid = -1;
488                                 return -1;
489                         }
490                         *ptr = 0;
491                         sscanf(ibuf, "%d", oid++);
492                         ptr = ibuf;
493                         dotted++;
494
495                 }
496                 else
497                 {
498                         *ptr++ = *dotted++;
499                 }
500         }
501         if (n < MAX_OID)
502         {
503                 *ptr = 0;
504                 sscanf(ibuf, "%d", oid++);
505         }
506         *oid = -1;
507         return 0;
508 }
509
510
511 int bend_fetch(void *handle, bend_fetch_rr *rr)
512 {
513         HV *href;
514         SV **temp;
515         SV *basename;
516         SV *record;
517         SV *last;
518         SV *err_code;
519         SV *err_string;
520         SV *sur_flag;
521         SV *point;
522         SV *rep_form;
523         char *ptr;
524         char *ODR_record;
525         char *ODR_basename;
526         char *ODR_errstr;
527         int *ODR_oid_buf;
528         oident *oid;
529         WRBUF oid_dotted;
530         Zfront_handle *zhandle = (Zfront_handle *)handle;
531
532         Z_RecordComposition *composition;
533         Z_ElementSetNames *simple;
534         STRLEN length;
535
536         dSP;
537         ENTER;
538         SAVETMPS;
539
540         rr->errcode = 0;
541         href = newHV();
542         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
543         temp = hv_store(href, "OFFSET", 6, newSViv(rr->number), 0);
544         oid_dotted = oid2dotted(rr->request_format_raw);
545         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
546         hv_store(href, "REP_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);
547         hv_store(href, "BASENAME", 8, newSVpv("", 0), 0);
548         hv_store(href, "RECORD", 6, newSVpv("", 0), 0);
549         hv_store(href, "LAST", 4, newSViv(0), 0);
550         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
551         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
552         hv_store(href, "SUR_FLAG", 8, newSViv(0), 0);
553         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
554         hv_store(href, "PID", 3, newSViv(getpid()), 0);
555         if (rr->comp)
556         {
557                 composition = rr->comp;
558                 if (composition->which == Z_RecordComp_simple)
559                 {
560                         simple = composition->u.simple;
561                         if (simple->which == Z_ElementSetNames_generic)
562                         {
563                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
564                         } 
565                         else
566                         {
567                                 rr->errcode = 26;
568                         }
569                 }
570                 else
571                 {
572                         rr->errcode = 26;
573                 }
574         }
575
576         PUSHMARK(sp);
577
578         XPUSHs(sv_2mortal(newRV( (SV*) href)));
579
580         PUTBACK;
581         
582         perl_call_sv(fetch_ref, G_SCALAR | G_DISCARD);
583
584         SPAGAIN;
585
586         temp = hv_fetch(href, "BASENAME", 8, 1);
587         basename = newSVsv(*temp);
588
589         temp = hv_fetch(href, "RECORD", 6, 1);
590         record = newSVsv(*temp);
591
592         temp = hv_fetch(href, "LAST", 4, 1);
593         last = newSVsv(*temp);
594
595         temp = hv_fetch(href, "ERR_CODE", 8, 1);
596         err_code = newSVsv(*temp);
597
598         temp = hv_fetch(href, "ERR_STR", 7, 1),
599         err_string = newSVsv(*temp);
600
601         temp = hv_fetch(href, "SUR_FLAG", 8, 1);
602         sur_flag = newSVsv(*temp);
603
604         temp = hv_fetch(href, "REP_FORM", 8, 1);
605         rep_form = newSVsv(*temp);
606
607         temp = hv_fetch(href, "HANDLE", 6, 1);
608         point = newSVsv(*temp);
609
610         PUTBACK;
611         FREETMPS;
612         LEAVE;
613
614         hv_undef(href);
615         
616         ptr = SvPV(basename, length);
617         ODR_basename = (char *)odr_malloc(rr->stream, length + 1);
618         strcpy(ODR_basename, ptr);
619         rr->basename = ODR_basename;
620
621         ptr = SvPV(rep_form, length);
622         ODR_oid_buf = (int *)odr_malloc(rr->stream, (MAX_OID + 1) * sizeof(int));
623         if (dotted2oid(ptr, ODR_oid_buf) == -1)         /* Maximum number of OID elements exceeded */
624         {
625                 printf("Net::Z3950::SimpleServer: WARNING: OID structure too long, max length is %d\n", MAX_OID);
626         }
627         rr->output_format_raw = ODR_oid_buf;    
628         
629         ptr = SvPV(record, length);
630         oid = oid_getentbyoid(ODR_oid_buf);
631         if (oid->value == VAL_GRS1)             /* Treat GRS-1 records separately */
632         {
633                 rr->record = (char *) read_grs1(ptr, rr->stream);
634                 rr->len = -1;
635         }
636         else
637         {
638                 ODR_record = (char *)odr_malloc(rr->stream, length + 1);
639                 strcpy(ODR_record, ptr);
640                 rr->record = ODR_record;
641                 rr->len = length;
642         }
643         zhandle->handle = point;
644         handle = zhandle;
645         rr->last_in_set = SvIV(last);
646         
647         if (!(rr->errcode))
648         {
649                 rr->errcode = SvIV(err_code);
650                 ptr = SvPV(err_string, length);
651                 ODR_errstr = (char *)odr_malloc(rr->stream, length + 1);
652                 strcpy(ODR_errstr, ptr);
653                 rr->errstring = ODR_errstr;
654         }
655         rr->surrogate_flag = SvIV(sur_flag);
656
657         wrbuf_free(oid_dotted, 1);
658         sv_free((SV*) href);
659         sv_free(basename);
660         sv_free(record);
661         sv_free(last);
662         sv_free(err_string);
663         sv_free(err_code),
664         sv_free(sur_flag);
665         sv_free(rep_form);
666         
667         return 0;
668 }
669
670
671 int bend_present(void *handle, bend_present_rr *rr)
672 {
673
674         HV *href;
675         SV **temp;
676         SV *err_code;
677         SV *err_string;
678         SV *hits;
679         SV *point;
680         STRLEN len;
681         Z_RecordComposition *composition;
682         Z_ElementSetNames *simple;
683         char *ODR_errstr;
684         char *ptr;
685         Zfront_handle *zhandle = (Zfront_handle *)handle;
686
687 /*      WRBUF oid_dotted; */
688
689         dSP;
690         ENTER;
691         SAVETMPS;
692
693         href = newHV();
694         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
695         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
696         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
697         hv_store(href, "START", 5, newSViv(rr->start), 0);
698         hv_store(href, "SETNAME", 7, newSVpv(rr->setname, 0), 0);
699         hv_store(href, "NUMBER", 6, newSViv(rr->number), 0);
700         /*oid_dotted = oid2dotted(rr->request_format_raw);
701         hv_store(href, "REQ_FORM", 8, newSVpv((char *)oid_dotted->buf, oid_dotted->pos), 0);*/
702         hv_store(href, "HITS", 4, newSViv(0), 0);
703         hv_store(href, "PID", 3, newSViv(getpid()), 0);
704         if (rr->comp)
705         {
706                 composition = rr->comp;
707                 if (composition->which == Z_RecordComp_simple)
708                 {
709                         simple = composition->u.simple;
710                         if (simple->which == Z_ElementSetNames_generic)
711                         {
712                                 hv_store(href, "COMP", 4, newSVpv(simple->u.generic, 0), 0);
713                         } 
714                         else
715                         {
716                                 rr->errcode = 26;
717                                 return 0;
718                         }
719                 }
720                 else
721                 {
722                         rr->errcode = 26;
723                         return 0;
724                 }
725         }
726
727         PUSHMARK(sp);
728         
729         XPUSHs(sv_2mortal(newRV( (SV*) href)));
730         
731         PUTBACK;
732         
733         perl_call_sv(present_ref, G_SCALAR | G_DISCARD);
734         
735         SPAGAIN;
736
737         temp = hv_fetch(href, "ERR_CODE", 8, 1);
738         err_code = newSVsv(*temp);
739
740         temp = hv_fetch(href, "ERR_STR", 7, 1);
741         err_string = newSVsv(*temp);
742
743         temp = hv_fetch(href, "HITS", 4, 1);
744         hits = newSVsv(*temp);
745
746         temp = hv_fetch(href, "HANDLE", 6, 1);
747         point = newSVsv(*temp);
748
749         PUTBACK;
750         FREETMPS;
751         LEAVE;
752         
753         hv_undef(href);
754         rr->errcode = SvIV(err_code);
755         rr->hits = SvIV(hits);
756
757         ptr = SvPV(err_string, len);
758         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
759         strcpy(ODR_errstr, ptr);
760         rr->errstring = ODR_errstr;
761 /*      wrbuf_free(oid_dotted, 1);*/
762         zhandle->handle = point;
763         handle = zhandle;
764         sv_free(err_code);
765         sv_free(err_string);
766         sv_free(hits);
767         sv_free( (SV*) href);
768
769         return 0;
770 }
771
772
773 int bend_esrequest(void *handle, bend_esrequest_rr *rr)
774 {
775         perl_call_sv(esrequest_ref, G_VOID | G_DISCARD | G_NOARGS);
776         return 0;
777 }
778
779
780 int bend_delete(void *handle, bend_delete_rr *rr)
781 {
782         perl_call_sv(delete_ref, G_VOID | G_DISCARD | G_NOARGS);
783         return 0;
784 }
785
786
787 int bend_scan(void *handle, bend_scan_rr *rr)
788 {
789         HV *href;
790         AV *aref;
791         AV *list;
792         AV *entries;
793         HV *scan_item;
794         struct scan_entry *scan_list;
795         struct scan_entry *buffer;
796         int *step_size = rr->step_size;
797         int i;
798         char **basenames;
799         SV **temp;
800         SV *list_ref = sv_newmortal();
801         SV *err_code = sv_newmortal();
802         SV *err_str = sv_newmortal();
803         SV *point = sv_newmortal();
804         SV *status = sv_newmortal();
805         SV *number = sv_newmortal();
806         char *ptr;
807         char *ODR_errstr;
808         STRLEN len;
809         
810         Zfront_handle *zhandle = (Zfront_handle *)handle;
811
812         dSP;
813         ENTER;
814         SAVETMPS;
815         href = newHV();
816         list = newAV();
817         if (rr->term->term->which == Z_Term_general)
818         {
819                 hv_store(href, "TERM", 4, newSVpv(rr->term->term->u.general->buf, 0), 0);
820         } else {
821                 rr->errcode = 229;      /* Unsupported term type */
822                 return 0;
823         }
824         hv_store(href, "STEP", 4, newSViv(*step_size), 0);
825         hv_store(href, "NUMBER", 6, newSViv(rr->num_entries), 0);
826         hv_store(href, "POS", 3, newSViv(rr->term_position), 0);
827         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
828         hv_store(href, "ERR_STR", 7, newSVpv("", 0), 0);
829         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
830         hv_store(href, "STATUS", 6, newSViv(BEND_SCAN_SUCCESS), 0);
831         hv_store(href, "ENTRIES", 7, newRV((SV *) list), 0);
832         aref = newAV();
833         basenames = rr->basenames;
834         for (i = 0; i < rr->num_bases; i++)
835         {
836                 av_push(aref, newSVpv(*basenames++, 0));
837         }
838         hv_store(href, "DATABASES", 9, newRV( (SV*) aref), 0);
839
840         PUSHMARK(sp);
841
842         XPUSHs(sv_2mortal(newRV( (SV*) href)));
843
844         PUTBACK;
845
846         perl_call_sv(scan_ref, G_SCALAR | G_DISCARD);
847
848         SPAGAIN;
849
850         temp = hv_fetch(href, "ERR_CODE", 8, 1);
851         err_code = newSVsv(*temp);
852
853         temp = hv_fetch(href, "ERR_STR", 7, 1);
854         err_str = newSVsv(*temp);
855
856         temp = hv_fetch(href, "HANDLE", 6, 1);
857         point = newSVsv(*temp);
858
859         temp = hv_fetch(href, "STATUS", 6, 1);
860         status = newSVsv(*temp);
861         
862         temp = hv_fetch(href, "NUMBER", 6, 1);
863         number = newSVsv(*temp);
864
865         temp = hv_fetch(href, "ENTRIES", 7, 1);
866         list_ref = newSVsv(*temp);
867         entries = (AV *)SvRV(list_ref);
868
869         PUTBACK;
870         FREETMPS;
871         LEAVE;
872
873         ptr = SvPV(err_str, len);
874         ODR_errstr = (char *)odr_malloc(rr->stream, len + 1);
875         strcpy(ODR_errstr, ptr);
876         rr->errstring = ODR_errstr;
877         rr->errcode = SvIV(err_code);
878         rr->num_entries = SvIV(number);
879         rr->status = SvIV(status);
880         scan_list = (struct scan_entry *) odr_malloc (rr->stream, rr->num_entries * sizeof(*scan_list));
881         buffer = scan_list;
882         for (i = 0; i < rr->num_entries; i++)
883         {
884                 scan_item = (HV *)SvRV(sv_2mortal(av_shift(entries)));
885                 temp = hv_fetch(scan_item, "TERM", 4, 1);
886                 ptr = SvPV(*temp, len);
887                 buffer->term = (char *) odr_malloc (rr->stream, len + 1); 
888                 strcpy(buffer->term, ptr);
889                 temp = hv_fetch(scan_item, "OCCURRENCE", 10, 1); 
890                 buffer->occurrences = SvIV(*temp);
891                 buffer++;
892                 hv_undef(scan_item);
893         }
894         rr->entries = scan_list;
895         zhandle->handle = point;
896         handle = zhandle;
897         /*sv_free(list_ref);*/
898         sv_free(err_code);
899         sv_free(err_str);
900         sv_free(status);
901         sv_free(number);
902         /*sv_free(point);*/
903         hv_undef(href);
904         av_undef(aref);
905         av_undef(list);
906         av_undef(entries);
907
908         return 0;
909 }
910
911
912 bend_initresult *bend_init(bend_initrequest *q)
913 {
914         bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
915         HV *href;
916         SV **temp;
917         SV *name;
918         SV *ver;
919         SV *err_str;
920         SV *status;
921         Zfront_handle *zhandle =  (Zfront_handle *) xmalloc (sizeof(*zhandle));
922         STRLEN len;
923         int n;
924         SV *handle;
925         /*char *name_ptr;
926         char *ver_ptr;*/
927         char *ptr;
928
929         dSP;
930         ENTER;
931         SAVETMPS;
932
933         /*q->bend_sort = bend_sort;*/
934         if (search_ref)
935         {
936                 q->bend_search = bend_search;
937         }
938         if (present_ref)
939         {
940                 q->bend_present = bend_present;
941         }
942         /*q->bend_esrequest = bend_esrequest;*/
943         /*q->bend_delete = bend_delete;*/
944         if (fetch_ref)
945         {
946                 q->bend_fetch = bend_fetch;
947         }
948         if (scan_ref)
949         {
950                 q->bend_scan = bend_scan;
951         }
952         href = newHV(); 
953         hv_store(href, "IMP_NAME", 8, newSVpv("", 0), 0);
954         hv_store(href, "IMP_VER", 7, newSVpv("", 0), 0);
955         hv_store(href, "ERR_CODE", 8, newSViv(0), 0);
956         hv_store(href, "PEER_NAME", 9, newSVpv(q->peer_name, 0), 0);
957         hv_store(href, "HANDLE", 6, newSVsv(&sv_undef), 0);
958         hv_store(href, "PID", 3, newSViv(getpid()), 0);
959
960         PUSHMARK(sp);   
961
962         XPUSHs(sv_2mortal(newRV( (SV*) href)));
963
964         PUTBACK;
965
966         if (init_ref != NULL)
967         {
968                 perl_call_sv(init_ref, G_SCALAR | G_DISCARD);
969         }
970
971         SPAGAIN;
972
973         temp = hv_fetch(href, "IMP_NAME", 8, 1);
974         name = newSVsv(*temp);
975
976         temp = hv_fetch(href, "IMP_VER", 7, 1);
977         ver = newSVsv(*temp);
978
979         temp = hv_fetch(href, "ERR_CODE", 8, 1);
980         status = newSVsv(*temp);
981
982         temp = hv_fetch(href, "HANDLE", 6, 1);
983         handle= newSVsv(*temp);
984
985         hv_undef(href);
986         PUTBACK;
987         FREETMPS;
988         LEAVE;
989         zhandle->handle = handle;
990         r->errcode = SvIV(status);
991         r->handle = zhandle;
992         ptr = SvPV(name, len);
993         q->implementation_name = (char *)xmalloc(len + 1);
994         strcpy(q->implementation_name, ptr);
995 /*      q->implementation_name = SvPV(name, len);*/
996         ptr = SvPV(ver, len);
997         q->implementation_version = (char *)xmalloc(len + 1);
998         strcpy(q->implementation_version, ptr);
999         
1000         return r;
1001 }
1002
1003
1004 void bend_close(void *handle)
1005 {
1006         HV *href;
1007         Zfront_handle *zhandle = (Zfront_handle *)handle;
1008         SV **temp;
1009
1010         dSP;
1011         ENTER;
1012         SAVETMPS;
1013
1014         if (close_ref == NULL)
1015         {
1016                 return;
1017         }
1018
1019         href = newHV();
1020         hv_store(href, "HANDLE", 6, zhandle->handle, 0);
1021
1022         PUSHMARK(sp);
1023
1024         XPUSHs(sv_2mortal(newRV((SV *)href)));
1025
1026         PUTBACK;
1027         
1028         perl_call_sv(close_ref, G_SCALAR | G_DISCARD);
1029         
1030         SPAGAIN;
1031
1032         PUTBACK;
1033         FREETMPS;
1034         LEAVE;
1035
1036         xfree(handle);
1037         
1038         return;
1039 }
1040
1041
1042 MODULE = Net::Z3950::SimpleServer       PACKAGE = Net::Z3950::SimpleServer
1043
1044 void
1045 set_init_handler(arg)
1046                 SV *arg
1047         CODE:
1048                 init_ref = newSVsv(arg);
1049                 
1050
1051 void
1052 set_close_handler(arg)
1053                 SV *arg
1054         CODE:
1055                 close_ref = newSVsv(arg);
1056
1057
1058 void
1059 set_sort_handler(arg)
1060                 SV *arg
1061         CODE:
1062                 sort_ref = newSVsv(arg);
1063
1064 void
1065 set_search_handler(arg)
1066                 SV *arg
1067         CODE:
1068                 search_ref = newSVsv(arg);
1069
1070
1071 void
1072 set_fetch_handler(arg)
1073                 SV *arg
1074         CODE:
1075                 fetch_ref = newSVsv(arg);
1076
1077
1078 void
1079 set_present_handler(arg)
1080                 SV *arg
1081         CODE:
1082                 present_ref = newSVsv(arg);
1083
1084
1085 void
1086 set_esrequest_handler(arg)
1087                 SV *arg
1088         CODE:
1089                 esrequest_ref = newSVsv(arg);
1090
1091
1092 void
1093 set_delete_handler(arg)
1094                 SV *arg
1095         CODE:
1096                 delete_ref = newSVsv(arg);
1097
1098
1099 void
1100 set_scan_handler(arg)
1101                 SV *arg
1102         CODE:
1103                 scan_ref = newSVsv(arg);
1104
1105
1106 int
1107 start_server(...)
1108         PREINIT:
1109                 char **argv;
1110                 char **argv_buf;
1111                 char *ptr;
1112                 int i;
1113                 STRLEN len;
1114         CODE:
1115                 argv_buf = (char **)xmalloc((items + 1) * sizeof(char *));
1116                 argv = argv_buf;
1117                 for (i = 0; i < items; i++)
1118                 {
1119                         ptr = SvPV(ST(i), len);
1120                         *argv_buf = (char *)xmalloc(len + 1);
1121                         strcpy(*argv_buf++, ptr); 
1122                 }
1123                 *argv_buf = NULL;
1124                 
1125                 RETVAL = statserv_main(items, argv, bend_init, bend_close);
1126         OUTPUT:
1127                 RETVAL
1128
1129
1130 int
1131 ScanSuccess()
1132         CODE:
1133                 RETVAL = BEND_SCAN_SUCCESS;
1134         OUTPUT:
1135                 RETVAL
1136
1137 int
1138 ScanPartial()
1139         CODE:
1140                 RETVAL = BEND_SCAN_PARTIAL;
1141         OUTPUT:
1142                 RETVAL
1143
1144