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