Resource/config system used by the gateway.
[egate.git] / www / wirtcl.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  * $Log: wirtcl.c,v $
44  * Revision 1.14  1996/02/12 10:10:31  adam
45  * Resource/config system used by the gateway.
46  *
47  * Revision 1.13  1996/01/24  08:26:54  adam
48  * All tcl commands prefixed with egw_ (except the html command).
49  *
50  * Revision 1.12  1996/01/12  10:05:18  adam
51  * If script name ends with ';' HTTP/GET/Expires will be defined.
52  * The cgi interface only reads final handshake if response from
53  * server (shell) was zero-terminated [If it isn't it probably died].
54  *
55  * Revision 1.11  1996/01/09  16:16:49  adam
56  * Port to OSF/1. Gif references moved from /gif/ to /egwgif/.
57  *
58  * Revision 1.10  1996/01/09  10:46:50  adam
59  * New defines: LOGDIR/EGWDIR/CGIDIR set in Makefile.
60  *
61  * Revision 1.9  1995/11/07  14:56:59  adam
62  * Work on search in multiple targets.
63  * New wtcl command: wlog.
64  * Optional timeout parameter to zwait.
65  *
66  * Revision 1.8  1995/11/06  17:44:22  adam
67  * State reestablised when shell restarts. History of previous
68  * result sets.
69  *
70  * Revision 1.7  1995/11/02  16:35:37  adam
71  * Bug fixes and select on FIFOs in wcgi - doesn't really work!
72  *
73  * Revision 1.6  1995/11/01  16:15:47  adam
74  * Better presentation of records. Query/set number persistent.
75  *
76  * Revision 1.5  1995/10/31  16:56:24  adam
77  * Record presentation.
78  *
79  * Revision 1.4  1995/10/31  10:03:53  adam
80  * Work on queries.
81  * New command implemented - aborts script.
82  *
83  * Revision 1.3  1995/10/30  17:35:18  adam
84  * New function zwait that waits for a variable change - due to i/o events
85  * that invoke callback routines.
86  *
87  * Revision 1.2  1995/10/27  17:30:16  adam
88  * First search request/response that works.
89  *
90  * Revision 1.1  1995/10/27  15:12:08  adam
91  * IrTcl incorporated in the gateway.
92  * Better separation of script types.
93  * Z39.50 gateway scripts entered.
94  *
95  */
96
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <unistd.h>
100 #include <sys/time.h>
101 #include <sys/types.h>
102 #ifdef AIX
103 #include <sys/select.h>
104 #endif
105 #include <string.h>
106 #include <assert.h>
107 #include <ctype.h>
108
109 #include <log.h>
110 #include "wtcl.h"
111 #include "wirtcl.h"
112
113 static void *do_create (WCLIENT wcl, void *args);
114 static int do_exec (const char *fname, char *parms, void *mydata);
115 static int do_load (char *parms, void *mydata);
116 static int do_save (char *parms, void *mydata);
117
118 static struct w_interp_type w_interp_t = {
119     "irtcl",
120     do_create,
121     do_exec,
122     do_load,
123     do_save
124 };
125
126 W_Interp_Type w_interp_irtcl = &w_interp_t;
127
128
129 static char *mod = "wirtcl";
130
131 struct tcl_info {
132     W_Interp w_interp;
133     Tcl_Interp *interp;
134     WCLIENT wcl;
135 };
136
137
138 static int events (struct tcl_info *p, char *waitVar, int tout);
139
140 static int proc_zwait_invoke (ClientData clientData, Tcl_Interp *interp,
141                               int argc, char **argv)
142 {
143     struct tcl_info *p = (struct tcl_info*) clientData;
144     
145     if (argc < 2)
146         return TCL_OK;
147     return events (p, argv[1], (argc == 3) ? atoi(argv[2]) : 0);
148 }
149
150
151
152 /* select(2) callbacks */
153 struct callback {
154     void (*r_handle)(ClientData);
155     void (*w_handle)(ClientData);
156     void (*x_handle)(ClientData);
157     void *obj;
158 };
159 #define MAX_CALLBACK 200
160
161 static struct callback callback_table[MAX_CALLBACK];
162 static int max_fd = 3;            /* don't worry: it will grow... */
163
164 static void *do_create (WCLIENT wcl, void *args)
165 {
166     struct tcl_info *p;
167     int i;
168
169     if (!(p = malloc (sizeof(*p))))
170     {
171         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, mod, "malloc: irtcl_info");
172         exit (1);
173     }
174     if (!(p->w_interp = w_interp_create (w_interp_tcl, wcl, NULL)))
175     {
176         gw_log (GW_LOG_FATAL, mod, "Cannot make Tcl_Interp");
177         exit (1);
178     }
179     p->wcl = wcl;
180     p->interp = w_interp_tcl_get (p->w_interp);
181     if (Irtcl_Init(p->interp) == TCL_ERROR)
182     {
183         gw_log (GW_LOG_FATAL, mod, "Cannot make Irtcl_Interp");
184         exit (1);
185     }
186     log_init(LOG_ALL, "irtcl", "irtcl_log");
187     /* initialize irtcl */
188     Tcl_CreateCommand (p->interp, "egw_wait", proc_zwait_invoke, p, NULL);
189     for (i=0; i<MAX_CALLBACK; i++)
190     {
191         callback_table[i].r_handle = NULL;
192         callback_table[i].w_handle = NULL;
193         callback_table[i].x_handle = NULL;
194     }
195     return p;
196 }
197
198
199 static int do_exec (const char *fname, char *parms, void *mydata)
200 {
201     struct tcl_info *p = mydata;
202     int r;
203     if ((r = w_interp_exec (p->w_interp, fname, parms)))
204         return r;
205     return 0;
206 }
207
208
209 static int events (struct tcl_info *p, char *waitVar, int tout)
210 {
211     int r, i;
212     char *cp;
213     char *waitVarVal;
214     static fd_set fdset_tcl_r;
215     static fd_set fdset_tcl_w;
216     static fd_set fdset_tcl_x;
217     int fifo_in = p->wcl->linein;
218     if (fifo_in > max_fd)
219         max_fd = fifo_in;
220
221     assert (waitVar);
222     if ((cp = Tcl_GetVar (p->interp, waitVar, 0)))
223     {
224         waitVarVal = malloc (strlen(cp)+1);
225         strcpy (waitVarVal, cp);
226     }
227     else
228     {
229         char msg[128];
230
231         sprintf (msg, "Variable %s doesn't exist", waitVar);
232         gw_log (GW_LOG_WARN, mod, "%s", msg);
233         Tcl_AppendResult (p->interp, msg, NULL);
234         return TCL_ERROR;
235     }
236     gw_log (GW_LOG_DEBUG, mod, "Waiting %s=%s", waitVar, waitVarVal);
237     while (1)
238     {
239         struct timeval to, *top;
240         if (tout > 0)
241         {
242             to.tv_usec = 0;
243             to.tv_sec = tout;
244             top = &to;
245         }
246         else
247             top = 0;
248
249         if (!(cp = Tcl_GetVar (p->interp, waitVar, 0)) ||
250             strcmp (cp, waitVarVal))
251         {
252             gw_log (GW_LOG_DEBUG, mod, "Changed to %s", cp);
253             Tcl_AppendResult (p->interp, cp, NULL);
254             free (waitVarVal);
255             return TCL_OK;
256         }
257         FD_ZERO (&fdset_tcl_r);
258         FD_ZERO (&fdset_tcl_w);
259         FD_ZERO (&fdset_tcl_x);
260         
261         for (r=0, i=0; i<=max_fd; i++)
262         {
263             if (callback_table[i].w_handle)
264             {
265                 FD_SET (i, &fdset_tcl_w);
266                 r++;
267             }
268             if (callback_table[i].r_handle)
269             {
270                 FD_SET (i, &fdset_tcl_r);
271                 r++;
272             }
273             if (callback_table[i].x_handle)
274             {
275                 FD_SET (i, &fdset_tcl_x);
276                 r++;
277             }
278         }
279         if (!r)
280             break;
281 #if 1
282         gw_log (GW_LOG_DEBUG, mod, "fifo select %d", fifo_in);
283         FD_SET (fifo_in, &fdset_tcl_r);
284 #endif
285         if ((r = select(max_fd+1, &fdset_tcl_r, &fdset_tcl_w, 
286                           &fdset_tcl_x, top)) < 0)
287         {
288             gw_log (GW_LOG_ERRNO|GW_LOG_FATAL, mod, "select");
289             exit(1);
290         }
291         if (!r)
292         {
293             gw_log (GW_LOG_DEBUG, mod, "timeout");
294             free (waitVarVal);
295             return TCL_ERROR;
296         }
297         if (FD_ISSET (fifo_in, &fdset_tcl_r))
298         {
299             gw_log (GW_LOG_DEBUG, mod, "FIFO closed");
300             free (waitVarVal);
301             return TCL_ERROR;
302         }
303         for (i=0; i<=max_fd; i++)
304         {
305             if (FD_ISSET (i, &fdset_tcl_r))
306             {
307                 if (callback_table[i].r_handle)
308                     (*callback_table[i].r_handle) (callback_table[i].obj);
309             }
310             if (FD_ISSET (i, &fdset_tcl_w))
311             {
312                 if (callback_table[i].w_handle)
313                     (*callback_table[i].w_handle) (callback_table[i].obj);
314             }
315             if (FD_ISSET (i, &fdset_tcl_x))
316             {
317                 if (callback_table[i].x_handle)
318                     (*callback_table[i].x_handle) (callback_table[i].obj);
319             }
320         }
321     }
322     free (waitVarVal);
323     return TCL_OK;
324 }
325
326 void ir_select_add (int fd, void *obj)
327 {
328     callback_table[fd].obj = obj;
329     callback_table[fd].r_handle = ir_select_read;
330     callback_table[fd].w_handle = NULL;
331     callback_table[fd].x_handle = NULL;
332     if (fd > max_fd)
333         max_fd = fd;
334 }
335
336 void ir_select_add_write (int fd, void *obj)
337 {
338     callback_table[fd].w_handle = ir_select_write;
339     if (fd > max_fd)
340         max_fd = fd;
341 }
342
343 void ir_select_remove_write (int fd, void *obj)
344 {
345     callback_table[fd].w_handle = NULL;
346 }
347
348 void ir_select_remove (int fd, void *obj)
349 {
350     callback_table[fd].r_handle = NULL;
351     callback_table[fd].w_handle = NULL;
352     callback_table[fd].x_handle = NULL;
353 }
354
355 static int do_load (char *parms, void *mydata)
356 {
357     struct tcl_info *p = mydata;
358
359     return w_interp_load_state (p->w_interp, parms);
360 }
361
362 static int do_save (char *parms, void *mydata)
363 {
364     struct tcl_info *p = mydata;
365
366     return w_interp_save_state (p->w_interp, parms);
367 }
368