Postfix3.3.1
dict_proxy.c
[詳解]
1 /*++
2 /* NAME
3 /* dict_proxy 3
4 /* SUMMARY
5 /* generic dictionary proxy client
6 /* SYNOPSIS
7 /* #include <dict_proxy.h>
8 /*
9 /* DICT *dict_proxy_open(map, open_flags, dict_flags)
10 /* const char *map;
11 /* int open_flags;
12 /* int dict_flags;
13 /* DESCRIPTION
14 /* dict_proxy_open() relays read-only or read-write operations
15 /* through the Postfix proxymap server.
16 /*
17 /* The \fIopen_flags\fR argument must specify O_RDONLY
18 /* or O_RDWR. Depending on this, the client
19 /* connects to the proxymap multiserver or to the
20 /* proxywrite single updater.
21 /*
22 /* The connection to the Postfix proxymap server is automatically
23 /* closed after $ipc_idle seconds of idle time, or after $ipc_ttl
24 /* seconds of activity.
25 /* SECURITY
26 /* The proxy map server is not meant to be a trusted process. Proxy
27 /* maps must not be used to look up security sensitive information
28 /* such as user/group IDs, output files, or external commands.
29 /* SEE ALSO
30 /* dict(3) generic dictionary manager
31 /* clnt_stream(3) client endpoint connection management
32 /* DIAGNOSTICS
33 /* Fatal errors: out of memory, unimplemented operation,
34 /* bad request parameter, map not approved for proxy access.
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /* The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*--*/
45 
46 /* System library. */
47 
48 #include <sys_defs.h>
49 #include <errno.h>
50 #include <unistd.h>
51 
52 /* Utility library. */
53 
54 #include <msg.h>
55 #include <mymalloc.h>
56 #include <stringops.h>
57 #include <vstring.h>
58 #include <vstream.h>
59 #include <attr.h>
60 #include <dict.h>
61 
62 /* Global library. */
63 
64 #include <mail_proto.h>
65 #include <mail_params.h>
66 #include <clnt_stream.h>
67 #include <dict_proxy.h>
68 
69 /* Application-specific. */
70 
71 typedef struct {
72  DICT dict; /* generic members */
73  CLNT_STREAM *clnt; /* client handle (shared) */
74  const char *service; /* service name */
75  int inst_flags; /* saved dict flags */
76  VSTRING *reskey; /* result key storage */
77  VSTRING *result; /* storage */
78 } DICT_PROXY;
79 
80  /*
81  * SLMs.
82  */
83 #define STR(x) vstring_str(x)
84 #define VSTREQ(v,s) (strcmp(STR(v),s) == 0)
85 
86  /*
87  * All proxied maps of the same type share the same query/reply socket.
88  */
89 static CLNT_STREAM *proxymap_stream; /* read-only maps */
90 static CLNT_STREAM *proxywrite_stream; /* read-write maps */
91 
92 /* dict_proxy_sequence - find first/next entry */
93 
94 static int dict_proxy_sequence(DICT *dict, int function,
95  const char **key, const char **value)
96 {
97  const char *myname = "dict_proxy_sequence";
98  DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
99  VSTREAM *stream;
100  int status;
101  int count = 0;
102  int request_flags;
103 
104  /*
105  * The client and server live in separate processes that may start and
106  * terminate independently. We cannot rely on a persistent connection,
107  * let alone on persistent state (such as a specific open table) that is
108  * associated with a specific connection. Each lookup needs to specify
109  * the table and the flags that were specified to dict_proxy_open().
110  */
111  VSTRING_RESET(dict_proxy->reskey);
112  VSTRING_TERMINATE(dict_proxy->reskey);
113  VSTRING_RESET(dict_proxy->result);
114  VSTRING_TERMINATE(dict_proxy->result);
115  request_flags = dict_proxy->inst_flags
116  | (dict->flags & DICT_FLAG_RQST_MASK);
117  for (;;) {
118  stream = clnt_stream_access(dict_proxy->clnt);
119  errno = 0;
120  count += 1;
121  if (attr_print(stream, ATTR_FLAG_NONE,
124  SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
125  SEND_ATTR_INT(MAIL_ATTR_FUNC, function),
126  ATTR_TYPE_END) != 0
127  || vstream_fflush(stream)
128  || attr_scan(stream, ATTR_FLAG_STRICT,
130  RECV_ATTR_STR(MAIL_ATTR_KEY, dict_proxy->reskey),
131  RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
132  ATTR_TYPE_END) != 3) {
133  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
134  msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
135  } else {
136  if (msg_verbose)
137  msg_info("%s: table=%s flags=%s func=%d -> status=%d key=%s val=%s",
138  myname, dict->name, dict_flags_str(request_flags),
139  function, status, STR(dict_proxy->reskey),
140  STR(dict_proxy->result));
141  switch (status) {
142  case PROXY_STAT_BAD:
143  msg_fatal("%s sequence failed for table \"%s\" function %d: "
144  "invalid request",
145  dict_proxy->service, dict->name, function);
146  case PROXY_STAT_DENY:
147  msg_fatal("%s service is not configured for table \"%s\"",
148  dict_proxy->service, dict->name);
149  case PROXY_STAT_OK:
150  *key = STR(dict_proxy->reskey);
151  *value = STR(dict_proxy->result);
153  case PROXY_STAT_NOKEY:
154  *key = *value = 0;
156  case PROXY_STAT_RETRY:
157  *key = *value = 0;
159  case PROXY_STAT_CONFIG:
160  *key = *value = 0;
162  default:
163  msg_warn("%s sequence failed for table \"%s\" function %d: "
164  "unexpected reply status %d",
165  dict_proxy->service, dict->name, function, status);
166  }
167  }
168  clnt_stream_recover(dict_proxy->clnt);
169  sleep(1); /* XXX make configurable */
170  }
171 }
172 
173 /* dict_proxy_lookup - find table entry */
174 
175 static const char *dict_proxy_lookup(DICT *dict, const char *key)
176 {
177  const char *myname = "dict_proxy_lookup";
178  DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
179  VSTREAM *stream;
180  int status;
181  int count = 0;
182  int request_flags;
183 
184  /*
185  * The client and server live in separate processes that may start and
186  * terminate independently. We cannot rely on a persistent connection,
187  * let alone on persistent state (such as a specific open table) that is
188  * associated with a specific connection. Each lookup needs to specify
189  * the table and the flags that were specified to dict_proxy_open().
190  */
191  VSTRING_RESET(dict_proxy->result);
192  VSTRING_TERMINATE(dict_proxy->result);
193  request_flags = dict_proxy->inst_flags
194  | (dict->flags & DICT_FLAG_RQST_MASK);
195  for (;;) {
196  stream = clnt_stream_access(dict_proxy->clnt);
197  errno = 0;
198  count += 1;
199  if (attr_print(stream, ATTR_FLAG_NONE,
202  SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
204  ATTR_TYPE_END) != 0
205  || vstream_fflush(stream)
206  || attr_scan(stream, ATTR_FLAG_STRICT,
208  RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
209  ATTR_TYPE_END) != 2) {
210  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
211  msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
212  } else {
213  if (msg_verbose)
214  msg_info("%s: table=%s flags=%s key=%s -> status=%d result=%s",
215  myname, dict->name,
216  dict_flags_str(request_flags), key,
217  status, STR(dict_proxy->result));
218  switch (status) {
219  case PROXY_STAT_BAD:
220  msg_fatal("%s lookup failed for table \"%s\" key \"%s\": "
221  "invalid request",
222  dict_proxy->service, dict->name, key);
223  case PROXY_STAT_DENY:
224  msg_fatal("%s service is not configured for table \"%s\"",
225  dict_proxy->service, dict->name);
226  case PROXY_STAT_OK:
227  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, STR(dict_proxy->result));
228  case PROXY_STAT_NOKEY:
229  DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, (char *) 0);
230  case PROXY_STAT_RETRY:
231  DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
232  case PROXY_STAT_CONFIG:
233  DICT_ERR_VAL_RETURN(dict, DICT_ERR_CONFIG, (char *) 0);
234  default:
235  msg_warn("%s lookup failed for table \"%s\" key \"%s\": "
236  "unexpected reply status %d",
237  dict_proxy->service, dict->name, key, status);
238  }
239  }
240  clnt_stream_recover(dict_proxy->clnt);
241  sleep(1); /* XXX make configurable */
242  }
243 }
244 
245 /* dict_proxy_update - update table entry */
246 
247 static int dict_proxy_update(DICT *dict, const char *key, const char *value)
248 {
249  const char *myname = "dict_proxy_update";
250  DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
251  VSTREAM *stream;
252  int status;
253  int count = 0;
254  int request_flags;
255 
256  /*
257  * The client and server live in separate processes that may start and
258  * terminate independently. We cannot rely on a persistent connection,
259  * let alone on persistent state (such as a specific open table) that is
260  * associated with a specific connection. Each lookup needs to specify
261  * the table and the flags that were specified to dict_proxy_open().
262  */
263  request_flags = dict_proxy->inst_flags
264  | (dict->flags & DICT_FLAG_RQST_MASK);
265  for (;;) {
266  stream = clnt_stream_access(dict_proxy->clnt);
267  errno = 0;
268  count += 1;
269  if (attr_print(stream, ATTR_FLAG_NONE,
272  SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
275  ATTR_TYPE_END) != 0
276  || vstream_fflush(stream)
277  || attr_scan(stream, ATTR_FLAG_STRICT,
279  ATTR_TYPE_END) != 1) {
280  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
281  msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
282  } else {
283  if (msg_verbose)
284  msg_info("%s: table=%s flags=%s key=%s value=%s -> status=%d",
285  myname, dict->name, dict_flags_str(request_flags),
286  key, value, status);
287  switch (status) {
288  case PROXY_STAT_BAD:
289  msg_fatal("%s update failed for table \"%s\" key \"%s\": "
290  "invalid request",
291  dict_proxy->service, dict->name, key);
292  case PROXY_STAT_DENY:
293  msg_fatal("%s update access is not configured for table \"%s\"",
294  dict_proxy->service, dict->name);
295  case PROXY_STAT_OK:
297  case PROXY_STAT_NOKEY:
299  case PROXY_STAT_RETRY:
301  case PROXY_STAT_CONFIG:
303  default:
304  msg_warn("%s update failed for table \"%s\" key \"%s\": "
305  "unexpected reply status %d",
306  dict_proxy->service, dict->name, key, status);
307  }
308  }
309  clnt_stream_recover(dict_proxy->clnt);
310  sleep(1); /* XXX make configurable */
311  }
312 }
313 
314 /* dict_proxy_delete - delete table entry */
315 
316 static int dict_proxy_delete(DICT *dict, const char *key)
317 {
318  const char *myname = "dict_proxy_delete";
319  DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
320  VSTREAM *stream;
321  int status;
322  int count = 0;
323  int request_flags;
324 
325  /*
326  * The client and server live in separate processes that may start and
327  * terminate independently. We cannot rely on a persistent connection,
328  * let alone on persistent state (such as a specific open table) that is
329  * associated with a specific connection. Each lookup needs to specify
330  * the table and the flags that were specified to dict_proxy_open().
331  */
332  request_flags = dict_proxy->inst_flags
333  | (dict->flags & DICT_FLAG_RQST_MASK);
334  for (;;) {
335  stream = clnt_stream_access(dict_proxy->clnt);
336  errno = 0;
337  count += 1;
338  if (attr_print(stream, ATTR_FLAG_NONE,
341  SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
343  ATTR_TYPE_END) != 0
344  || vstream_fflush(stream)
345  || attr_scan(stream, ATTR_FLAG_STRICT,
347  ATTR_TYPE_END) != 1) {
348  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno !=
349  ENOENT))
350  msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
351  } else {
352  if (msg_verbose)
353  msg_info("%s: table=%s flags=%s key=%s -> status=%d",
354  myname, dict->name, dict_flags_str(request_flags),
355  key, status);
356  switch (status) {
357  case PROXY_STAT_BAD:
358  msg_fatal("%s delete failed for table \"%s\" key \"%s\": "
359  "invalid request",
360  dict_proxy->service, dict->name, key);
361  case PROXY_STAT_DENY:
362  msg_fatal("%s update access is not configured for table \"%s\"",
363  dict_proxy->service, dict->name);
364  case PROXY_STAT_OK:
366  case PROXY_STAT_NOKEY:
368  case PROXY_STAT_RETRY:
370  case PROXY_STAT_CONFIG:
372  default:
373  msg_warn("%s delete failed for table \"%s\" key \"%s\": "
374  "unexpected reply status %d",
375  dict_proxy->service, dict->name, key, status);
376  }
377  }
378  clnt_stream_recover(dict_proxy->clnt);
379  sleep(1); /* XXX make configurable */
380  }
381 }
382 
383 /* dict_proxy_close - disconnect */
384 
385 static void dict_proxy_close(DICT *dict)
386 {
387  DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
388 
389  vstring_free(dict_proxy->reskey);
390  vstring_free(dict_proxy->result);
391  dict_free(dict);
392 }
393 
394 /* dict_proxy_open - open remote map */
395 
396 DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
397 {
398  const char *myname = "dict_proxy_open";
399  DICT_PROXY *dict_proxy;
400  VSTREAM *stream;
401  int server_flags;
402  int status;
403  const char *service;
404  char *relative_path;
405  char *kludge = 0;
406  char *prefix;
407  CLNT_STREAM **pstream;
408 
409  /*
410  * If this map can't be proxied then we silently do a direct open. This
411  * allows sites to benefit from proxying the virtual mailbox maps without
412  * unnecessary pain.
413  */
414  if (dict_flags & DICT_FLAG_NO_PROXY)
415  return (dict_open(map, open_flags, dict_flags));
416 
417  /*
418  * Use a shared stream for proxied table lookups of the same type.
419  *
420  * XXX A complete implementation would also allow O_RDWR without O_CREAT.
421  * But we must not pass on every possible set of flags to the proxy
422  * server; only sets that make sense. For now, the flags are passed
423  * implicitly by choosing between the proxymap or proxywrite service.
424  *
425  * XXX Use absolute pathname to make this work from non-daemon processes.
426  */
427  if (open_flags == O_RDONLY) {
428  pstream = &proxymap_stream;
429  service = var_proxymap_service;
430  } else if ((open_flags & O_RDWR) == O_RDWR) {
431  pstream = &proxywrite_stream;
432  service = var_proxywrite_service;
433  } else
434  msg_fatal("%s: %s map open requires O_RDONLY or O_RDWR mode",
435  map, DICT_TYPE_PROXY);
436 
437  if (*pstream == 0) {
438  relative_path = concatenate(MAIL_CLASS_PRIVATE "/",
439  service, (char *) 0);
440  if (access(relative_path, F_OK) == 0)
441  prefix = MAIL_CLASS_PRIVATE;
442  else
443  prefix = kludge = concatenate(var_queue_dir, "/",
444  MAIL_CLASS_PRIVATE, (char *) 0);
445  *pstream = clnt_stream_create(prefix, service, var_ipc_idle_limit,
447  if (kludge)
448  myfree(kludge);
449  myfree(relative_path);
450  }
451 
452  /*
453  * Local initialization.
454  */
455  dict_proxy = (DICT_PROXY *)
456  dict_alloc(DICT_TYPE_PROXY, map, sizeof(*dict_proxy));
457  dict_proxy->dict.lookup = dict_proxy_lookup;
458  dict_proxy->dict.update = dict_proxy_update;
459  dict_proxy->dict.delete = dict_proxy_delete;
460  dict_proxy->dict.sequence = dict_proxy_sequence;
461  dict_proxy->dict.close = dict_proxy_close;
462  dict_proxy->inst_flags = (dict_flags & DICT_FLAG_INST_MASK);
463  dict_proxy->reskey = vstring_alloc(10);
464  dict_proxy->result = vstring_alloc(10);
465  dict_proxy->clnt = *pstream;
466  dict_proxy->service = service;
467 
468  /*
469  * Establish initial contact and get the map type specific flags.
470  *
471  * XXX Should retrieve flags from local instance.
472  */
473  for (;;) {
474  stream = clnt_stream_access(dict_proxy->clnt);
475  errno = 0;
476  if (attr_print(stream, ATTR_FLAG_NONE,
478  SEND_ATTR_STR(MAIL_ATTR_TABLE, dict_proxy->dict.name),
480  ATTR_TYPE_END) != 0
481  || vstream_fflush(stream)
482  || attr_scan(stream, ATTR_FLAG_STRICT,
484  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &server_flags),
485  ATTR_TYPE_END) != 2) {
486  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
487  msg_warn("%s: service %s: %m", VSTREAM_PATH(stream), myname);
488  } else {
489  if (msg_verbose)
490  msg_info("%s: connect to map=%s status=%d server_flags=%s",
491  myname, dict_proxy->dict.name, status,
492  dict_flags_str(server_flags));
493  switch (status) {
494  case PROXY_STAT_BAD:
495  msg_fatal("%s open failed for table \"%s\": invalid request",
496  dict_proxy->service, dict_proxy->dict.name);
497  case PROXY_STAT_DENY:
498  msg_fatal("%s service is not configured for table \"%s\"",
499  dict_proxy->service, dict_proxy->dict.name);
500  case PROXY_STAT_OK:
501  dict_proxy->dict.flags = (dict_flags & ~DICT_FLAG_IMPL_MASK)
502  | (server_flags & DICT_FLAG_IMPL_MASK);
503  return (DICT_DEBUG (&dict_proxy->dict));
504  default:
505  msg_warn("%s open failed for table \"%s\": unexpected status %d",
506  dict_proxy->service, dict_proxy->dict.name, status);
507  }
508  }
509  clnt_stream_recover(dict_proxy->clnt);
510  sleep(1); /* XXX make configurable */
511  }
512 }
int msg_verbose
Definition: msg.c:177
#define DICT_ERR_CONFIG
Definition: dict.h:179
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
#define DICT_TYPE_PROXY
Definition: dict_proxy.h:22
char * var_proxymap_service
Definition: mail_params.c:312
VSTREAM * clnt_stream_access(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:206
#define MAIL_ATTR_FUNC
Definition: mail_proto.h:172
#define DICT_FLAG_RQST_MASK
Definition: dict.h:162
void(* close)(struct DICT *)
Definition: dict.h:87
int var_ipc_idle_limit
Definition: mail_params.c:268
int(* delete)(struct DICT *, const char *)
Definition: dict.h:84
char * name
Definition: dict.h:80
#define MAIL_ATTR_REQ
Definition: mail_proto.h:124
int flags
Definition: dict.h:81
#define DICT_ERR_RETRY
Definition: dict.h:178
#define MAIL_ATTR_TABLE
Definition: mail_proto.h:152
#define DICT_STAT_FAIL
Definition: dict.h:185
#define PROXY_REQ_SEQUENCE
Definition: dict_proxy.h:33
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
char * var_proxywrite_service
Definition: mail_params.c:313
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
#define PROXY_STAT_DENY
Definition: dict_proxy.h:39
DICT * dict_open(const char *, int, int)
Definition: dict_open.c:421
#define DICT_ERR_NONE
Definition: dict.h:177
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
DICT * dict_proxy_open(const char *map, int open_flags, int dict_flags)
Definition: dict_proxy.c:396
Definition: dict.h:78
int(* update)(struct DICT *, const char *, const char *)
Definition: dict.h:83
#define DICT_STAT_SUCCESS
Definition: dict.h:186
#define attr_print
Definition: attr.h:109
#define PROXY_STAT_CONFIG
Definition: dict_proxy.h:40
#define PROXY_REQ_DELETE
Definition: dict_proxy.h:32
#define PROXY_STAT_RETRY
Definition: dict_proxy.h:37
CLNT_STREAM * clnt_stream_create(const char *class, const char *service, int timeout, int ttl)
Definition: clnt_stream.c:228
int var_ipc_ttl_limit
Definition: mail_params.c:269
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define PROXY_REQ_UPDATE
Definition: dict_proxy.h:31
#define PROXY_STAT_NOKEY
Definition: dict_proxy.h:36
VSTRING * reskey
Definition: dict_proxy.c:76
#define PROXY_REQ_OPEN
Definition: dict_proxy.h:29
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
const char * dict_flags_str(int dict_flags)
Definition: dict.c:647
#define DICT_FLAG_INST_MASK
Definition: dict.h:166
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
const char *(* lookup)(struct DICT *, const char *)
Definition: dict.h:82
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define DICT_ERR_VAL_RETURN(dict, err, val)
Definition: dict.h:192
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void dict_free(DICT *)
Definition: dict_alloc.c:163
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
DICT dict
Definition: dict_proxy.c:72
#define PROXY_STAT_BAD
Definition: dict_proxy.h:38
#define DICT_FLAG_IMPL_MASK
Definition: dict.h:160
#define PROXY_REQ_LOOKUP
Definition: dict_proxy.h:30
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define DICT_STAT_ERROR
Definition: dict.h:187
char * var_queue_dir
Definition: mail_params.c:246
#define MAIL_ATTR_VALUE
Definition: mail_proto.h:154
VSTRING * result
Definition: dict_proxy.c:77
void clnt_stream_recover(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:194
int(* sequence)(struct DICT *, int, const char **, const char **)
Definition: dict.h:85
DICT * dict_alloc(const char *, const char *, ssize_t)
Definition: dict_alloc.c:135
int server_flags
#define MAIL_ATTR_KEY
Definition: mail_proto.h:153
#define attr_scan
Definition: attr.h:111
#define PROXY_STAT_OK
Definition: dict_proxy.h:35
CLNT_STREAM * clnt
Definition: dict_proxy.c:73
const char * service
Definition: dict_proxy.c:74
int inst_flags
Definition: dict_proxy.c:75
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define DICT_FLAG_NO_PROXY
Definition: dict.h:122
#define STR(x)
Definition: dict_proxy.c:83
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199