/src/postfix/postfix/src/util/dict_random.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*++ |
2 | | /* NAME |
3 | | /* dict_random 3 |
4 | | /* SUMMARY |
5 | | /* dictionary manager interface for randomized tables |
6 | | /* SYNOPSIS |
7 | | /* #include <dict_random.h> |
8 | | /* |
9 | | /* DICT *dict_random_open(name, open_flags, dict_flags) |
10 | | /* const char *name; |
11 | | /* int open_flags; |
12 | | /* int dict_flags; |
13 | | /* DESCRIPTION |
14 | | /* dict_random_open() opens an in-memory, read-only, table. |
15 | | /* Example: "\fBrandmap:{\fIresult_1, ... ,result_n}\fR". |
16 | | /* |
17 | | /* Each table query returns a random choice from the specified |
18 | | /* results. Other table access methods are not supported. |
19 | | /* |
20 | | /* The first and last characters of the "randmap:" table name |
21 | | /* must be '{' and '}'. Within these, individual maps are |
22 | | /* separated with comma or whitespace. |
23 | | /* SEE ALSO |
24 | | /* dict(3) generic dictionary manager |
25 | | /* LICENSE |
26 | | /* .ad |
27 | | /* .fi |
28 | | /* The Secure Mailer license must be distributed with this software. |
29 | | /* AUTHOR(S) |
30 | | /* Wietse Venema |
31 | | /* IBM T.J. Watson Research |
32 | | /* P.O. Box 704 |
33 | | /* Yorktown Heights, NY 10598, USA |
34 | | /* |
35 | | /* Wietse Venema |
36 | | /* Google, Inc. |
37 | | /* 111 8th Avenue |
38 | | /* New York, NY 10011, USA |
39 | | /*--*/ |
40 | | |
41 | | /* System library. */ |
42 | | |
43 | | #include <sys_defs.h> |
44 | | #include <string.h> |
45 | | |
46 | | /* Utility library. */ |
47 | | |
48 | | #include <msg.h> |
49 | | #include <mymalloc.h> |
50 | | #include <myrand.h> |
51 | | #include <stringops.h> |
52 | | #include <dict_random.h> |
53 | | |
54 | | /* Application-specific. */ |
55 | | |
56 | | typedef struct { |
57 | | DICT dict; /* generic members */ |
58 | | ARGV *replies; /* reply values */ |
59 | | } DICT_RANDOM; |
60 | | |
61 | | #define STR(x) vstring_str(x) |
62 | | |
63 | | /* dict_random_lookup - find randomized-table entry */ |
64 | | |
65 | | static const char *dict_random_lookup(DICT *dict, const char *unused_query) |
66 | 0 | { |
67 | 0 | DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; |
68 | |
|
69 | 0 | DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, |
70 | 0 | dict_random->replies->argv[myrand() % dict_random->replies->argc]); |
71 | 0 | } |
72 | | |
73 | | /* dict_random_close - disassociate from randomized table */ |
74 | | |
75 | | static void dict_random_close(DICT *dict) |
76 | 0 | { |
77 | 0 | DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; |
78 | |
|
79 | 0 | if (dict_random->replies) |
80 | 0 | argv_free(dict_random->replies); |
81 | 0 | dict_free(dict); |
82 | 0 | } |
83 | | |
84 | | static char *dict_random_parse_name(DICT *dict, ARGV **argv, |
85 | | const char *string, |
86 | | const char *delim, |
87 | | const char *parens) |
88 | 0 | { |
89 | 0 | ARGV *argvp = argv_alloc(1); |
90 | 0 | char *saved_string = mystrdup(string); |
91 | 0 | char *bp = saved_string; |
92 | 0 | char *arg; |
93 | 0 | VSTRING *b64 = 0; |
94 | 0 | char *err = 0; |
95 | |
|
96 | 0 | while ((arg = mystrtokq(&bp, delim, parens)) != 0) { |
97 | 0 | if (dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) { |
98 | 0 | if ((b64 = dict_file_to_b64(dict, arg)) != 0) { |
99 | 0 | argv_add(argvp, vstring_str(b64), (char *) 0); |
100 | 0 | } else { |
101 | 0 | err = dict_file_get_error(dict); |
102 | 0 | break; |
103 | 0 | } |
104 | 0 | } else { |
105 | 0 | argv_add(argvp, arg, (char *) 0); |
106 | 0 | } |
107 | 0 | } |
108 | 0 | argv_terminate(argvp); |
109 | 0 | myfree(saved_string); |
110 | 0 | *argv = argvp; |
111 | 0 | return (err); |
112 | 0 | } |
113 | | |
114 | | /* dict_random_open - open a randomized table */ |
115 | | |
116 | | DICT *dict_random_open(const char *name, int open_flags, int dict_flags) |
117 | 0 | { |
118 | 0 | DICT_RANDOM *dict_random; |
119 | 0 | char *saved_name = 0; |
120 | 0 | size_t len; |
121 | 0 | char *err = 0; |
122 | | |
123 | | /* |
124 | | * Clarity first. Let the optimizer worry about redundant code. |
125 | | */ |
126 | 0 | #define DICT_RANDOM_RETURN(x) do { \ |
127 | 0 | DICT *__d = (x); \ |
128 | 0 | if (saved_name != 0) \ |
129 | 0 | myfree(saved_name); \ |
130 | 0 | if (err != 0) \ |
131 | 0 | myfree(err); \ |
132 | 0 | return (__d); \ |
133 | 0 | } while (0) |
134 | | |
135 | | /* |
136 | | * Sanity checks. |
137 | | */ |
138 | 0 | if (open_flags != O_RDONLY) |
139 | 0 | DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, |
140 | 0 | open_flags, dict_flags, |
141 | 0 | "%s:%s map requires O_RDONLY access mode", |
142 | 0 | DICT_TYPE_RANDOM, name)); |
143 | | |
144 | | /* |
145 | | * Bundle up preliminary results. |
146 | | */ |
147 | 0 | dict_random = |
148 | 0 | (DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random)); |
149 | 0 | dict_random->dict.lookup = dict_random_lookup; |
150 | 0 | dict_random->dict.close = dict_random_close; |
151 | 0 | dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN; |
152 | 0 | dict_random->replies = 0; |
153 | 0 | dict_random->dict.owner.status = DICT_OWNER_TRUSTED; |
154 | 0 | dict_random->dict.owner.uid = 0; |
155 | | |
156 | | /* |
157 | | * Split the table name into its constituent parts. |
158 | | */ |
159 | 0 | if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0 |
160 | 0 | || *(saved_name = mystrndup(name + 1, len - 2)) == 0 |
161 | 0 | || (err = dict_random_parse_name(&dict_random->dict, |
162 | 0 | &dict_random->replies, saved_name, |
163 | 0 | CHARS_COMMA_SP, CHARS_BRACE)) != 0 |
164 | 0 | || dict_random->replies->argc == 0) { |
165 | 0 | dict_random_close(&dict_random->dict); |
166 | 0 | DICT_RANDOM_RETURN(err == 0 ? |
167 | 0 | dict_surrogate(DICT_TYPE_RANDOM, name, |
168 | 0 | open_flags, dict_flags, |
169 | 0 | "bad syntax: \"%s:%s\"; " |
170 | 0 | "need \"%s:{value...}\"", |
171 | 0 | DICT_TYPE_RANDOM, name, |
172 | 0 | DICT_TYPE_RANDOM) : |
173 | 0 | dict_surrogate(DICT_TYPE_RANDOM, name, |
174 | 0 | open_flags, dict_flags, |
175 | 0 | "%s", err)); |
176 | 0 | } |
177 | 0 | dict_file_purge_buffers(&dict_random->dict); |
178 | 0 | DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict)); |
179 | 0 | } |