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