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