1b063b25bf5577b1a540012c170dfa1049b872fd
[idzebra-moved-to-github.git] / index / zserver.c
1 /* $Id: zserver.c,v 1.99 2002-09-17 21:17:37 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
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 Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24
25 #include <stdio.h>
26 #include <assert.h>
27 #include <fcntl.h>
28 #ifdef WIN32
29 #include <io.h>
30 #include <process.h>
31 #else
32 #include <unistd.h>
33 #endif
34
35 #include <yaz/data1.h>
36 #include <yaz/ill.h>
37
38 #include "zserver.h"
39
40 static int bend_sort (void *handle, bend_sort_rr *rr);
41 static int bend_delete (void *handle, bend_delete_rr *rr);
42 static int bend_esrequest (void *handle, bend_esrequest_rr *rr);
43 static int bend_segment (void *handle, bend_segment_rr *rr);
44 static int bend_search (void *handle, bend_search_rr *r);
45 static int bend_fetch (void *handle, bend_fetch_rr *r);
46 static int bend_scan (void *handle, bend_scan_rr *r);
47
48 bend_initresult *bend_init (bend_initrequest *q)
49 {
50     bend_initresult *r = (bend_initresult *)
51         odr_malloc (q->stream, sizeof(*r));
52     ZebraHandle zh;
53     struct statserv_options_block *sob;
54     char *user = NULL;
55     char *passwd = NULL;
56
57     r->errcode = 0;
58     r->errstring = 0;
59     q->bend_sort = bend_sort;
60     q->bend_delete = bend_delete;
61     q->bend_esrequest = bend_esrequest;
62     q->bend_segment = bend_segment;
63     q->bend_search = bend_search;
64     q->bend_fetch = bend_fetch;
65     q->bend_scan = bend_scan;
66
67     q->implementation_name = "Zebra Information Server";
68     q->implementation_version = "Zebra " ZEBRAVER;
69
70     logf (LOG_DEBUG, "bend_init");
71
72     sob = statserv_getcontrol ();
73     if (!(zh = zebra_open (sob->handle)))
74     {
75         yaz_log (LOG_WARN, "Failed to read config `%s'", sob->configname);
76         r->errcode = 1;
77         return r;
78     }
79     if (q->auth)
80     {
81         if (q->auth->which == Z_IdAuthentication_open)
82         {
83             char *openpass = xstrdup (q->auth->u.open);
84             char *cp = strchr (openpass, '/');
85             if (cp)
86             {
87                 *cp = '\0';
88                 user = nmem_strdup (odr_getmem (q->stream), openpass);
89                 passwd = nmem_strdup (odr_getmem (q->stream), cp+1);
90             }
91             xfree (openpass);
92         }
93     }
94     if (zebra_auth (zh, user, passwd))
95     {
96         r->errcode = 222;
97         r->errstring = user;
98         zebra_close (zh);
99         return r;
100     }
101     r->handle = zh;
102     if (q->charneg_request) /* characater set and langauge negotiation? */
103     {
104         char **charsets = 0;
105         int num_charsets;
106         char **langs = 0;
107         int num_langs = 0;
108         int selected = 0;
109         int i;
110
111         NMEM nmem = nmem_create ();
112         yaz_log (LOG_LOG, "character set and language negotiation");
113
114         yaz_get_proposal_charneg (nmem, q->charneg_request,
115                                   &charsets, &num_charsets,
116                                   &langs, &num_langs, &selected);
117         for (i = 0; i < num_charsets; i++)
118         {
119             yaz_log (LOG_LOG, "charset %d %s", i, charsets[i]);
120             
121             if (odr_set_charset (q->decode, "UTF-8", charsets[i]) == 0)
122             {
123                 odr_set_charset (q->stream, charsets[i], "UTF-8");
124                 if (selected)
125                     zebra_record_encoding (zh, charsets[i]);
126                 q->charneg_response =
127                     yaz_set_response_charneg (q->stream, charsets[i],
128                                               0, selected);
129                 break;
130             }
131         }
132         nmem_destroy (nmem);
133     }
134     return r;
135 }
136
137 static void search_terms (ZebraHandle zh, bend_search_rr *r)
138 {
139     int count;
140     int no_terms;
141     int i;
142     int type;
143     struct Z_External *ext;
144     Z_SearchInfoReport *sr;
145
146     /* get no of terms for result set */
147     no_terms = zebra_resultSetTerms (zh, r->setname, 0, 0, 0, 0, 0);
148     if (!no_terms)
149         return;
150
151     r->search_info = odr_malloc (r->stream, sizeof(*r->search_info));
152
153     r->search_info->num_elements = 1;
154     r->search_info->list =
155         odr_malloc (r->stream, sizeof(*r->search_info->list));
156     r->search_info->list[0] =
157         odr_malloc (r->stream, sizeof(**r->search_info->list));
158     r->search_info->list[0]->category = 0;
159     r->search_info->list[0]->which = Z_OtherInfo_externallyDefinedInfo;
160     ext = odr_malloc (r->stream, sizeof(*ext));
161     r->search_info->list[0]->information.externallyDefinedInfo = ext;
162     ext->direct_reference =
163         yaz_oidval_to_z3950oid (r->stream, CLASS_USERINFO, VAL_SEARCHRES1);
164     ext->indirect_reference = 0;
165     ext->descriptor = 0;
166     ext->which = Z_External_searchResult1;
167     sr = odr_malloc (r->stream, sizeof(Z_SearchInfoReport));
168     ext->u.searchResult1 = sr;
169     sr->num = no_terms;
170     sr->elements = odr_malloc (r->stream, sr->num *
171                                sizeof(*sr->elements));
172     for (i = 0; i<no_terms; i++)
173     {
174         Z_Term *term;
175         char outbuf[1024];
176         size_t len = sizeof(outbuf);
177         zebra_resultSetTerms (zh, r->setname, i,
178                               &count, &type, outbuf, &len);
179         
180         sr->elements[i] = odr_malloc (r->stream, sizeof(**sr->elements));
181         sr->elements[i]->subqueryId = 0;
182         sr->elements[i]->fullQuery = odr_malloc (r->stream, 
183                                                  sizeof(bool_t));
184         *sr->elements[i]->fullQuery = 0;
185         sr->elements[i]->subqueryExpression = 
186             odr_malloc (r->stream, sizeof(Z_QueryExpression));
187         sr->elements[i]->subqueryExpression->which = 
188             Z_QueryExpression_term;
189         sr->elements[i]->subqueryExpression->u.term =
190             odr_malloc (r->stream, sizeof(Z_QueryExpressionTerm));
191         term = odr_malloc (r->stream, sizeof(Z_Term));
192         sr->elements[i]->subqueryExpression->u.term->queryTerm = term;
193         switch (type)
194         {
195         case Z_Term_characterString:
196             yaz_log (LOG_DEBUG, "term as characterString");
197             term->which = Z_Term_characterString;
198             term->u.characterString = odr_strdup (r->stream, outbuf);
199             break;
200         case Z_Term_general:
201             yaz_log (LOG_DEBUG, "term as general");
202             term->which = Z_Term_general;
203             term->u.general = odr_malloc (r->stream, sizeof(*term->u.general));
204             term->u.general->size = term->u.general->len = len;
205             term->u.general->buf = odr_malloc (r->stream, len);
206             memcpy (term->u.general->buf, outbuf, len);
207             break;
208         default:
209             term->which = Z_Term_general;
210             term->u.null = odr_nullval();
211         }
212         sr->elements[i]->subqueryExpression->u.term->termComment = 0;
213         sr->elements[i]->subqueryInterpretation = 0;
214         sr->elements[i]->subqueryRecommendation = 0;
215         sr->elements[i]->subqueryCount = odr_intdup (r->stream, count);
216         sr->elements[i]->subqueryWeight = 0;
217         sr->elements[i]->resultsByDB = 0;
218     }
219 }
220
221 int bend_search (void *handle, bend_search_rr *r)
222 {
223     ZebraHandle zh = (ZebraHandle) handle;
224
225     r->hits = 0;
226     r->errcode = 0;
227     r->errstring = NULL;
228     
229     if (zebra_select_databases (zh, r->num_bases,
230                                 (const char **) r->basenames))
231     {
232         zebra_result (zh, &r->errcode, &r->errstring);
233         return 0;
234     }
235     logf (LOG_LOG, "ResultSet '%s'", r->setname);
236     switch (r->query->which)
237     {
238     case Z_Query_type_1: case Z_Query_type_101:
239         zebra_search_rpn (zh, r->decode, r->stream, r->query->u.type_1,
240                           r->setname, &r->hits);
241         zebra_result (zh, &r->errcode, &r->errstring);
242         if (!r->errcode)
243             search_terms (zh, r);
244         break;
245     case Z_Query_type_2:
246         r->errcode = 107;
247         r->errstring = "type-2";
248         break;
249     default:
250         r->errcode = 107;
251     }
252     return 0;
253 }
254
255
256 int bend_fetch (void *handle, bend_fetch_rr *r)
257 {
258     ZebraHandle zh = (ZebraHandle) handle;
259     ZebraRetrievalRecord retrievalRecord;
260
261     retrievalRecord.position = r->number;
262     
263     r->last_in_set = 0;
264     zebra_records_retrieve (zh, r->stream, r->setname, r->comp,
265                             r->request_format, 1, &retrievalRecord);
266     zebra_result (zh, &r->errcode, &r->errstring);
267     /*  non Surrogate Diagnostic OR Surrogate Diagnostic */
268     if (r->errcode == 0 && retrievalRecord.errCode)
269     {
270         r->surrogate_flag = 1;
271         r->errcode = retrievalRecord.errCode;
272         r->errstring = retrievalRecord.errString;
273         r->basename = retrievalRecord.base;
274     }
275     else if (r->errcode == 0)        /* Database Record */
276     {
277         r->errcode = 0;
278         r->basename = retrievalRecord.base;
279         r->record = retrievalRecord.buf;
280         r->len = retrievalRecord.len;
281         r->output_format = retrievalRecord.format;
282     }
283     return 0;
284 }
285
286 static int bend_scan (void *handle, bend_scan_rr *r)
287 {
288     ZebraScanEntry *entries;
289     ZebraHandle zh = (ZebraHandle) handle;
290     int is_partial, i;
291
292     if (zebra_select_databases (zh, r->num_bases, 
293                                 (const char **) r->basenames))
294     {
295         zebra_result (zh, &r->errcode, &r->errstring);
296         return 0;
297     }
298     r->entries = (struct scan_entry *)
299         odr_malloc (r->stream, sizeof(*r->entries) * r->num_entries);
300     zebra_scan (zh, r->stream, r->term,
301                 r->attributeset,
302                 &r->term_position,
303                 &r->num_entries, &entries, &is_partial);
304     if (is_partial)
305         r->status = BEND_SCAN_PARTIAL;
306     else
307         r->status = BEND_SCAN_SUCCESS;
308     for (i = 0; i < r->num_entries; i++)
309     {
310         r->entries[i].term = entries[i].term;
311         r->entries[i].occurrences = entries[i].occurrences;
312     }
313     zebra_result (zh, &r->errcode, &r->errstring);
314     return 0;
315 }
316
317 void bend_close (void *handle)
318 {
319     zebra_close ((ZebraHandle) handle);
320     xmalloc_trav("bend_close");
321     nmem_print_list();
322 }
323
324 int bend_sort (void *handle, bend_sort_rr *rr)
325 {
326     ZebraHandle zh = (ZebraHandle) handle;
327
328     zebra_sort (zh, rr->stream,
329                 rr->num_input_setnames, (const char **) rr->input_setnames,
330                 rr->output_setname, rr->sort_sequence, &rr->sort_status);
331     zebra_result (zh, &rr->errcode, &rr->errstring);
332     return 0;
333 }
334
335 int bend_delete (void *handle, bend_delete_rr *rr)
336 {
337     ZebraHandle zh = (ZebraHandle) handle;
338
339     rr->delete_status = zebra_deleleResultSet(zh, rr->function,
340                                               rr->num_setnames, rr->setnames,
341                                               rr->statuses);
342     return 0;
343 }
344
345 static int es_admin_request (ZebraHandle zh, Z_AdminEsRequest *r)
346 {
347     switch (r->toKeep->which)
348     {
349     case Z_ESAdminOriginPartToKeep_reIndex:
350         yaz_log(LOG_LOG, "adm-reindex");
351         break;
352     case Z_ESAdminOriginPartToKeep_truncate:
353         yaz_log(LOG_LOG, "adm-truncate");
354         break;
355     case Z_ESAdminOriginPartToKeep_drop:
356         yaz_log(LOG_LOG, "adm-drop");
357         break;
358     case Z_ESAdminOriginPartToKeep_create:
359         yaz_log(LOG_LOG, "adm-create %s", r->toKeep->databaseName);
360         zebra_admin_create (zh, r->toKeep->databaseName);
361         break;
362     case Z_ESAdminOriginPartToKeep_import:
363         yaz_log(LOG_LOG, "adm-import");
364         zebra_admin_import_begin (zh, r->toKeep->databaseName,
365                         r->toKeep->u.import->recordType);
366         break;
367     case Z_ESAdminOriginPartToKeep_refresh:
368         yaz_log(LOG_LOG, "adm-refresh");
369         break;
370     case Z_ESAdminOriginPartToKeep_commit:
371         yaz_log(LOG_LOG, "adm-commit");
372         break;
373     case Z_ESAdminOriginPartToKeep_shutdown:
374         yaz_log(LOG_LOG, "shutdown");
375         zebra_admin_shutdown(zh);
376         break;
377     case Z_ESAdminOriginPartToKeep_start:
378         yaz_log(LOG_LOG, "start");
379         zebra_admin_start(zh);
380         break;
381     default:
382         yaz_log(LOG_LOG, "unknown admin");
383     }
384     if (r->toKeep->databaseName)
385     {
386         yaz_log(LOG_LOG, "database %s", r->toKeep->databaseName);
387     }
388     return 0;
389 }
390
391 static int es_admin (ZebraHandle zh, Z_Admin *r)
392 {
393     switch (r->which)
394     {
395     case Z_Admin_esRequest:
396         es_admin_request (zh, r->u.esRequest);
397         break;
398     case Z_Admin_taskPackage:
399         yaz_log (LOG_LOG, "adm taskpackage (unhandled)");
400         break;
401     default:
402         break;
403     }
404
405     return 0;
406 }
407
408 int bend_segment (void *handle, bend_segment_rr *rr)
409 {
410     ZebraHandle zh = (ZebraHandle) handle;
411     Z_Segment *segment = rr->segment;
412
413     if (segment->num_segmentRecords)
414         zebra_admin_import_segment (zh, rr->segment);
415     else
416         zebra_admin_import_end (zh);
417     return 0;
418 }
419
420 int bend_esrequest (void *handle, bend_esrequest_rr *rr)
421 {
422     ZebraHandle zh = (ZebraHandle) handle;
423     
424     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
425     if (rr->esr->packageName)
426         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
427     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
428
429     if (!rr->esr->taskSpecificParameters)
430     {
431         yaz_log (LOG_WARN, "No task specific parameters");
432     }
433     else if (rr->esr->taskSpecificParameters->which == Z_External_ESAdmin)
434     {
435         es_admin (zh, rr->esr->taskSpecificParameters->u.adminService);
436
437         zebra_result (zh, &rr->errcode, &rr->errstring);
438     }
439     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
440     {
441         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
442         yaz_log (LOG_LOG, "Received DB Update");
443         if (up->which == Z_IUUpdate_esRequest)
444         {
445             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
446             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
447             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
448             
449             yaz_log (LOG_LOG, "action");
450             if (toKeep->action)
451             {
452                 switch (*toKeep->action)
453                 {
454                 case Z_IUOriginPartToKeep_recordInsert:
455                     yaz_log (LOG_LOG, "recordInsert");
456                     break;
457                 case Z_IUOriginPartToKeep_recordReplace:
458                     yaz_log (LOG_LOG, "recordUpdate");
459                     break;
460                 case Z_IUOriginPartToKeep_recordDelete:
461                     yaz_log (LOG_LOG, "recordDelete");
462                     break;
463                 case Z_IUOriginPartToKeep_elementUpdate:
464                     yaz_log (LOG_LOG, "elementUpdate");
465                     break;
466                 case Z_IUOriginPartToKeep_specialUpdate:
467                     yaz_log (LOG_LOG, "specialUpdate");
468                     break;
469                 case Z_ESAdminOriginPartToKeep_shutdown:
470                     yaz_log (LOG_LOG, "shutDown");
471                     break;
472                 case Z_ESAdminOriginPartToKeep_start:
473                     yaz_log (LOG_LOG, "start");
474                     break;
475                 default:
476                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
477                 }
478             }
479             if (toKeep->databaseName)
480             {
481                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
482
483                 if (zebra_select_database(zh, toKeep->databaseName))
484                     return 0;
485             }
486             else
487             {
488                 yaz_log (LOG_WARN, "no database supplied for ES Update");
489                 rr->errcode = 1008;
490                 rr->errstring = "database";
491                 return 0;
492             }
493             if (notToKeep)
494             {
495                 int i;
496                 zebra_begin_trans (zh);
497                 for (i = 0; i < notToKeep->num; i++)
498                 {
499                     Z_External *rec = notToKeep->elements[i]->record;
500                     struct oident *oident = 0;
501                     Odr_oct *recid = notToKeep->elements[i]->u.opaque;
502
503                     if (!recid)
504                     {
505                         rr->errcode = 224;
506                         rr->errstring = "record Id not supplied";
507                         break;
508                     }
509                     if (notToKeep->elements[i]->which !=
510                         Z_IUSuppliedRecords_elem_opaque)
511                     {
512                         rr->errcode = 224;
513                         rr->errstring = "only opaque record ID supported";
514                         break;
515                     }
516                         
517                     if (rec->direct_reference)
518                     {
519                         oident = oid_getentbyoid(rec->direct_reference);
520                         if (oident)
521                             yaz_log (LOG_LOG, "record %d type %s", i,
522                                      oident->desc);
523                     }
524                     switch (rec->which)
525                     {
526                     case Z_External_sutrs:
527                         if (rec->u.octet_aligned->len > 170)
528                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
529                                      rec->u.sutrs->len,
530                                      rec->u.sutrs->buf);
531                         else
532                             yaz_log (LOG_LOG, "%d bytes:\n%s",
533                                      rec->u.sutrs->len,
534                                      rec->u.sutrs->buf);
535                         break;
536                     case Z_External_octet:
537                         if (rec->u.octet_aligned->len > 170)
538                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
539                                      rec->u.octet_aligned->len,
540                                      rec->u.octet_aligned->buf);
541                         else
542                             yaz_log (LOG_LOG, "%d bytes\n%s",
543                                      rec->u.octet_aligned->len,
544                                      rec->u.octet_aligned->buf);
545                     }
546                     if (oident && oident->value != VAL_TEXT_XML)
547                     {
548                         rr->errcode = 224;
549                         rr->errstring = "only XML update supported";
550                         break;
551                     }
552                     if (rec->which == Z_External_octet)
553                     {
554                         int action = 0;
555
556                         if (*toKeep->action ==
557                             Z_IUOriginPartToKeep_recordInsert)
558                             action = 1;
559                         if (*toKeep->action ==
560                             Z_IUOriginPartToKeep_recordReplace)
561                             action = 2;
562                         if (*toKeep->action ==
563                             Z_IUOriginPartToKeep_recordDelete)
564                             action = 3;
565                         if (*toKeep->action ==
566                             Z_IUOriginPartToKeep_specialUpdate)
567                             action = 1;
568
569                         if (!action)
570                         {
571                             rr->errcode = 224;
572                             rr->errstring = "unsupported ES Update action";
573                             break;
574                         }
575                         else
576                         {
577                             int r = zebra_admin_exchange_record (
578                                 zh, toKeep->databaseName,
579                                 rec->u.octet_aligned->buf,
580                                 rec->u.octet_aligned->len,
581                                 recid->buf, recid->len,
582                                 action);
583                             if (r && *toKeep->action ==
584                                 Z_IUOriginPartToKeep_specialUpdate)
585                             {
586                                 r = zebra_admin_exchange_record (
587                                     zh, toKeep->databaseName,
588                                     rec->u.octet_aligned->buf,
589                                     rec->u.octet_aligned->len,
590                                     recid->buf, recid->len,
591                                     2);
592                             }
593                             if (r)
594                             {
595                                 rr->errcode = 224;
596                                 rr->errstring = "record exchange failed";
597                                 break;
598                             }
599                         }
600                     }
601                 }
602                 zebra_end_trans (zh);
603             }
604         }
605     }
606     else
607     {
608         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
609                  rr->esr->taskSpecificParameters->which);
610         rr->errcode = 221;
611         
612     }
613     return 0;
614 }
615
616 static void bend_start (struct statserv_options_block *sob)
617 {
618 #ifdef WIN32
619     
620 #else
621     if (!sob->inetd) 
622     {
623         char *pidfile = "zebrasrv.pid";
624         int fd = creat (pidfile, 0666);
625         if (fd == -1)
626             logf (LOG_WARN|LOG_ERRNO, "creat %s", pidfile);
627         else
628         {
629             char pidstr[30];
630         
631             sprintf (pidstr, "%ld", (long) getpid ());
632             write (fd, pidstr, strlen(pidstr));
633             close (fd);
634         }
635     }
636 #endif
637     if (sob->handle)
638         zebra_stop((ZebraService) sob->handle);
639     sob->handle = zebra_start(sob->configname);
640     if (!sob->handle)
641     {
642         yaz_log (LOG_FATAL, "Failed to read config `%s'", sob->configname);
643         exit (1);
644     }
645 }
646
647 static void bend_stop(struct statserv_options_block *sob)
648 {
649 #ifdef WIN32
650
651 #else
652     if (!sob->inetd) 
653         unlink ("zebrasrv.pid");
654 #endif
655     if (sob->handle)
656     {
657         ZebraService service = sob->handle;
658         zebra_stop(service);
659     }
660 }
661
662 int main (int argc, char **argv)
663 {
664     struct statserv_options_block *sob;
665
666     sob = statserv_getcontrol ();
667     strcpy (sob->configname, "zebra.cfg");
668     sob->bend_start = bend_start;
669     sob->bend_stop = bend_stop;
670 #ifdef WIN32
671     strcpy (sob->service_display_name, "Zebra Server");
672 #endif
673     statserv_setcontrol (sob);
674
675     return statserv_main (argc, argv, bend_init, bend_close);
676 }