2 * Copyright (c) 1995, the EUROPAGATE consortium (see below).
4 * The EUROPAGATE consortium members are:
6 * University College Dublin
7 * Danmarks Teknologiske Videnscenter
8 * An Chomhairle Leabharlanna
9 * Consejo Superior de Investigaciones Cientificas
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,
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.
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.
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.
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.
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.
45 * Implementation of resource management.
47 * Europagate, 1994-1995.
50 * Revision 1.7 1995/05/16 09:40:49 adam
53 * Revision 1.6 1995/04/19 12:12:07 adam
54 * Resource system uses only one log debug level.
56 * Revision 1.5 1995/02/23 08:32:22 adam
59 * Revision 1.3 1995/02/21 14:00:11 adam
62 * Revision 1.2 1995/02/16 13:21:30 adam
63 * A few logging messages added.
65 * Revision 1.1.1.1 1995/02/09 17:27:12 adam
66 * Initial version of email gateway under CVS control.
68 * Initial: Dec 8, 94 (Adam Dickmeiss)
82 #include <sys/types.h>
89 symtab_open: Create empty symbol table.
90 symbol table handle is returned.
93 static struct res_symtab *symtab_open (void)
95 struct res_symtab *symtab;
97 symtab = malloc (sizeof(*symtab));
105 symtab_close: Delete symbol table.
107 static void symtab_close (struct res_symtab *symtab)
109 struct res_sym_entry *entry, *entry1;
111 for (entry = symtab->next; entry; entry = entry1)
113 entry1 = entry->next;
120 symtab_override: Add symbol to table. 'rl' holds symbol
121 table entry info. If the symbol is already present it
122 will override old info.
124 static int symtab_override (struct res_symtab *symtab,
125 struct res_line_info *rl)
127 struct res_sym_entry *entry;
129 for (entry = symtab->next; entry; entry=entry->next)
130 if (!strcmp (entry->info->name, rl->name))
135 entry = malloc (sizeof(*entry));
138 entry->next = symtab->next;
139 symtab->next = entry;
145 symtab_lookup: Symbol table lookup. If successful info is returned;
146 otherwise NULL is returned.
148 static struct res_line_info *symtab_lookup (struct res_symtab *symtab,
151 struct res_sym_entry *entry;
153 for (entry = symtab->next; entry; entry=entry->next)
154 if (!strcmp (entry->info->name, name))
160 lock_file: File locking using fcntl.
163 static void lock_file (int fd, int type)
167 area.l_whence = SEEK_SET;
170 fcntl (fd, F_SETLKW, &area);
175 gw_res_init: A resource handle is returned by this function
176 describing empty resources.
178 GwRes gw_res_init (void)
182 if (!(p = malloc (sizeof(*p))))
185 p->symtab = symtab_open ();
195 gw_res_close: The resources described by 'id' are freed.
196 No further references to 'id' are allowed.
198 void gw_res_close (GwRes id)
200 struct res_line_info *rl, *rl1;
201 struct res_file_info *rf, *rf1;
205 symtab_close (id->symtab);
206 for (rf = id->files; rf; rf = rf1)
208 for (rl = rf->lines; rl; rl = rl1)
223 add_name: add a node with line information.
225 static struct res_line_info *add_name (enum res_kind kind,
226 const char *name, const char *value)
228 struct res_line_info *rl;
230 if (!(rl = malloc (sizeof(*rl))))
236 rl->name = gw_strdup (name);
247 rl->value = gw_strdup (value);
261 gw_res_merge: The resources described by 'id' are merged by the contents
262 of 'filename'. If a resource is duplicated (in both resources 'id'
263 and the file) the resource is set to the value specified in 'filename'.
264 This function returns 0 on success; -1 on failure ('filename'
267 int gw_res_merge (GwRes id, const char *filename)
272 struct res_file_info *ri;
273 struct res_line_info **rlp, *rl;
274 struct res_line_info *rl_last = NULL;
279 gw_log (RES_DEBUG, "res", "gw_res_merge");
280 gw_log (RES_DEBUG, "res", "checking %s", filename);
281 if (!(inf = fopen (filename, "r")))
284 flock (fileno(inf), LOCK_SH);
286 lock_file (fileno (inf), F_RDLCK);
288 if (!(ri = malloc (sizeof (*ri))))
293 if (!(ri->fname = gw_strdup (filename)))
299 gw_log (RES_DEBUG, "res", "reading %s", filename);
300 ri->next = id->files;
304 while (fgets (buffer, sizeof(buffer)-1, inf))
307 while ((cp = strchr (buffer, '\n')))
311 rl = add_name (comment, NULL, buffer);
320 else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
323 while (buffer[i] == ' ' || buffer[i] == '\t')
325 if (buffer[i] == '\0')
327 rl = add_name (blank, NULL, NULL);
337 { /* continuation line */
338 int j = strlen (buffer)-1;
339 /* strip trailing blanks */
340 while (buffer[j] == '\t' || buffer[j] == ' ')
345 if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
347 gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
348 " truncated", rl_last->name);
352 /* effectively add one blank, then buffer */
354 strcat (value, buffer+i);
358 gw_log (GW_LOG_WARN, "res", "Resource file has bad "
359 "continuation line");
363 { /* resource line */
367 rl_last->value = gw_strdup (value);
370 while (buffer[i] && buffer[i] != ':')
372 if (buffer[i] == ':')
374 int j = strlen(buffer)-1;
375 buffer[i++] = '\0'; /* terminate name */
376 while (buffer[i] == ' ' || buffer[i] == '\t')
377 i++; /* skip blanks before */
378 while (buffer[j] == '\t' || buffer[j] == ' ')
379 --j; /* skip blanks after */
380 buffer[j+1] = '\0'; /* terminate value */
381 strcpy (value, buffer+i);
382 rl_last = add_name (resource, buffer, NULL);
388 rlp = &rl_last->next;
394 rl_last->value = gw_strdup (value);
396 flock (fileno (inf), LOCK_UN);
398 lock_file (fileno (inf), F_UNLCK);
401 gw_log (RES_DEBUG, "res", "close of %s", filename);
402 for (rl = ri->lines; rl; rl = rl->next)
407 gw_log (RES_DEBUG, "res", "%s", rl->value);
410 gw_log (RES_DEBUG, "res", "%s: %s", rl->name, rl->value);
411 if (symtab_override (id->symtab, rl) < 0)
415 gw_log (RES_DEBUG, "res", "");
421 gw_log (RES_DEBUG, "res", "gw_res_merge returned %d", err);
426 gw_res_get: The resource with name 'name' is checked in the resources
427 represented by 'id'. If the resource is present a pointer to the
428 value (null-terminated string) is returned. If the value is not
429 present the value of 'def' is returned.
431 const char *gw_res_get (GwRes id, const char *name, const char *def)
433 struct res_line_info *rl;
436 rl = symtab_lookup (id->symtab, name);
443 gw_res_put: Change a resource - modify if it exists - add if not
444 already there. The resource will have impact on the file name
445 'fname'. Use gw_res_commit (see below) to actually write to the
448 int gw_res_put (GwRes id, const char *name, const char *value,
451 struct res_file_info *ri;
452 struct res_line_info **rlp;
456 for (ri = id->files; ri; ri = ri->next)
457 if (!strcmp (ri->fname, fname))
461 if (!(ri = malloc (sizeof (*ri))))
463 if (!(ri->fname = gw_strdup (fname)))
468 ri->next = id->files;
472 for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
473 if (!strcmp ((*rlp)->name, name))
477 char *new_val = gw_strdup (value);
480 free ((*rlp)->value);
481 (*rlp)->value = new_val;
485 *rlp = add_name (resource, name, value);
489 if (symtab_override (id->symtab, *rlp) < 0)
496 gw_res_commit: Write the resource file 'fname'. If resources
497 are modified/added then these will be written now.
499 int gw_res_commit (GwRes id, const char *fname)
501 struct res_file_info *ri;
502 struct res_line_info *rl;
509 for (ri = id->files; ri; ri = ri->next)
510 if (!strcmp (ri->fname, fname))
514 if (!(out = fopen (fname, "w")))
517 flock (fileno (out), LOCK_EX);
519 lock_file (fileno (out), F_WRLCK);
521 for (rl = ri->lines; rl; rl = rl->next)
525 fputs (rl->value, out);
530 fprintf (out, "%s: ", rl->name);
531 pos = strlen(rl->name)+2;
536 if ((int) strlen(rl->value+i) <= left)
540 if (rl->value[i+left] == ' ')
548 for (j = 0; j<left; j++)
549 fputc (rl->value[i+j], out);
554 fprintf (out, "\n ");
557 fprintf (out, "%s\n", rl->value+i);
564 flock (fileno (out), LOCK_UN);
566 lock_file (fileno (out), F_UNLCK);
573 gw_res_trav: Traverse resources associated with file 'fname'. For
574 each resource the handler 'tf' is invoked with name and value.
576 int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
584 struct res_file_info *ri;
585 struct res_line_info *rl;
587 for (ri = id->files; ri; ri = ri->next)
588 if (!strcmp (ri->fname, fname))
592 for (rl = ri->lines; rl; rl = rl->next)
593 if (rl->kind == resource)
594 (*tf) (rl->name, rl->value);
598 struct res_sym_entry *entry;
600 for (entry = id->symtab->next; entry; entry=entry->next)
601 (*tf) (entry->info->name, entry->info->value);