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