LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res.
[egate.git] / kernel / persist.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /* Gateway kernel - Z39.50 Persistence
45  * Europagate, 1995
46  *
47  * $Log: persist.c,v $
48  * Revision 1.8  1995/05/16 09:40:43  adam
49  * LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res.
50  *
51  * Revision 1.7  1995/05/03  16:34:19  adam
52  * CCL def command, i.e. user definitions - saved as resource files.
53  *
54  * Revision 1.6  1995/05/03  07:37:44  adam
55  * CCL commands stop/continue implemented. New functions gw_res_{int,bool}
56  * are used when possible.
57  *
58  * Revision 1.5  1995/05/02  15:26:00  adam
59  * Monitor observes death of child (email kernel). The number
60  * of simultanous processes is controlled now. Email requests are
61  * queued if necessary. This scheme should only be forced if no kernels
62  * are idle.
63  *
64  * Revision 1.4  1995/04/20  16:10:46  adam
65  * Modified to work with non-blocking zass-api. Not using non-blocking
66  * facility yet.
67  *
68  * Revision 1.3  1995/04/19  13:19:09  adam
69  * New command: account - for authentication.
70  *
71  * Revision 1.2  1995/04/19  10:46:19  adam
72  * Persistency works much better now. New command: status - history-like
73  *
74  * Revision 1.1  1995/04/19  07:31:10  adam
75  * First work on Z39.50 persistence.
76  *
77  */
78
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <assert.h>
82 #include <ctype.h>
83 #include <string.h>
84 #include <unistd.h>
85 #include <fcntl.h>
86
87 #include "kernel.h"
88
89 static int fgetsx (char *buf, int size, FILE *inf)
90 {
91     char *cp;
92
93     if (!fgets (buf, size, inf))
94         return 0;
95     if ((cp = strchr (buf, '\n')))
96         *cp = '\0';
97     return 1;
98 }
99
100 static int set_change;
101
102 static int obtain_set (ZASS zass, struct gw_user_set *set)
103 {
104     const struct zass_searchent *p;
105
106     p = zass_search (zass, set->rpn, set->name, set->database, NULL);
107     if (!p)
108         return 2;
109     if (p->errcode != -1)
110         return 3;
111     if (p->num != set->hits)
112         set_change = 1;
113     set->present_flag = 1;
114     set->hits = p->num;
115     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s researched", set->name);
116     return 0;
117 }
118
119 static int obtain_sets (ZASS zass, struct ccl_rpn_node *rpn, 
120                         struct gw_user_set *sets)
121 {
122     struct gw_user_set *set;
123     int r;
124
125     switch (rpn->kind)
126     {
127     case CCL_RPN_AND:
128     case CCL_RPN_OR:
129     case CCL_RPN_NOT:
130     case CCL_RPN_PROX:
131         if ((r=obtain_sets (zass, rpn->u.p[0], sets)))
132             return r;
133         return obtain_sets (zass, rpn->u.p[1], sets);
134     case CCL_RPN_TERM:
135         return 0;
136     case CCL_RPN_SET:
137         set = user_set_search (rpn->u.setname);
138         if (!set)
139         {
140             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s not there at all",
141                     rpn->u.setname);
142             return 1;
143         }
144         if (set->present_flag)
145         {
146             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s already there",
147                     rpn->u.setname);
148             return 0;
149         }
150     }
151     return obtain_set (zass, set);
152 }
153
154 const struct zass_searchent *zass_p_search (ZASS zass, 
155                         struct ccl_rpn_node *rpn, 
156                         const char *result_set,
157                         const char *database,
158                         struct gw_user_set *sets)
159 {
160     int r;
161
162     set_change = 0;
163     r = obtain_sets (zass, rpn, sets);
164     if (r)
165         return NULL;
166     return zass_search (zass, rpn, (char*) result_set, (char*) database, NULL);
167 }
168
169 const struct zass_presentent *zass_p_present (ZASS zass,
170                         const char *result_set, int offset, int number)
171 {
172     struct gw_user_set *set;
173
174     set = user_set_search (result_set);
175     if (!set)
176         return NULL;
177     if (!set->present_flag)
178     {
179         const struct zass_searchent *p;
180
181         p = zass_p_search (zass, set->rpn, result_set, set->database,
182                            info.sets);
183         if (!p)
184             return NULL;
185     }
186     return zass_present (zass, (char*) result_set, offset, number, NULL);
187 }
188
189 struct ccl_rpn_node *load_rpn (char *buf, FILE *inf)
190 {
191     struct ccl_rpn_node *rpn;
192     struct ccl_rpn_attr **attrp;
193     int type, value, no_read;
194     char *cp;
195
196     if (!fgetsx (buf, 1024, inf))
197         return NULL;
198     rpn = malloc (sizeof (*rpn));
199     if (!rpn)
200         return NULL;
201     switch (*buf)
202     {
203     case 'A':
204         rpn->kind = CCL_RPN_AND;
205         rpn->u.p[0] = load_rpn (buf, inf);
206         rpn->u.p[1] = load_rpn (buf, inf);
207         break;
208     case 'O':
209         rpn->kind = CCL_RPN_OR;
210         rpn->u.p[0] = load_rpn (buf, inf);
211         rpn->u.p[1] = load_rpn (buf, inf);
212         break;
213     case 'N':
214         rpn->kind = CCL_RPN_NOT;
215         rpn->u.p[0] = load_rpn (buf, inf);
216         rpn->u.p[1] = load_rpn (buf, inf);
217         break;
218     case 'P':
219         rpn->kind = CCL_RPN_PROX;
220         rpn->u.p[0] = load_rpn (buf, inf);
221         rpn->u.p[1] = load_rpn (buf, inf);
222         break;
223     case 'T':
224         rpn->kind = CCL_RPN_TERM;
225
226         rpn->u.t.term = gw_strdup (buf+2);
227         attrp = &rpn->u.t.attr_list;
228         if (!fgetsx (buf, 1024, inf))
229             return NULL;
230         cp = buf;
231         while (sscanf (cp, "%d %d%n", &type, &value, &no_read) > 1)
232         {
233             *attrp = malloc (sizeof(**attrp));
234             (*attrp)->type = type;
235             (*attrp)->value = value;
236             attrp = &(*attrp)->next;
237             cp += no_read; 
238         }
239         *attrp = NULL;
240         break;
241     case 'S':
242         rpn->kind = CCL_RPN_SET;
243         rpn->u.setname = gw_strdup (buf+2);
244         break;
245     default:
246         free (rpn);
247         return NULL;
248     }
249     return rpn;
250 }
251
252 int load_p_state (int userid)
253 {
254     FILE *inf;
255     char fname[128];
256     char fline[1025];
257     char database[1024];
258     char resultname[32];
259     int hits;
260     struct gw_user_set *set;
261
262     sprintf (fname, "user.%d.p", userid);
263
264     inf = fopen (fname, "r");
265     if (!inf)
266     {
267         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
268                 "Couldn't open %s", fname);
269         return -1;
270     }
271     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
272        "Reading persistence file %s", fname);
273
274     if (!fgetsx (fline, 1024, inf))
275         return -1;
276     if (sscanf (fline, "%s", info.target) != 1)
277         *info.target = '\0';
278     read_kernel_res ();
279
280     if (!fgetsx (fline, 1024, inf))
281         return -1;
282     if (sscanf (fline, "%s", info.account) != 1)
283         *info.account = '\0';
284    
285     if (!fgetsx (fline, 1024, inf))
286         return -1;
287     free (info.database);
288     info.database = gw_strdup (fline);
289
290     if (!fgetsx (fline, 1024, inf))
291         return -1;
292     if (sscanf (fline, "%d", &info.setno) != 1)
293         return -1;
294     if (!fgetsx (fline, 1024, inf))
295         return -1;
296     if (sscanf (fline, "%d", &info.next_position) != 1)
297         return -1;
298     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
299            "Reading persistence file %s (2)", fname);
300 #if 0
301     reopen_target ();
302 #endif
303     while (fgetsx (fline, 1024, inf))
304     {
305         gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
306               "Reading persistence file %s (3)", fname);
307         if (sscanf (fline, "%s %d %s", resultname, &hits, database) != 3)
308             return -1;
309         if (!fgetsx (fline, 1024, inf))        /* search string */
310             return -1;
311         gw_log (GW_LOG_DEBUG, KERNEL_LOG,
312                 "Adding %s, %d hits, database %s",
313                 resultname, hits, database);
314         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Search string %s", fline);
315         set = user_set_add (resultname, hits, database, NULL, 0, fline);
316         set->rpn = load_rpn (fline, inf);
317         ccl_pr_tree (set->rpn, stderr);
318         fgetsx (fline, 1024, inf);
319     }
320     fclose (inf);
321     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Finished reading %s", fname);
322     return 0;
323 }
324
325 static void save_rpn (struct ccl_rpn_node *rpn, FILE *of)
326 {
327     struct ccl_rpn_attr *attr;
328
329     switch (rpn->kind)
330     {
331     case CCL_RPN_AND:
332         fprintf (of, "A\n");
333         save_rpn (rpn->u.p[0], of);
334         save_rpn (rpn->u.p[1], of);
335         break;
336     case CCL_RPN_OR:
337         fprintf (of, "O\n");
338         save_rpn (rpn->u.p[0], of);
339         save_rpn (rpn->u.p[1], of);
340         break;
341     case CCL_RPN_NOT:
342         fprintf (of, "N\n");
343         save_rpn (rpn->u.p[0], of);
344         save_rpn (rpn->u.p[1], of);
345         break;
346     case CCL_RPN_PROX:
347         fprintf (of, "P\n");
348         save_rpn (rpn->u.p[0], of);
349         save_rpn (rpn->u.p[1], of);
350         break;
351     case CCL_RPN_TERM:
352         fprintf (of, "T %s\n", rpn->u.t.term);
353         for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
354             fprintf (of, "%d %d ", attr->type, attr->value);
355         fprintf (of, "\n");
356         break;
357     case CCL_RPN_SET:
358         fprintf (of, "S %s\n", rpn->u.setname); 
359     }
360 }
361
362 static void save_sets (FILE *of, struct gw_user_set *sp)
363 {
364     if (!sp)
365         return;
366     save_sets (of, sp->prev);
367     fprintf (of, "%s %d %s\n%s\n", sp->name, sp->hits, sp->database,
368              sp->search_str);
369     save_rpn (sp->rpn, of);
370     fprintf (of, "X\n");
371 }
372
373 int save_p_state (int userid)
374 {
375     FILE *of;
376     char fname[128];
377
378     sprintf (fname, "user.%d.p", userid);
379
380     of = fopen (fname, "w");
381     if (!of)
382     {
383         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
384                 "Couldn't open %s", fname);
385         return -1;
386     }
387     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Writing persistence file %s", fname);
388     fprintf (of, "%s\n%s\n%s\n%d\n%d\n", info.target, info.account,
389              info.database, info.setno, info.next_position);
390     save_sets (of, info.sets);
391     fclose (of);
392     return 0;
393 }
394
395 void del_p_state (int userid)
396 {
397     char fname[128];
398
399     sprintf (fname, "user.%d.p", userid);
400     unlink (fname);
401 }
402