source: npl/mailserver/dspam/dspam-3.10.2/src/pref.c

Last change on this file was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/* $Id: pref.c,v 1.38 2011/06/28 00:13:48 sbajic Exp $ */
2
3/*
4 DSPAM
5 COPYRIGHT (C) 2002-2012 DSPAM PROJECT
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Affero General Public License as
9 published by the Free Software Foundation, either version 3 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20*/
21
22#ifdef HAVE_CONFIG_H
23#include <auto-config.h>
24#endif
25
26#include <string.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <errno.h>
30#include <error.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#ifndef _WIN32
34#include <unistd.h>
35#include <pwd.h>
36#endif
37#include <stdio.h>
38#include <stdlib.h>
39#include <errno.h>
40
41#include "pref.h"
42#include "config.h"
43#include "util.h"
44#include "language.h"
45#include "read_config.h"
46
47/*
48 *  _ds_pref_aggregate: aggregate system preferences and user preferences
49 *
50 *  This function takes a set of system preferences and a set of user
51 *  preferences as input and returns an aggregated set of preferences based on
52 *  the system's override rules.
53 */
54
55agent_pref_t _ds_pref_aggregate(agent_pref_t STX, agent_pref_t UTX) {
56  agent_pref_t PTX = calloc(1, PREF_MAX*sizeof(agent_attrib_t ));
57  int i, size = 0;
58
59  if (STX) {
60    for(i=0;STX[i];i++) {
61      PTX[i] = _ds_pref_new(STX[i]->attribute, STX[i]->value);
62      PTX[i+1] = NULL;
63      size++;
64    }
65  }
66
67  if (UTX) {
68    for(i=0;UTX[i];i++) {
69
70      if (_ds_match_attribute(agent_config, "AllowOverride", UTX[i]->attribute))
71      {
72        int found = 0;
73        int j;
74
75        for(j=0;PTX[j];j++) {
76          if (!strcasecmp(PTX[j]->attribute, UTX[i]->attribute)) {
77            found = 1;
78            free(PTX[j]->value);
79            PTX[j]->value = strdup(UTX[i]->value);
80            break;
81          }
82        }
83
84        if (!found) {
85          PTX[size] = _ds_pref_new(UTX[i]->attribute, UTX[i]->value);
86          PTX[size+1] = NULL;
87          size++;
88        }
89      } else {
90        LOG(LOG_ERR, ERR_AGENT_IGNORE_PREF, UTX[i]->attribute);
91      }
92    }
93  }
94
95  return PTX;
96}
97
98int _ds_pref_free(agent_pref_t PTX) {
99  agent_attrib_t pref;
100  int i;
101
102  if (!PTX)
103    return 0;
104
105  for(i=0;PTX[i];i++) {
106    pref = PTX[i];
107
108    free(pref->attribute);
109    free(pref->value);
110    free(pref);
111  }
112
113  return 0;
114}
115
116/*
117 *  _ds_pref_val: returns the value of an attribute within a preference set
118 *
119 *  To allow this function to work with string operations, "" will be returned
120 *  if the value isn't found, insttead of NULL
121 */
122
123const char *_ds_pref_val(
124  agent_pref_t PTX,
125  const char *attrib)
126{
127  agent_attrib_t pref;
128  int i;
129
130  if (PTX == NULL)
131    return "";
132
133  for(i=0;PTX[i];i++) {
134    pref = PTX[i];
135    if (!strcasecmp(pref->attribute, attrib))
136      return pref->value;
137  }
138
139  return "";
140}
141
142agent_attrib_t _ds_pref_new(const char *attribute, const char *value) {
143  agent_attrib_t pref;
144
145  pref = malloc(sizeof(struct _ds_agent_attribute));
146
147  if (pref == NULL) {
148    LOG(LOG_CRIT, ERR_MEM_ALLOC);
149    return NULL;
150  }
151
152  pref->attribute = strdup(attribute);
153  pref->value = strdup(value);
154
155  return pref;
156}
157
158/* flat-file preference extensions (defaulted to if storage driver extensions
159   are not found) */
160
161agent_pref_t _ds_ff_pref_load(
162  config_t config,
163  const char *user,
164  const char *home,
165  void *ignore)
166{
167  char filename[MAX_FILENAME_LENGTH];
168  agent_pref_t PTX = malloc(sizeof(agent_attrib_t )*PREF_MAX);
169  char buff[258];
170  FILE *file;
171  char *p, *q;
172  int i = 0;
173  config = config; /* Keep compiler happy */
174  ignore = ignore; /* Keep compiler happy */
175
176  if (PTX == NULL) {
177    LOG(LOG_CRIT, ERR_MEM_ALLOC);
178    return NULL;
179  }
180  PTX[0] = NULL;
181
182  if (user == NULL) {
183    snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home);
184  } else {
185    _ds_userdir_path (filename, home, user, "prefs");
186  }
187  file = fopen(filename, "r");
188
189  /* Apply default preferences from dspam.conf */
190
191  if (file != NULL) {
192    char *ptrptr;
193    while(i<(PREF_MAX-1) && fgets(buff, sizeof(buff), file)!=NULL) {
194      if (buff[0] == '#' || buff[0] == 0)
195        continue;
196      chomp(buff);
197
198      p = strtok_r(buff, "=", &ptrptr);
199
200      if (p == NULL)
201        continue;
202      q = p + strlen(p)+1;
203
204      LOGDEBUG("Loading preference '%s' = '%s'", p, q);
205
206      PTX[i] = _ds_pref_new(p, q);
207      PTX[i+1] = NULL;
208      i++;
209    }
210    fclose(file);
211  } else {
212    free(PTX);
213    return NULL;
214  }
215
216  return PTX;
217}
218
219/*
220 *  _ds_ff_pref_prepare_file: prepares a backup copy of a preference file
221 *
222 *  This operation prepares a backup copy of a given preference file, using a
223 *  .bak extension and returns an open filehandle to it at the end of the file.
224 *  This function also allows for an omission to be passed in, which is the name
225 *  of a preference that should be omitted from the file (if that preference
226 *  is to be overwritten or deleted. If nlines is provided, it will be set to
227 *  the number of lines in the file.
228 */
229
230FILE *_ds_ff_pref_prepare_file (
231  const char *filename,
232  const char *omission,
233  int *nlines)
234{
235  char line[1024], out_filename[MAX_FILENAME_LENGTH];
236  int lineno = 0, omission_len;
237  FILE *in_file, *out_file;
238  char omission_pref[1024];
239
240  snprintf(omission_pref, sizeof(omission_pref), "%s=", omission);
241  omission_len = strlen(omission_pref);
242
243  snprintf(out_filename, MAX_FILENAME_LENGTH, "%s.bak", filename);
244  out_file = fopen(out_filename, "w");
245
246  if (out_file == NULL) {
247    LOG(LOG_ERR, ERR_IO_FILE_OPEN, out_filename, strerror(errno));
248    return NULL;
249  }
250
251  in_file = fopen(filename, "r");
252
253  if (in_file) {
254    while (fgets(line, sizeof(line), in_file)) {
255      if (!strncmp(line, omission_pref, omission_len))
256        continue;
257
258      lineno++;
259
260      if (fputs(line, out_file)<0) {
261        LOG(LOG_ERR, ERR_IO_FILE_WRITE, out_filename, strerror(errno));
262        fclose(in_file);
263        fclose(out_file);
264        unlink(out_filename);
265        return NULL;
266      }
267    }
268    fclose(in_file);
269  }
270
271  if (nlines != NULL)
272    *nlines = lineno;
273  return out_file;
274}
275
276/* _ds_pref_commit: close scratch copy and commit it as the new live copy */
277
278int _ds_ff_pref_commit (
279  const char *filename,
280  FILE *out_file)
281{
282  char backup[MAX_FILENAME_LENGTH];
283
284  snprintf(backup, sizeof(backup), "%s.bak", filename);
285  if (fclose(out_file)) {
286    LOG(LOG_ERR, ERR_IO_FILE_CLOSE, backup, strerror(errno));
287    return EFAILURE;
288  }
289
290  if (rename(backup, filename)) {
291    LOG(LOG_ERR, ERR_IO_FILE_RENAME, backup, strerror(errno));
292    unlink(backup);
293    return EFAILURE;
294  }
295
296  return 0;
297}
298
299int _ds_ff_pref_set (
300  config_t config,
301  const char *username,
302  const char *home,
303  const char *preference,
304  const char *value,
305  void *ignore)
306{
307  char filename[MAX_FILENAME_LENGTH];
308  FILE *out_file;
309  config = config; /* Keep compiler happy */
310  ignore = ignore; /* Keep compiler happy */
311
312  if (username == NULL) {
313    snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home);
314  } else {
315    _ds_userdir_path (filename, home, username, "prefs");
316  }
317
318  out_file = _ds_ff_pref_prepare_file(filename, preference, NULL);
319
320  if (out_file == NULL)
321    return EFAILURE;
322
323  fprintf(out_file, "%s=%s\n", preference, value);
324
325  return _ds_ff_pref_commit(filename, out_file);
326}
327
328int _ds_ff_pref_del (
329  config_t config,
330  const char *username,
331  const char *home,
332  const char *preference,
333  void *ignore)
334{
335  char filename[MAX_FILENAME_LENGTH];
336  FILE *out_file;
337  int nlines;
338  config = config; /* Keep compiler happy */
339  ignore = ignore; /* Keep compiler happy */
340
341  if (username == NULL) {
342    snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home);
343  } else {
344    _ds_userdir_path (filename, home, username, "prefs");
345  }
346
347  out_file = _ds_ff_pref_prepare_file(filename, preference, &nlines);
348
349  if (out_file == NULL)
350    return EFAILURE;
351
352  if (!nlines) {
353    char backup[MAX_FILENAME_LENGTH];
354    fclose(out_file);
355    snprintf(backup, sizeof(backup), "%s.bak", filename);
356    unlink(backup);
357    return unlink(filename);
358  }
359
360  return _ds_ff_pref_commit(filename, out_file);
361}
Note: See TracBrowser for help on using the repository browser.