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