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