First use of string-queue utility.
[egate.git] / kernel / main.c
1 /* Gateway kernel
2  * Europagate, 1995
3  *
4  * $Log: main.c,v $
5  * Revision 1.14  1995/03/28 11:42:34  adam
6  * First use of string-queue utility.
7  *
8  * Revision 1.13  1995/03/28  08:01:25  adam
9  * FIFO existence is used to test for a running kernel.
10  *
11  * Revision 1.12  1995/03/27  12:51:05  adam
12  * New log level in use: GW_LOG_ERRNO.
13  *
14  * Revision 1.11  1995/03/27  08:24:02  adam
15  * First use of gip interface and gw-db.
16  * First work on eti program.
17  *
18  * Revision 1.10  1995/03/01  14:32:25  adam
19  * Better diagnostics. Default is, that only one database selected when
20  * several are known.
21  *
22  * Revision 1.9  1995/02/23  08:32:17  adam
23  * Changed header.
24  *
25  * Revision 1.7  1995/02/22  15:22:33  adam
26  * Much more checking of run-time state. Show command never retrieves
27  * more records than indicated by the previous search request. Help
28  * command available. The maximum number of records retrieved can be
29  * controlled now.
30  *
31  * Revision 1.6  1995/02/22  08:51:34  adam
32  * Output function can be customized in fml, which is used to print
33  * the reply to reply_fd.
34  *
35  * Revision 1.5  1995/02/20  21:16:20  adam
36  * FML support. Bug fixes. Profile for drewdb.
37  *
38  * Revision 1.4  1995/02/17  17:06:16  adam
39  * Minor changes.
40  *
41  * Revision 1.3  1995/02/16  18:35:09  adam
42  * First use of Zdist library. Search requests are supported.
43  * Present requests are not supported yet.
44  *
45  * Revision 1.2  1995/02/16  13:21:00  adam
46  * Organization of resource files for targets and conversion
47  * language implemented.
48  *
49  * Revision 1.1  1995/02/15  17:45:29  adam
50  * First version of email gateway kernel. Email requests are read
51  * from stdin. The output is transferred to an MTA if 'From' is
52  * found in the header - or stdout if absent. No Z39.50 client is used.
53  *
54  */
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <assert.h>
60 #include <unistd.h>
61 #include <sys/types.h>
62 #include <sys/time.h>
63 #include <fcntl.h>
64
65 #include <gip.h>
66 #include <strqueue.h>
67 #include "kernel.h"
68
69 FILE *reply_fd = stdout;
70
71 struct gw_kernel_info info;
72
73 static void kernel_events (struct str_queue *queue, int userid)
74 {
75     char fifo_client_name[1024];
76     char fifo_server_name[1024];
77     char line_buf[1024];
78     GIP gip;
79     fd_set set_r;
80     int r, gip_fd;
81     struct timeval tv;
82
83     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "kernel event loop");
84
85     sprintf (fifo_client_name, "fifo.c.%d", userid);
86     sprintf (fifo_server_name, "fifo.s.%d", userid);
87
88     gip = gips_initialize (fifo_server_name);
89     gips_open (gip, fifo_client_name);
90     gip_fd = gip_infileno (gip);
91
92     while (1)
93     {
94         FD_ZERO (&set_r);
95         FD_SET (gip_fd, &set_r);
96         tv.tv_sec = 60;
97         tv.tv_usec = 0;
98
99         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "IPC select");
100         r = select (gip_fd+1, &set_r, NULL, NULL, &tv);
101         if (r == -1)
102         {
103             gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, KERNEL_LOG, "select");
104             exit (1);
105         }
106         if (r == 0)
107         {
108             gw_log (GW_LOG_STAT, KERNEL_LOG, "Timeout");
109             break;
110         }
111         if (FD_ISSET (gip_fd, &set_r))
112         {
113             char command[128], *cp;
114
115             if (!(lgets (command, 127, gip_fd)))
116             {
117                 gw_log (GW_LOG_WARN, KERNEL_LOG, "Unexpected close");
118                 break;
119             }
120             if ((cp = strchr (command, '\n')))
121                 *cp = '\0';
122             gw_log (GW_LOG_STAT, KERNEL_LOG, "IPC: %s", command);
123             if (!strcmp (command, "mail"))
124             {
125                 gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Incoming mail...\n");
126                 while (lgets (line_buf, sizeof(line_buf)-1, gip_fd))
127                     str_queue_enq (queue, line_buf);
128                 urp (queue);
129                 while (str_queue_deq (queue, 0, 0))
130                     ;
131             }
132             else if (!strcmp (command, "stop"))
133             {
134                 gw_log (GW_LOG_DEBUG, KERNEL_LOG, "stop");
135                 break;
136             }
137             else 
138             {
139                 gw_log (GW_LOG_WARN, KERNEL_LOG, "Unknown IPC: %s", command);
140             }
141         }
142     }
143     gips_close (gip);
144     gips_destroy (gip);
145     unlink (fifo_client_name);
146     unlink (fifo_server_name);
147 }
148
149 int main (int argc, char **argv)
150 {
151     int userid = -1;
152     struct str_queue *queue;
153
154     info.kernel_res = NULL;
155     info.default_res = "default.res";
156     info.override_res = NULL;
157     *info.target = 0;
158     info.lang = NULL;
159     info.bibset = NULL;
160     info.zass = NULL;
161     info.override_portno = NULL;
162     info.override_hostname = NULL;
163     info.databases = NULL;
164     info.database = NULL;
165 #if USE_FML
166     info.fml = NULL;
167 #endif
168     info.sets = NULL;
169
170     gw_log_init (*argv);
171     info.kernel_res = gw_res_init ();
172     while (--argc > 0)
173     {
174         if (**++argv == '-')
175         {
176             switch (argv[0][1])
177             {
178             case 'H':
179                 fprintf (stderr, "kernel [option..] [resource]\n");
180                 fprintf (stderr, "If no resource file is given");
181                 fprintf (stderr, " default.res is used\n");
182                 fprintf (stderr, "Options:\n");
183                 fprintf (stderr, " -d           Enable debugging log\n");
184                 fprintf (stderr, " -t target    Open target immediately\n");
185                 fprintf (stderr, " -l lang      Set language\n");
186                 fprintf (stderr, " -o resource  Override with resource\n");
187                 fprintf (stderr, " -h host      Override host\n");
188                 fprintf (stderr, " -p port      Override port\n");
189                 fprintf (stderr, " -g log       Set Log file\n");
190                 fprintf (stderr, " -i id        Set IPC userid\n");
191                 exit (1);
192             case 'd':
193                 gw_log_level (GW_LOG_ALL);
194                 break;
195             case 't':
196                 if (argv[0][2])
197                     strcpy (info.target, argv[0]+2);
198                 else if (argc > 0)
199                 {
200                     --argc;
201                     strcpy (info.target, *++argv);
202                 }
203                 else
204                 {
205                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing target name");
206                     exit (1);
207                 }
208                 break;
209             case 'l':
210                 if (argv[0][2])
211                     info.lang = argv[0]+2;
212                 else if (argc > 0)
213                 {
214                     --argc;
215                     info.lang = *++argv;
216                 }
217                 else
218                 {
219                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing language name");
220                     exit (1);
221                 }
222                 break;
223             case 'o':
224                 if (argv[0][2])
225                     info.override_res = argv[0]+2;
226                 else if (argc > 0)
227                 {
228                     --argc;
229                     info.override_res = *++argv;
230                 }
231                 else
232                 {
233                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing override name");
234                     exit (1);
235                 }
236                 break;
237             case 'p':
238                 if (argv[0][2])
239                     info.override_portno = argv[0]+2;
240                 else if (argc > 0)
241                 {
242                     --argc;
243                     info.override_portno = *++argv;
244                 }
245                 else
246                 {
247                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing portno");
248                     exit (1);
249                 }
250                 break;
251             case 'h':
252                 if (argv[0][2])
253                     info.override_hostname = argv[0]+2;
254                 else if (argc > 0)
255                 {
256                     --argc;
257                     info.override_hostname = *++argv;
258                 }
259                 else
260                 {
261                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing hostname");
262                     exit (1);
263                 }
264                 break;
265             case 'g':
266                 if (argv[0][2])
267                     gw_log_file (GW_LOG_ALL, argv[0]+2);
268                 else if (argc > 0)
269                 {
270                     --argc;
271                     gw_log_file (GW_LOG_ALL, *++argv);
272                 }
273                 else
274                 {
275                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing log filename");
276                     exit (1);
277                 }
278                 break;
279             case 'i':
280                 if (argv[0][2])
281                     userid = atoi (argv[0]+2);
282                 else if (argc > 0)
283                 {
284                     --argc;
285                     userid = atoi (*++argv);
286                 }
287                 else
288                 {
289                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing user id");
290                     exit (1);
291                 }
292                 break;
293             default:
294                 gw_log (GW_LOG_FATAL, KERNEL_LOG, "unknown option %s", *argv);
295                 exit (1);
296             }
297         }
298         else
299             info.default_res = *argv;
300     }
301     read_kernel_res ();
302     if (!(queue = str_queue_mk ()))
303     {
304         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, KERNEL_LOG, "str_queue_mk");
305         exit (1);
306     }
307     if (userid != -1)
308         kernel_events (queue, userid);
309     else
310     {
311         char line_buf[512];
312         while (lgets (line_buf, sizeof(line_buf)-1, 0))
313             str_queue_enq (queue, line_buf);
314         urp (queue);
315     }
316     return 0;
317 }
318
319 struct gw_user_set *user_set_add (const char *name, int hits)
320 {
321     struct gw_user_set *s;
322
323     s = malloc (sizeof (*s));
324     assert (s);
325
326     s->name = gw_strdup (name);
327     s->hits = hits;
328     s->prev = info.sets;
329     info.sets = s;
330     return s;
331 }
332
333 void user_set_init (void)
334 {
335     struct gw_user_set *s, *s1;
336
337     for (s = info.sets; s; s = s1)
338     {
339         free (s->name);
340         s1 = s->prev;
341         free (s);
342     }
343     info.sets = NULL;
344 }
345
346 struct gw_user_set *user_set_search (const char *name)
347 {
348     struct gw_user_set *s;
349
350     if (!name)
351         return info.sets;
352     for (s = info.sets; s; s = s->prev)
353         if (!strcmp (s->name, name))
354             return s;
355     return NULL;
356 }
357
358 #if USE_FML
359 static void fml_inf_write (int ch)
360 {
361     putc (ch, reply_fd);
362 }
363 static FILE *fml_inf;
364
365 static int fml_inf_read (void)
366 {
367     return getc (fml_inf);
368 }
369 #endif
370
371 void read_kernel_res (void)
372 {
373     char path_prefix[128];
374     char fname[160];
375     const char *v;
376     char *cp;
377     char resource_name[256];
378
379     user_set_init ();
380
381     if (info.bibset)
382         ccl_qual_rm (&info.bibset);
383     info.bibset = ccl_qual_mk ();
384
385     if (info.kernel_res)
386         gw_res_close (info.kernel_res);
387     info.kernel_res = gw_res_init ();
388
389     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, default %s",
390             info.default_res);
391     if (*info.target)
392         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, target %s",
393                 info.target);
394     if (info.lang)
395         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, lang %s",
396                 info.lang);
397
398     if (gw_res_merge (info.kernel_res, info.default_res))
399     {
400         gw_log (GW_LOG_WARN, KERNEL_LOG, "Couldn't read resource file %s",
401                 info.default_res);
402         return;
403     }
404     strcpy (path_prefix, gw_res_get (info.kernel_res, "gw.path", "."));
405     
406     if (*info.target)
407     {
408         sprintf (resource_name, "gw.target.%s", info.target);
409         v = gw_res_get (info.kernel_res, resource_name, NULL);
410         if (v)
411         {
412             sprintf (fname, "%s/%s", path_prefix, v);
413             gw_res_merge (info.kernel_res, fname);
414         }
415     }
416     if (info.lang)
417     {
418         sprintf (resource_name, "gw.lang.%s", info.lang);
419         v = gw_res_get (info.kernel_res, resource_name, NULL);
420         if (v)
421         {
422             sprintf (fname, "%s/%s", path_prefix, v);
423             gw_res_merge (info.kernel_res, fname);
424         }
425     }
426     if (info.override_res)
427     {
428         sprintf (fname, "%s/%s", path_prefix, info.override_res);
429         gw_res_merge (info.kernel_res, fname);        
430     }
431     v = gw_res_get (info.kernel_res, "gw.bibset", NULL);
432     if (v)
433     {
434         FILE *bib_inf;
435
436         sprintf (fname, "%s/%s", path_prefix, v);
437         bib_inf = fopen (fname, "r");
438         if (!bib_inf)
439             gw_log (GW_LOG_WARN, KERNEL_LOG, "cannot open %s", fname);
440         else
441         {
442             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading bib file %s", fname);
443             ccl_qual_file (info.bibset, bib_inf);
444             fclose (bib_inf);
445         }
446     }
447     sprintf (resource_name, "gw.target.%s", info.target);
448     if (*info.target && ! gw_res_get (info.kernel_res, resource_name, NULL))
449     {
450         /* target is there, and there is no sub-resource for it... */
451         char *split;
452
453         if ((split = strchr (info.target, ':')))
454             *split++ = '\0';
455         strncpy (info.hostname, info.target, sizeof(info.hostname)-1);
456         if (split)
457             info.port = atoi (split);
458         else
459             info.port = atoi (gw_res_get
460                               (info.kernel_res, "gw.portno", "210"));
461     }
462     else
463     {
464         strncpy (info.hostname, gw_res_get (info.kernel_res,
465                                             "gw.hostname", "localhost"),
466                  sizeof(info.hostname)-1);
467         info.port = atoi (gw_res_get (info.kernel_res,
468                                       "gw.portno", "210"));
469     }
470     if (info.databases)
471         free (info.databases);
472     if (info.database)
473         free (info.database);
474     v = gw_res_get (info.kernel_res, "gw.databases", "");
475     info.databases = gw_strdup (v);
476     for (cp = info.databases; (cp = strchr (cp, ' ')); cp++)
477         *cp = ',';
478     v = gw_res_get (info.kernel_res, "gw.database", "");
479     if (*v == '\0' && *info.databases)
480     {
481         int len;
482         cp = strchr (info.databases, ',');
483         
484         len = cp ? (cp-info.databases) : strlen (info.databases);
485         info.database = malloc (len+1);
486         assert (info.database);
487         memcpy (info.database, info.databases, len);
488         info.database[len] = '\0';
489     }
490     else
491     {
492         info.database = gw_strdup (v);
493         for (cp = info.database; (cp = strchr (cp, ' ')); cp++)
494             *cp = ',';
495     }
496     if (info.override_portno)
497         info.port = atoi (info.override_portno);
498     if (info.override_hostname)
499         strncpy (info.hostname, info.override_hostname,
500                  sizeof(info.hostname)-1);
501 #if USE_FML
502     if (!info.fml)
503     {
504         v = gw_res_get (info.kernel_res, "gw.fml", "default.fml");    
505         sprintf (fname, "%s/%s", path_prefix, v);
506         fml_inf = fopen (fname, "r");
507         if (!fml_inf)
508             gw_log (GW_LOG_WARN, KERNEL_LOG,
509                     "cannot open fml script %s", fname);
510         else
511         {
512             info.fml = fml_open ();
513             info.fml->read_func = fml_inf_read;
514             info.fml->write_func = fml_inf_write;
515             fml_preprocess (info.fml);
516             fml_exec (info.fml);
517             fclose (fml_inf);
518         }
519     }
520 #endif
521 }