Generic snippet support. Unlike previous versions of snippet
[idzebra-moved-to-github.git] / index / retrieve.c
1 /* $Id: retrieve.c,v 1.71 2007-08-21 11:06:47 adam Exp $
2    Copyright (C) 1995-2007
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25
26 #include <fcntl.h>
27 #ifdef WIN32
28 #include <io.h>
29 #include <process.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include "index.h"
36 #include <yaz/diagbib1.h>
37 #include <yaz/snprintf.h>
38 #include <direntz.h>
39 #include <yaz/oid_db.h>
40
41 #define ZEBRA_XML_HEADER_STR "<record xmlns=\"http://www.indexdata.com/zebra/\""
42
43 static int zebra_create_record_stream(ZebraHandle zh, 
44                                       Record *rec,
45                                       struct ZebraRecStream *stream)
46 {
47     RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, *rec);
48
49     if ((*rec)->size[recInfo_storeData] > 0)
50         zebra_create_stream_mem(stream, (*rec)->info[recInfo_storeData],
51                                 (*rec)->size[recInfo_storeData]);
52     else
53     {
54         char full_rep[1024];
55         int fd;
56             
57         if (zh->path_reg && !yaz_is_abspath((*rec)->info[recInfo_filename])){
58             strcpy(full_rep, zh->path_reg);
59             strcat(full_rep, "/");
60             strcat(full_rep, (*rec)->info[recInfo_filename]);
61         }
62         else
63             strcpy(full_rep, (*rec)->info[recInfo_filename]);
64             
65         if ((fd = open (full_rep, O_BINARY|O_RDONLY)) == -1){
66             yaz_log (YLOG_WARN|YLOG_ERRNO, "Retrieve fail; missing file: %s",
67                      full_rep);
68             rec_free(rec);
69             return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
70         }
71         zebra_create_stream_fd(stream, fd, recordAttr->recordOffset);
72     }
73     return 0;
74 }
75     
76
77
78 static int parse_zebra_elem(const char *elem,
79                             const char **index, size_t *index_len,
80                             const char **type, size_t *type_len)
81 {
82     *index = 0;
83     *index_len = 0;
84
85     *type = 0;
86     *type_len = 0;
87
88     if (elem && *elem)
89     {
90         char *cp;
91         /* verify that '::' is in the beginning of *elem 
92            and something more follows */
93         if (':' != *elem
94             || !(elem +1) || ':' != *(elem +1)
95             || !(elem +2) || '\0' == *(elem +2))
96             return 0;
97  
98         /* pick out info from string after '::' */
99         elem = elem + 2;
100         cp = strchr(elem, ':');
101
102         if (!cp) /* index, no colon, no type */
103         {
104             *index = elem;
105             *index_len = strlen(elem);
106         }
107         else if (cp[1] == '\0') /* colon, but no following type */
108         {
109             return 0;
110         }
111         else  /* index, colon and type */
112         {
113             *index = elem;
114             *index_len = cp - elem;
115             *type = cp+1;
116             *type_len = strlen(cp+1);
117         }
118     }
119     return 1;
120 }
121
122
123 int zebra_special_sort_fetch(ZebraHandle zh, zint sysno, ODR odr,
124                              const char *elemsetname,
125                              const Odr_oid *input_format,
126                              const Odr_oid **output_format,
127                              char **rec_bufp, int *rec_lenp)
128 {
129     const char *retrieval_index;
130     size_t retrieval_index_len; 
131     const char *retrieval_type;
132     size_t retrieval_type_len;
133     char retrieval_index_cstr[256];
134     int ord;
135
136     /* only accept XML and SUTRS requests */
137     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml) 
138         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
139     {
140         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
141                 elemsetname);
142         *output_format = 0;
143         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
144     }
145     
146     if (!parse_zebra_elem(elemsetname,
147                           &retrieval_index, &retrieval_index_len,
148                           &retrieval_type,  &retrieval_type_len))
149     {
150         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
151     }
152     
153     if (retrieval_type_len == 0)
154         return -1;   /* must have a register type specified */
155     if (!retrieval_index_len ||
156         retrieval_index_len >= sizeof(retrieval_index_cstr)-1)
157     {
158         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
159     }
160         
161     memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
162     retrieval_index_cstr[retrieval_index_len] = '\0';
163
164     ord = zebraExplain_lookup_attr_str(zh->reg->zei,
165                                        zinfo_index_category_sort,
166                                        retrieval_type[0],
167                                        retrieval_index_cstr);
168     if (ord == -1)
169         return -1;  /* is not a sort index */
170     else
171     {
172         char dst_buf[IT_MAX_WORD];
173         char str[IT_MAX_WORD];
174         int index_type;
175         const char *db = 0;
176         const char *string_index = 0;
177         WRBUF wrbuf = wrbuf_alloc();
178         
179         zebra_sort_sysno(zh->reg->sort_index, sysno);
180         zebra_sort_type(zh->reg->sort_index, ord);
181         zebra_sort_read(zh->reg->sort_index, str);
182
183         zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db, &string_index);
184         
185         zebra_term_untrans(zh, index_type, dst_buf, str);
186         
187
188         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
189         {
190             *output_format = yaz_oid_recsyn_xml;
191             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
192                          " sysno=\"" ZINT_FORMAT "\""
193                          " set=\"zebra::index%s/\">\n",
194                          sysno, elemsetname);
195
196             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
197                          string_index);
198             wrbuf_printf(wrbuf, " type=\"%c\">", index_type);
199             wrbuf_xmlputs(wrbuf, dst_buf);
200             wrbuf_printf(wrbuf, "</index>\n");
201             wrbuf_printf(wrbuf, "</record>\n");
202         }
203         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
204         {
205             *output_format = yaz_oid_recsyn_sutrs;
206             
207             wrbuf_printf(wrbuf, "%s %c %s\n", string_index, index_type,
208                          dst_buf);
209         }
210         *rec_lenp = wrbuf_len(wrbuf);
211         *rec_bufp = odr_malloc(odr, *rec_lenp);
212         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
213         wrbuf_destroy(wrbuf);
214         return 0;
215     }
216 }
217                             
218 int zebra_special_index_fetch(ZebraHandle zh, zint sysno, ODR odr,
219                               Record rec,
220                               const char *elemsetname,
221                               const Odr_oid *input_format,
222                               const Odr_oid **output_format,
223                               char **rec_bufp, int *rec_lenp)
224 {
225     const char *retrieval_index;
226     size_t retrieval_index_len; 
227     const char *retrieval_type;
228     size_t retrieval_type_len;
229     zebra_rec_keys_t keys;
230     int ret_code = 0;
231     
232     /* set output variables before processing possible error states */
233     /* *rec_lenp = 0; */
234
235     /* only accept XML and SUTRS requests */
236     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
237         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
238     {
239         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
240                 elemsetname);
241         *output_format = 0;
242         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
243     }
244
245     if (!parse_zebra_elem(elemsetname,
246                      &retrieval_index, &retrieval_index_len,
247                      &retrieval_type,  &retrieval_type_len))
248         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
249
250     if (retrieval_type_len != 0 && retrieval_type_len != 1)
251     {
252         return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
253     }
254
255     if (retrieval_index_len)
256     {
257         char retrieval_index_cstr[256];
258
259         if (retrieval_index_len < sizeof(retrieval_index_cstr) -1)
260         {
261             memcpy(retrieval_index_cstr, retrieval_index, retrieval_index_len);
262             retrieval_index_cstr[retrieval_index_len] = '\0';
263             
264             if (zebraExplain_lookup_attr_str(zh->reg->zei,
265                                              zinfo_index_category_index,
266                                              (retrieval_type_len == 0 ? -1 : 
267                                               retrieval_type[0]),
268                                              retrieval_index_cstr) == -1)
269                 return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
270         }
271     }
272
273     keys = zebra_rec_keys_open();
274     zebra_rec_keys_set_buf(keys, rec->info[recInfo_delKeys],
275                            rec->size[recInfo_delKeys], 0);
276
277     if (!zebra_rec_keys_rewind(keys))
278     {
279         ret_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
280     }
281     else
282     {
283         size_t slen;
284         const char *str;
285         struct it_key key_in;
286         WRBUF wrbuf = wrbuf_alloc();
287     
288         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
289         {
290             *output_format = input_format;
291             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
292                          " sysno=\"" ZINT_FORMAT "\""
293                          " set=\"zebra::index%s/\">\n",
294                          sysno, elemsetname);
295         }
296         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
297             *output_format = input_format;
298
299         while (zebra_rec_keys_read(keys, &str, &slen, &key_in))
300         {
301             int i;
302             int ord = CAST_ZINT_TO_INT(key_in.mem[0]);
303             int index_type;
304             const char *db = 0;
305             const char *string_index = 0;
306             size_t string_index_len;
307             char dst_buf[IT_MAX_WORD];
308             
309             zebraExplain_lookup_ord(zh->reg->zei, ord, &index_type, &db,
310                                     &string_index);
311             string_index_len = strlen(string_index);
312
313             /* process only if index is not defined, 
314                or if defined and matching */
315             if (retrieval_index == 0 
316                 || (string_index_len == retrieval_index_len 
317                     && !memcmp(string_index, retrieval_index,
318                                string_index_len)))
319             {
320                 /* process only if type is not defined, or is matching */
321                 if (retrieval_type == 0 
322                     || (retrieval_type_len == 1 
323                         && retrieval_type[0] == index_type))
324                 {
325                     zebra_term_untrans(zh, index_type, dst_buf, str);
326                     if (strlen(dst_buf))
327                     {
328                         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
329                         {
330                             wrbuf_printf(wrbuf, "  <index name=\"%s\"", 
331                                          string_index);
332                             
333                             wrbuf_printf(wrbuf, " type=\"%c\"", index_type);
334                             
335                             wrbuf_printf(wrbuf, " seq=\"" ZINT_FORMAT "\">", 
336                                          key_in.mem[key_in.len -1]);
337                         
338                             wrbuf_xmlputs(wrbuf, dst_buf);
339                             wrbuf_printf(wrbuf, "</index>\n");
340                         }
341                         else 
342                         {
343                             wrbuf_printf(wrbuf, "%s ", string_index);
344                             
345                             wrbuf_printf(wrbuf, "%c", index_type);
346                             
347                             for (i = 1; i < key_in.len; i++)
348                                 wrbuf_printf(wrbuf, " " ZINT_FORMAT, 
349                                              key_in.mem[i]);
350                             
351                             /* zebra_term_untrans(zh, index_type, dst_buf, str); */
352                             wrbuf_printf(wrbuf, " %s", dst_buf);
353                         
354                             wrbuf_printf(wrbuf, "\n");
355                         }
356                     }
357                     
358                 }
359             }
360         }
361         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
362             wrbuf_printf(wrbuf, "</record>\n");
363         *rec_lenp = wrbuf_len(wrbuf);
364         *rec_bufp = odr_malloc(odr, *rec_lenp);
365         memcpy(*rec_bufp, wrbuf_buf(wrbuf), *rec_lenp);
366         wrbuf_destroy(wrbuf);
367     }
368     zebra_rec_keys_close(keys);
369     return ret_code;
370 }
371
372
373 static void retrieve_puts_attr(WRBUF wrbuf, const char *name,
374                                const char *value)
375 {
376     if (value)
377     {
378         wrbuf_printf(wrbuf, " %s=\"", name);
379         wrbuf_xmlputs(wrbuf, value);
380         wrbuf_printf(wrbuf, "\"");
381     }
382 }
383
384 static void retrieve_puts_attr_int(WRBUF wrbuf, const char *name,
385                                const int value)
386 {
387     wrbuf_printf(wrbuf, " %s=\"%i\"", name, value);
388 }
389
390 static void retrieve_puts_str(WRBUF wrbuf, const char *name,
391                                const char *value)
392 {
393     if (value)
394         wrbuf_printf(wrbuf, "%s %s\n", name, value);
395 }
396
397 static void retrieve_puts_int(WRBUF wrbuf, const char *name,
398                                const int value)
399 {
400     wrbuf_printf(wrbuf, "%s %i\n", name, value);
401 }
402
403
404 static void snippet_xml_record(ZebraHandle zh, WRBUF wrbuf, zebra_snippets *doc)
405 {
406     const zebra_snippet_word *doc_w;
407     int mark_state = 0;
408
409     wrbuf_printf(wrbuf, "%s>\n", ZEBRA_XML_HEADER_STR);
410     for (doc_w = zebra_snippets_constlist(doc); doc_w; doc_w = doc_w->next)
411     {
412         if (doc_w->mark)
413         {
414             int index_type;
415             const char *db = 0;
416             const char *string_index = 0;
417
418             zebraExplain_lookup_ord(zh->reg->zei, doc_w->ord, 
419                                     &index_type, &db, &string_index);
420
421             if (mark_state == 0)
422             {
423                 wrbuf_printf(wrbuf, "  <snippet name=\"%s\"",  string_index);
424                 wrbuf_printf(wrbuf, " type=\"%c\">", index_type);
425             }
426             if (doc_w->match)
427                 wrbuf_puts(wrbuf, "<s>");
428             /* not printing leading ws */
429             if (mark_state || !doc_w->ws || doc_w->match) 
430                 wrbuf_xmlputs(wrbuf, doc_w->term);
431             if (doc_w->match)
432                 wrbuf_puts(wrbuf, "</s>");
433         }
434         else if (mark_state == 1)
435         {
436             wrbuf_puts(wrbuf, "</snippet>\n");
437         }
438         mark_state = doc_w->mark;
439     }
440     if (mark_state == 1)
441     {
442         wrbuf_puts(wrbuf, "</snippet>\n");
443     }
444     wrbuf_printf(wrbuf, "</record>");
445 }
446
447 int zebra_special_snippet_fetch(ZebraHandle zh, const char *setname,
448                                 zint sysno, ODR odr,
449                                 const char *elemsetname,
450                                 const Odr_oid *input_format,
451                                 const Odr_oid **output_format,
452                                 char **rec_bufp, int *rec_lenp)
453 {
454     int return_code = 0;
455     Record rec;
456     
457     rec = rec_get(zh->reg->records, sysno);
458     if (!rec)
459     {
460         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
461         return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
462     }
463     else
464     {
465         const char *file_type = rec->info[recInfo_fileType];
466         void *recTypeClientData;
467         RecType rt = recType_byName(zh->reg->recTypes, zh->res,
468                                     file_type, &recTypeClientData);
469         zebra_snippets *hit_snippet = zebra_snippets_create();
470         WRBUF wrbuf = wrbuf_alloc();
471
472         zebra_snippets_hit_vector(zh, setname, sysno, hit_snippet);
473         
474         if (!rt)
475             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
476         else
477         {
478             struct ZebraRecStream stream;
479             
480             return_code = zebra_create_record_stream(zh, &rec, &stream);
481             if (return_code == 0)
482             {
483                 zebra_snippets *rec_snippet = zebra_snippets_create();
484                 extract_snippet(zh, rec_snippet, &stream,
485                                 rt, recTypeClientData);
486
487 #if 0
488                 /* for debugging purposes */
489                 yaz_log(YLOG_LOG, "---------------------------");
490                 yaz_log(YLOG_LOG, "REC SNIPPET:");
491                 zebra_snippets_log(rec_snippet, YLOG_LOG, 1);
492                 yaz_log(YLOG_LOG, "---------------------------");
493                 yaz_log(YLOG_LOG, "HIT SNIPPET:");
494                 zebra_snippets_log(hit_snippet, YLOG_LOG, 1);
495 #endif
496
497                 zebra_snippets_ring(rec_snippet, hit_snippet, 5, 5);
498
499 #if 0
500                 yaz_log(YLOG_LOG, "---------------------------");
501                 yaz_log(YLOG_LOG, "RING SNIPPET:");
502                 zebra_snippets_log(rec_snippet, YLOG_LOG, 1);
503 #endif
504                 
505                 snippet_xml_record(zh, wrbuf, rec_snippet);
506
507                 *output_format = yaz_oid_recsyn_xml;
508
509                 
510                 zebra_snippets_destroy(rec_snippet);
511             }
512             stream.destroy(&stream);
513         }
514         if (return_code == 0)
515         {
516             *rec_lenp = wrbuf_len(wrbuf);
517             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
518         }
519         wrbuf_destroy(wrbuf);
520         rec_free(&rec);
521         zebra_snippets_destroy(hit_snippet);
522     }
523     return return_code;
524 }
525
526 int zebra_special_fetch(ZebraHandle zh, const char *setname,
527                         zint sysno, int score, ODR odr,
528                         const char *elemsetname,
529                         const Odr_oid *input_format,
530                         const Odr_oid **output_format,
531                         char **rec_bufp, int *rec_lenp)
532 {
533     Record rec;
534     
535     /* set output variables before processing possible error states */
536     /* *rec_lenp = 0; */
537
538
539     if (elemsetname && 0 == strcmp(elemsetname, "snippet"))
540     {
541         return zebra_special_snippet_fetch(zh, setname, sysno, odr,
542                                            elemsetname + 7,
543                                            input_format, output_format,
544                                            rec_bufp, rec_lenp);
545     }
546
547     /* processing zebra::meta::sysno elemset without fetching binary data */
548     if (elemsetname && 0 == strcmp(elemsetname, "meta::sysno"))
549     {
550         int ret = 0;
551         WRBUF wrbuf = wrbuf_alloc();
552         if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
553         {
554             wrbuf_printf(wrbuf, ZINT_FORMAT, sysno);
555             *output_format = input_format;
556         } 
557         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
558         {
559             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
560                          " sysno=\"" ZINT_FORMAT "\"/>\n",
561                          sysno);
562             *output_format = input_format;
563         }
564         *rec_lenp = wrbuf_len(wrbuf);
565         if (*rec_lenp)
566             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
567         else
568             ret = YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
569         wrbuf_destroy(wrbuf);
570         return ret;
571     }
572
573     /* processing special elementsetname zebra::index:: for sort elements */
574     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
575     {
576         int ret = zebra_special_sort_fetch(zh, sysno, odr,
577                                            elemsetname + 5,
578                                            input_format, output_format,
579                                            rec_bufp, rec_lenp);
580         if (ret != -1)
581             return ret;
582         /* not a sort index so we continue to get the full record */
583     }
584
585
586     /* fetching binary record up for all other display elementsets */
587     rec = rec_get(zh->reg->records, sysno);
588     if (!rec)
589     {
590         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
591         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
592     }
593
594     /* processing special elementsetnames zebra::data */    
595     if (elemsetname && 0 == strcmp(elemsetname, "data"))
596     {
597         struct ZebraRecStream stream;
598         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
599         zebra_create_record_stream(zh, &rec, &stream);
600         *output_format = input_format;
601         *rec_lenp = recordAttr->recordSize;
602         *rec_bufp = (char *) odr_malloc(odr, *rec_lenp);
603         stream.readf(&stream, *rec_bufp, *rec_lenp);
604         stream.destroy(&stream);
605         rec_free(&rec);
606         return 0;
607     }
608
609     /* only accept XML and SUTRS requests from now */
610     if (oid_oidcmp(input_format, yaz_oid_recsyn_xml)
611         && oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
612     {
613         yaz_log(YLOG_WARN, "unsupported format for element set zebra::%s", 
614                 elemsetname);
615         return YAZ_BIB1_NO_SYNTAXES_AVAILABLE_FOR_THIS_REQUEST;
616     }
617     
618
619     /* processing special elementsetnames zebra::meta:: */
620     if (elemsetname && 0 == strcmp(elemsetname, "meta"))
621     {
622         int ret = 0;
623         WRBUF wrbuf = wrbuf_alloc();
624         RecordAttr *recordAttr = rec_init_attr(zh->reg->zei, rec); 
625
626         if (!oid_oidcmp(input_format, yaz_oid_recsyn_xml))
627         {
628             *output_format = input_format;
629             
630             wrbuf_printf(wrbuf, ZEBRA_XML_HEADER_STR
631                          " sysno=\"" ZINT_FORMAT "\"", sysno);
632             retrieve_puts_attr(wrbuf, "base", rec->info[recInfo_databaseName]);
633             retrieve_puts_attr(wrbuf, "file", rec->info[recInfo_filename]);
634             retrieve_puts_attr(wrbuf, "type", rec->info[recInfo_fileType]);
635             if (score >= 0)
636                 retrieve_puts_attr_int(wrbuf, "score", score);
637            
638             wrbuf_printf(wrbuf,
639                          " rank=\"" ZINT_FORMAT "\""
640                          " size=\"%i\""
641                          " set=\"zebra::%s\"/>\n",
642                          recordAttr->staticrank,
643                          recordAttr->recordSize,
644                          elemsetname);
645         }
646         else if (!oid_oidcmp(input_format, yaz_oid_recsyn_sutrs))
647         {
648             *output_format = input_format;
649             wrbuf_printf(wrbuf, "sysno " ZINT_FORMAT "\n", sysno);
650             retrieve_puts_str(wrbuf, "base", rec->info[recInfo_databaseName]);
651             retrieve_puts_str(wrbuf, "file", rec->info[recInfo_filename]);
652             retrieve_puts_str(wrbuf, "type", rec->info[recInfo_fileType]);
653             if (score >= 0)
654                 retrieve_puts_int(wrbuf, "score", score);
655
656             wrbuf_printf(wrbuf,
657                          "rank " ZINT_FORMAT "\n"
658                          "size %i\n"
659                          "set zebra::%s\n",
660                          recordAttr->staticrank,
661                          recordAttr->recordSize,
662                          elemsetname);
663         }
664         *rec_lenp = wrbuf_len(wrbuf);
665         if (*rec_lenp)
666             *rec_bufp = odr_strdup(odr, wrbuf_cstr(wrbuf));
667         else
668             ret = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
669
670         wrbuf_destroy(wrbuf);
671         rec_free(&rec);
672         return ret;
673     }
674
675     /* processing special elementsetnames zebra::index:: */
676     if (elemsetname && 0 == strncmp(elemsetname, "index", 5))
677     {
678         int ret = zebra_special_index_fetch(zh, sysno, odr, rec,
679                                             elemsetname + 5,
680                                             input_format, output_format,
681                                             rec_bufp, rec_lenp);
682         
683         rec_free(&rec);
684         return ret;
685     }
686
687     if (rec)
688         rec_free(&rec);
689     return YAZ_BIB1_SPECIFIED_ELEMENT_SET_NAME_NOT_VALID_FOR_SPECIFIED_;
690 }
691
692                           
693 int zebra_record_fetch(ZebraHandle zh, const char *setname,
694                        zint sysno, int score,
695                        zebra_snippets *hit_snippet, ODR odr,
696                        const Odr_oid *input_format, Z_RecordComposition *comp,
697                        const Odr_oid **output_format,
698                        char **rec_bufp, int *rec_lenp, char **basenamep,
699                        char **addinfo)
700 {
701     Record rec;
702     char *fname, *file_type, *basename;
703     const char *elemsetname;
704     struct ZebraRecStream stream;
705     RecordAttr *recordAttr;
706     void *clientData;
707     int return_code = 0;
708
709     *basenamep = 0;
710     *addinfo = 0;
711     elemsetname = yaz_get_esn(comp);
712
713     /* processing zebra special elementset names of form 'zebra:: */
714     if (elemsetname && 0 == strncmp(elemsetname, "zebra::", 7))
715         return  zebra_special_fetch(zh, setname, sysno, score, odr,
716                                     elemsetname + 7,
717                                     input_format, output_format,
718                                     rec_bufp, rec_lenp);
719
720
721     /* processing all other element set names */
722     rec = rec_get(zh->reg->records, sysno);
723     if (!rec)
724     {
725         yaz_log(YLOG_WARN, "rec_get fail on sysno=" ZINT_FORMAT, sysno);
726         *basenamep = 0;
727         return YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
728     }
729
730
731     recordAttr = rec_init_attr(zh->reg->zei, rec);
732
733     file_type = rec->info[recInfo_fileType];
734     fname = rec->info[recInfo_filename];
735     basename = rec->info[recInfo_databaseName];
736     *basenamep = (char *) odr_malloc (odr, strlen(basename)+1);
737     strcpy (*basenamep, basename);
738
739     yaz_log(YLOG_DEBUG, "retrieve localno=" ZINT_FORMAT " score=%d",
740             sysno, score);
741
742     return_code = zebra_create_record_stream(zh, &rec, &stream);
743
744     if (rec)
745     {
746         zebra_rec_keys_t reckeys = zebra_rec_keys_open();
747         RecType rt;
748         struct recRetrieveCtrl retrieveCtrl;
749
750         retrieveCtrl.stream = &stream;
751         retrieveCtrl.fname = fname;
752         retrieveCtrl.localno = sysno;
753         retrieveCtrl.staticrank = recordAttr->staticrank;
754         retrieveCtrl.score = score;
755         retrieveCtrl.recordSize = recordAttr->recordSize;
756         retrieveCtrl.odr = odr;
757         retrieveCtrl.input_format = retrieveCtrl.output_format = input_format;
758         retrieveCtrl.comp = comp;
759         retrieveCtrl.encoding = zh->record_encoding;
760         retrieveCtrl.diagnostic = 0;
761         retrieveCtrl.addinfo = 0;
762         retrieveCtrl.dh = zh->reg->dh;
763         retrieveCtrl.res = zh->res;
764         retrieveCtrl.rec_buf = 0;
765         retrieveCtrl.rec_len = -1;
766         retrieveCtrl.hit_snippet = hit_snippet;
767         retrieveCtrl.doc_snippet = zebra_snippets_create();
768
769         zebra_rec_keys_set_buf(reckeys,
770                                rec->info[recInfo_delKeys],
771                                rec->size[recInfo_delKeys], 
772                                0);
773         zebra_rec_keys_to_snippets(zh, reckeys, retrieveCtrl.doc_snippet);
774         zebra_rec_keys_close(reckeys);
775
776         if (!(rt = recType_byName(zh->reg->recTypes, zh->res,
777                                   file_type, &clientData)))
778         {
779             char addinfo_str[100];
780
781             sprintf(addinfo_str, "Could not handle record type %.40s",
782                     file_type);
783                     
784             *addinfo = odr_strdup(odr, addinfo_str);
785             return_code = YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS;
786         }
787         else
788         {
789             (*rt->retrieve)(clientData, &retrieveCtrl);
790             return_code = retrieveCtrl.diagnostic;
791
792             *output_format = retrieveCtrl.output_format;
793             *rec_bufp = (char *) retrieveCtrl.rec_buf;
794             *rec_lenp = retrieveCtrl.rec_len;
795             *addinfo = retrieveCtrl.addinfo;
796         }
797
798         zebra_snippets_destroy(retrieveCtrl.doc_snippet);
799
800         stream.destroy(&stream);
801         rec_free(&rec);
802     }
803
804     return return_code;
805 }
806
807 /*
808  * Local variables:
809  * c-basic-offset: 4
810  * indent-tabs-mode: nil
811  * End:
812  * vim: shiftwidth=4 tabstop=8 expandtab
813  */
814