Run latex
[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.10  1995/07/20 08:16:38  adam
49  * Bug fix in persist.c: Double referenced result-sets weren't recovered.
50  *
51  * Revision 1.9  1995/05/19  13:26:00  adam
52  * Bug fixes. Better command line options.
53  *
54  * Revision 1.8  1995/05/16  09:40:43  adam
55  * LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res.
56  *
57  * Revision 1.7  1995/05/03  16:34:19  adam
58  * CCL def command, i.e. user definitions - saved as resource files.
59  *
60  * Revision 1.6  1995/05/03  07:37:44  adam
61  * CCL commands stop/continue implemented. New functions gw_res_{int,bool}
62  * are used when possible.
63  *
64  * Revision 1.5  1995/05/02  15:26:00  adam
65  * Monitor observes death of child (email kernel). The number
66  * of simultanous processes is controlled now. Email requests are
67  * queued if necessary. This scheme should only be forced if no kernels
68  * are idle.
69  *
70  * Revision 1.4  1995/04/20  16:10:46  adam
71  * Modified to work with non-blocking zass-api. Not using non-blocking
72  * facility yet.
73  *
74  * Revision 1.3  1995/04/19  13:19:09  adam
75  * New command: account - for authentication.
76  *
77  * Revision 1.2  1995/04/19  10:46:19  adam
78  * Persistency works much better now. New command: status - history-like
79  *
80  * Revision 1.1  1995/04/19  07:31:10  adam
81  * First work on Z39.50 persistence.
82  *
83  */
84
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <assert.h>
88 #include <ctype.h>
89 #include <string.h>
90 #include <unistd.h>
91 #include <fcntl.h>
92
93 #include "kernel.h"
94
95 static int fgetsx (char *buf, int size, FILE *inf)
96 {
97     char *cp;
98
99     if (!fgets (buf, size, inf))
100         return 0;
101     if ((cp = strchr (buf, '\n')))
102         *cp = '\0';
103     return 1;
104 }
105
106 static int set_change;
107
108 static int obtain_set (ZASS zass, struct gw_user_set *set)
109 {
110     const struct zass_searchent *p;
111     
112     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s must be obtained", set->name);
113     p = zass_search (zass, set->rpn, set->name, set->database, NULL);
114     if (!p)
115         return 2;
116     if (p->errcode != -1)
117         return 3;
118     if (p->num != set->hits)
119         set_change = 1;
120     set->present_flag = 1;
121     set->hits = p->num;
122     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s researched", set->name);
123     return 0;
124 }
125
126 static int obtain_sets (ZASS zass, struct ccl_rpn_node *rpn, 
127                         struct gw_user_set *sets)
128 {
129     struct gw_user_set *set;
130     int r;
131
132     switch (rpn->kind)
133     {
134     case CCL_RPN_AND:
135     case CCL_RPN_OR:
136     case CCL_RPN_NOT:
137     case CCL_RPN_PROX:
138         if ((r=obtain_sets (zass, rpn->u.p[0], sets)))
139             return r;
140         return obtain_sets (zass, rpn->u.p[1], sets);
141     case CCL_RPN_TERM:
142         return 0;
143     case CCL_RPN_SET:
144         set = user_set_search (rpn->u.setname);
145         if (!set)
146         {
147             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s not there at all",
148                     rpn->u.setname);
149             return 1;
150         }
151         if (set->present_flag)
152         {
153             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s already there",
154                     rpn->u.setname);
155             return 0;
156         }
157     }
158     obtain_sets (zass, set->rpn, sets);
159     return obtain_set (zass, set);
160 }
161
162 const struct zass_searchent *zass_p_search (ZASS zass, 
163                         struct ccl_rpn_node *rpn, 
164                         const char *result_set,
165                         const char *database,
166                         struct gw_user_set *sets)
167 {
168     int r;
169
170     set_change = 0;
171     r = obtain_sets (zass, rpn, sets);
172     if (r)
173         return NULL;
174     return zass_search (zass, rpn, (char*) result_set, (char*) database, NULL);
175 }
176
177 const struct zass_presentent *zass_p_present (ZASS zass,
178                         const char *result_set, int offset, int number)
179 {
180     struct gw_user_set *set;
181
182     set = user_set_search (result_set);
183     if (!set)
184         return NULL;
185     if (!set->present_flag)
186     {
187         const struct zass_searchent *p;
188
189         p = zass_p_search (zass, set->rpn, result_set, set->database,
190                            info.sets);
191         if (!p)
192             return NULL;
193     }
194     return zass_present (zass, (char*) result_set, offset, number, NULL);
195 }
196
197 struct ccl_rpn_node *load_rpn (char *buf, FILE *inf)
198 {
199     struct ccl_rpn_node *rpn;
200     struct ccl_rpn_attr **attrp;
201     int type, value, no_read;
202     char *cp;
203
204     if (!fgetsx (buf, 1024, inf))
205         return NULL;
206     rpn = malloc (sizeof (*rpn));
207     if (!rpn)
208         return NULL;
209     switch (*buf)
210     {
211     case 'A':
212         rpn->kind = CCL_RPN_AND;
213         rpn->u.p[0] = load_rpn (buf, inf);
214         rpn->u.p[1] = load_rpn (buf, inf);
215         break;
216     case 'O':
217         rpn->kind = CCL_RPN_OR;
218         rpn->u.p[0] = load_rpn (buf, inf);
219         rpn->u.p[1] = load_rpn (buf, inf);
220         break;
221     case 'N':
222         rpn->kind = CCL_RPN_NOT;
223         rpn->u.p[0] = load_rpn (buf, inf);
224         rpn->u.p[1] = load_rpn (buf, inf);
225         break;
226     case 'P':
227         rpn->kind = CCL_RPN_PROX;
228         rpn->u.p[0] = load_rpn (buf, inf);
229         rpn->u.p[1] = load_rpn (buf, inf);
230         break;
231     case 'T':
232         rpn->kind = CCL_RPN_TERM;
233
234         rpn->u.t.term = gw_strdup (buf+2);
235         attrp = &rpn->u.t.attr_list;
236         if (!fgetsx (buf, 1024, inf))
237             return NULL;
238         cp = buf;
239         while (sscanf (cp, "%d %d%n", &type, &value, &no_read) > 1)
240         {
241             *attrp = malloc (sizeof(**attrp));
242             (*attrp)->type = type;
243             (*attrp)->value = value;
244             attrp = &(*attrp)->next;
245             cp += no_read; 
246         }
247         *attrp = NULL;
248         break;
249     case 'S':
250         rpn->kind = CCL_RPN_SET;
251         rpn->u.setname = gw_strdup (buf+2);
252         break;
253     default:
254         free (rpn);
255         return NULL;
256     }
257     return rpn;
258 }
259
260 int load_p_state (int userid)
261 {
262     FILE *inf;
263     char fname[128];
264     char fline[1025];
265     char database[1024];
266     char resultname[32];
267     int hits;
268     struct gw_user_set *set;
269
270     sprintf (fname, "user.%d.p", userid);
271
272     inf = fopen (fname, "r");
273     if (!inf)
274     {
275         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
276                 "Couldn't open %s", fname);
277         return -1;
278     }
279     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
280        "Reading persistence file %s", fname);
281
282     if (!fgetsx (fline, 1024, inf))
283         return -1;
284     if (sscanf (fline, "%s", info.target) != 1)
285         *info.target = '\0';
286     read_kernel_res ();
287
288     if (!fgetsx (fline, 1024, inf))
289         return -1;
290     if (sscanf (fline, "%s", info.account) != 1)
291         *info.account = '\0';
292    
293     if (!fgetsx (fline, 1024, inf))
294         return -1;
295     free (info.database);
296     info.database = gw_strdup (fline);
297
298     if (!fgetsx (fline, 1024, inf))
299         return -1;
300     if (sscanf (fline, "%d", &info.setno) != 1)
301         return -1;
302     if (!fgetsx (fline, 1024, inf))
303         return -1;
304     if (sscanf (fline, "%d", &info.next_position) != 1)
305         return -1;
306     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
307            "Reading persistence file %s (2)", fname);
308     while (fgetsx (fline, 1024, inf))
309     {
310         gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
311               "Reading persistence file %s (3)", fname);
312         if (sscanf (fline, "%s %d %s", resultname, &hits, database) != 3)
313             return -1;
314         if (!fgetsx (fline, 1024, inf))        /* search string */
315             return -1;
316         gw_log (GW_LOG_DEBUG, KERNEL_LOG,
317                 "Adding %s, %d hits, database %s",
318                 resultname, hits, database);
319         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Search string %s", fline);
320         set = user_set_add (resultname, hits, database, NULL, 0, fline);
321         set->rpn = load_rpn (fline, inf);
322 #if 0
323         ccl_pr_tree (set->rpn, stderr);
324 #endif
325         fgetsx (fline, 1024, inf);
326     }
327     fclose (inf);
328     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Finished reading %s", fname);
329     return 0;
330 }
331
332 static void save_rpn (struct ccl_rpn_node *rpn, FILE *of)
333 {
334     struct ccl_rpn_attr *attr;
335
336     switch (rpn->kind)
337     {
338     case CCL_RPN_AND:
339         fprintf (of, "A\n");
340         save_rpn (rpn->u.p[0], of);
341         save_rpn (rpn->u.p[1], of);
342         break;
343     case CCL_RPN_OR:
344         fprintf (of, "O\n");
345         save_rpn (rpn->u.p[0], of);
346         save_rpn (rpn->u.p[1], of);
347         break;
348     case CCL_RPN_NOT:
349         fprintf (of, "N\n");
350         save_rpn (rpn->u.p[0], of);
351         save_rpn (rpn->u.p[1], of);
352         break;
353     case CCL_RPN_PROX:
354         fprintf (of, "P\n");
355         save_rpn (rpn->u.p[0], of);
356         save_rpn (rpn->u.p[1], of);
357         break;
358     case CCL_RPN_TERM:
359         fprintf (of, "T %s\n", rpn->u.t.term);
360         for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
361             fprintf (of, "%d %d ", attr->type, attr->value);
362         fprintf (of, "\n");
363         break;
364     case CCL_RPN_SET:
365         fprintf (of, "S %s\n", rpn->u.setname); 
366     }
367 }
368
369 static void save_sets (FILE *of, struct gw_user_set *sp)
370 {
371     if (!sp)
372         return;
373     save_sets (of, sp->prev);
374     fprintf (of, "%s %d %s\n%s\n", sp->name, sp->hits, sp->database,
375              sp->search_str);
376     save_rpn (sp->rpn, of);
377     fprintf (of, "X\n");
378 }
379
380 int save_p_state (int userid)
381 {
382     FILE *of;
383     char fname[128];
384
385     sprintf (fname, "user.%d.p", userid);
386
387     of = fopen (fname, "w");
388     if (!of)
389     {
390         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
391                 "Couldn't open %s", fname);
392         return -1;
393     }
394     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Writing persistence file %s", fname);
395     fprintf (of, "%s\n%s\n%s\n%d\n%d\n", info.target, info.account,
396              info.database, info.setno, info.next_position);
397     save_sets (of, info.sets);
398     fclose (of);
399     return 0;
400 }
401
402 void del_p_state (int userid)
403 {
404     char fname[128];
405
406     sprintf (fname, "user.%d.p", userid);
407     unlink (fname);
408 }
409