Postfix3.3.1
attr_scan_plain.c
[詳解]
1 /*++
2 /* NAME
3 /* attr_scan_plain 3
4 /* SUMMARY
5 /* recover attributes from byte stream
6 /* SYNOPSIS
7 /* #include <attr.h>
8 /*
9 /* int attr_scan_plain(fp, flags, type, name, ..., ATTR_TYPE_END)
10 /* VSTREAM *fp;
11 /* int flags;
12 /* int type;
13 /* char *name;
14 /*
15 /* int attr_vscan_plain(fp, flags, ap)
16 /* VSTREAM *fp;
17 /* int flags;
18 /* va_list ap;
19 /*
20 /* int attr_scan_more_plain(fp)
21 /* VSTREAM *fp;
22 /* DESCRIPTION
23 /* attr_scan_plain() takes zero or more (name, value) request attributes
24 /* and recovers the attribute values from the byte stream that was
25 /* possibly generated by attr_print_plain().
26 /*
27 /* attr_vscan_plain() provides an alternative interface that is convenient
28 /* for calling from within a variadic function.
29 /*
30 /* attr_scan_more_plain() returns 0 when a terminator is found
31 /* (and consumes that terminator), returns 1 when more input
32 /* is expected (without consuming input), and returns -1
33 /* otherwise (error).
34 /*
35 /* The input stream is formatted as follows, where (item)* stands
36 /* for zero or more instances of the specified item, and where
37 /* (item1 | item2) stands for choice:
38 /*
39 /* .in +5
40 /* attr-list :== (simple-attr | multi-attr)* newline
41 /* .br
42 /* multi-attr :== "{" newline simple-attr* "}" newline
43 /* .br
44 /* simple-attr :== attr-name "=" attr-value newline
45 /* .br
46 /* attr-name :== any string without null or "=" or newline.
47 /* .br
48 /* attr-value :== any string without null or newline.
49 /* .br
50 /* newline :== the ASCII newline character
51 /* .in
52 /*
53 /* All attribute names and attribute values are sent as plain
54 /* strings. Each string must be no longer than 4*var_line_limit
55 /* characters. The formatting rules aim to make implementations in PERL
56 /* and other languages easy.
57 /*
58 /* Normally, attributes must be received in the sequence as specified
59 /* with the attr_scan_plain() argument list. The input stream may
60 /* contain additional attributes at any point in the input stream,
61 /* including additional instances of requested attributes.
62 /*
63 /* Additional input attributes or input attribute instances are silently
64 /* skipped over, unless the ATTR_FLAG_EXTRA processing flag is specified
65 /* (see below). This allows for some flexibility in the evolution of
66 /* protocols while still providing the option of being strict where
67 /* this is desirable.
68 /*
69 /* Arguments:
70 /* .IP fp
71 /* Stream to recover the input attributes from.
72 /* .IP flags
73 /* The bit-wise OR of zero or more of the following.
74 /* .RS
75 /* .IP ATTR_FLAG_MISSING
76 /* Log a warning when the input attribute list terminates before all
77 /* requested attributes are recovered. It is always an error when the
78 /* input stream ends without the newline attribute list terminator.
79 /* .IP ATTR_FLAG_EXTRA
80 /* Log a warning and stop attribute recovery when the input stream
81 /* contains an attribute that was not requested. This includes the
82 /* case of additional instances of a requested attribute.
83 /* .IP ATTR_FLAG_MORE
84 /* After recovering the requested attributes, leave the input stream
85 /* in a state that is usable for more attr_scan_plain() operations
86 /* from the same input attribute list.
87 /* By default, attr_scan_plain() skips forward past the input attribute
88 /* list terminator.
89 /* .IP ATTR_FLAG_STRICT
90 /* For convenience, this value combines both ATTR_FLAG_MISSING and
91 /* ATTR_FLAG_EXTRA.
92 /* .IP ATTR_FLAG_NONE
93 /* For convenience, this value requests none of the above.
94 /* .RE
95 /* .IP List of attributes followed by terminator:
96 /* .RS
97 /* .IP "RECV_ATTR_INT(const char *name, int *ptr)"
98 /* This argument is followed by an attribute name and an integer pointer.
99 /* .IP "RECV_ATTR_LONG(const char *name, long *ptr)"
100 /* This argument is followed by an attribute name and a long pointer.
101 /* .IP "RECV_ATTR_STR(const char *name, VSTRING *vp)"
102 /* This argument is followed by an attribute name and a VSTRING pointer.
103 /* .IP "RECV_ATTR_DATA(const char *name, VSTRING *vp)"
104 /* This argument is followed by an attribute name and a VSTRING pointer.
105 /* .IP "RECV_ATTR_FUNC(ATTR_SCAN_SLAVE_FN, void *data)"
106 /* This argument is followed by a function pointer and a generic data
107 /* pointer. The caller-specified function returns < 0 in case of
108 /* error.
109 /* .IP "RECV_ATTR_HASH(HTABLE *table)"
110 /* .IP "RECV_ATTR_NAMEVAL(NVTABLE *table)"
111 /* Receive a sequence of attribute names and string values.
112 /* There can be no more than 1024 attributes in a hash table.
113 /* .sp
114 /* The attribute string values are stored in the hash table under
115 /* keys equal to the attribute name (obtained from the input stream).
116 /* Values from the input stream are added to the hash table. Existing
117 /* hash table entries are not replaced.
118 /* .sp
119 /* Note: the SEND_ATTR_HASH or SEND_ATTR_NAMEVAL requests
120 /* format their payload as a multi-attr sequence (see syntax
121 /* above). When the receiver's input does not start with a
122 /* multi-attr delimiter (i.e. the sender did not request
123 /* SEND_ATTR_HASH or SEND_ATTR_NAMEVAL), the receiver will
124 /* store all attribute names and values up to the attribute
125 /* list terminator. In terms of code, this means that the
126 /* RECV_ATTR_HASH or RECV_ATTR_NAMEVAL request must be followed
127 /* by ATTR_TYPE_END.
128 /* .IP ATTR_TYPE_END
129 /* This argument terminates the requested attribute list.
130 /* .RE
131 /* BUGS
132 /* RECV_ATTR_HASH (RECV_ATTR_NAMEVAL) accepts attributes with arbitrary
133 /* names from possibly untrusted sources.
134 /* This is unsafe, unless the resulting table is queried only with
135 /* known to be good attribute names.
136 /* DIAGNOSTICS
137 /* attr_scan_plain() and attr_vscan_plain() return -1 when malformed input
138 /* is detected (string too long, incomplete line, missing end marker).
139 /* Otherwise, the result value is the number of attributes that were
140 /* successfully recovered from the input stream (a hash table counts
141 /* as the number of entries stored into the table).
142 /*
143 /* Panic: interface violation. All system call errors are fatal.
144 /* SEE ALSO
145 /* attr_print_plain(3) send attributes over byte stream.
146 /* LICENSE
147 /* .ad
148 /* .fi
149 /* The Secure Mailer license must be distributed with this software.
150 /* AUTHOR(S)
151 /* Wietse Venema
152 /* IBM T.J. Watson Research
153 /* P.O. Box 704
154 /* Yorktown Heights, NY 10598, USA
155 /*
156 /* Wietse Venema
157 /* Google, Inc.
158 /* 111 8th Avenue
159 /* New York, NY 10011, USA
160 /*--*/
161 
162 /* System library. */
163 
164 #include <sys_defs.h>
165 #include <stdarg.h>
166 #include <string.h>
167 #include <stdio.h>
168 
169 /* Utility library. */
170 
171 #include <msg.h>
172 #include <mymalloc.h>
173 #include <vstream.h>
174 #include <vstring.h>
175 #include <htable.h>
176 #include <base64_code.h>
177 #include <attr.h>
178 
179 /* Application specific. */
180 
181 #define STR(x) vstring_str(x)
182 #define LEN(x) VSTRING_LEN(x)
183 
184 /* attr_scan_plain_string - pull a string from the input stream */
185 
186 static int attr_scan_plain_string(VSTREAM *fp, VSTRING *plain_buf,
187  int terminator, const char *context)
188 {
189 #if 0
190  extern int var_line_limit; /* XXX */
191  int limit = var_line_limit * 4;
192 
193 #endif
194  int ch;
195 
196  VSTRING_RESET(plain_buf);
197  while ((ch = VSTREAM_GETC(fp)) != '\n'
198  && (terminator == 0 || ch != terminator)) {
199  if (ch == VSTREAM_EOF) {
200  msg_warn("%s on %s while reading %s",
201  vstream_ftimeout(fp) ? "timeout" : "premature end-of-input",
202  VSTREAM_PATH(fp), context);
203  return (-1);
204  }
205  VSTRING_ADDCH(plain_buf, ch);
206 #if 0
207  if (LEN(plain_buf) > limit) {
208  msg_warn("string length > %d characters from %s while reading %s",
209  limit, VSTREAM_PATH(fp), context);
210  return (-1);
211  }
212 #endif
213  }
214  VSTRING_TERMINATE(plain_buf);
215 
216  if (msg_verbose)
217  msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)");
218  return (ch);
219 }
220 
221 /* attr_scan_plain_data - pull a data blob from the input stream */
222 
223 static int attr_scan_plain_data(VSTREAM *fp, VSTRING *str_buf,
224  int terminator,
225  const char *context)
226 {
227  static VSTRING *base64_buf = 0;
228  int ch;
229 
230  if (base64_buf == 0)
231  base64_buf = vstring_alloc(10);
232  if ((ch = attr_scan_plain_string(fp, base64_buf, terminator, context)) < 0)
233  return (-1);
234  if (base64_decode(str_buf, STR(base64_buf), LEN(base64_buf)) == 0) {
235  msg_warn("malformed base64 data from %s while reading %s: %.100s",
236  VSTREAM_PATH(fp), context, STR(base64_buf));
237  return (-1);
238  }
239  return (ch);
240 }
241 
242 /* attr_scan_plain_number - pull a number from the input stream */
243 
244 static int attr_scan_plain_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
245  int terminator, const char *context)
246 {
247  char junk = 0;
248  int ch;
249 
250  if ((ch = attr_scan_plain_string(fp, str_buf, terminator, context)) < 0)
251  return (-1);
252  if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) {
253  msg_warn("malformed numerical data from %s while reading %s: %.100s",
254  VSTREAM_PATH(fp), context, STR(str_buf));
255  return (-1);
256  }
257  return (ch);
258 }
259 
260 /* attr_scan_plain_long_number - pull a number from the input stream */
261 
262 static int attr_scan_plain_long_number(VSTREAM *fp, unsigned long *ptr,
263  VSTRING *str_buf,
264  int terminator,
265  const char *context)
266 {
267  char junk = 0;
268  int ch;
269 
270  if ((ch = attr_scan_plain_string(fp, str_buf, terminator, context)) < 0)
271  return (-1);
272  if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) {
273  msg_warn("malformed numerical data from %s while reading %s: %.100s",
274  VSTREAM_PATH(fp), context, STR(str_buf));
275  return (-1);
276  }
277  return (ch);
278 }
279 
280 /* attr_vscan_plain - receive attribute list from stream */
281 
282 int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
283 {
284  const char *myname = "attr_scan_plain";
285  static VSTRING *str_buf = 0;
286  static VSTRING *name_buf = 0;
287  int wanted_type = -1;
288  char *wanted_name;
289  unsigned int *number;
290  unsigned long *long_number;
291  VSTRING *string;
292  HTABLE *hash_table;
293  int ch;
294  int conversions;
295  ATTR_SCAN_SLAVE_FN scan_fn;
296  void *scan_arg;
297 
298  /*
299  * Sanity check.
300  */
301  if (flags & ~ATTR_FLAG_ALL)
302  msg_panic("%s: bad flags: 0x%x", myname, flags);
303 
304  /*
305  * EOF check.
306  */
307  if ((ch = VSTREAM_GETC(fp)) == VSTREAM_EOF)
308  return (0);
309  vstream_ungetc(fp, ch);
310 
311  /*
312  * Initialize.
313  */
314  if (str_buf == 0) {
315  str_buf = vstring_alloc(10);
316  name_buf = vstring_alloc(10);
317  }
318 
319  /*
320  * Iterate over all (type, name, value) triples.
321  */
322  for (conversions = 0; /* void */ ; conversions++) {
323 
324  /*
325  * Determine the next attribute type and attribute name on the
326  * caller's wish list.
327  *
328  * If we're reading into a hash table, we already know that the
329  * attribute value is string-valued, and we get the attribute name
330  * from the input stream instead. This is secure only when the
331  * resulting table is queried with known to be good attribute names.
332  */
333  if (wanted_type != ATTR_TYPE_HASH
334  && wanted_type != ATTR_TYPE_CLOSE) {
335  wanted_type = va_arg(ap, int);
336  if (wanted_type == ATTR_TYPE_END) {
337  if ((flags & ATTR_FLAG_MORE) != 0)
338  return (conversions);
339  wanted_name = "(list terminator)";
340  } else if (wanted_type == ATTR_TYPE_HASH) {
341  wanted_name = "(any attribute name or list terminator)";
342  hash_table = va_arg(ap, HTABLE *);
343  } else if (wanted_type != ATTR_TYPE_FUNC) {
344  wanted_name = va_arg(ap, char *);
345  }
346  }
347 
348  /*
349  * Locate the next attribute of interest in the input stream.
350  */
351  while (wanted_type != ATTR_TYPE_FUNC) {
352 
353  /*
354  * Get the name of the next attribute. Hitting EOF is always bad.
355  * Hitting the end-of-input early is OK if the caller is prepared
356  * to deal with missing inputs.
357  */
358  if (msg_verbose)
359  msg_info("%s: wanted attribute: %s",
360  VSTREAM_PATH(fp), wanted_name);
361  if ((ch = attr_scan_plain_string(fp, name_buf, '=',
362  "input attribute name")) == VSTREAM_EOF)
363  return (-1);
364  if (ch == '\n' && LEN(name_buf) == 0) {
365  if (wanted_type == ATTR_TYPE_END
366  || wanted_type == ATTR_TYPE_HASH)
367  return (conversions);
368  if ((flags & ATTR_FLAG_MISSING) != 0)
369  msg_warn("missing attribute %s in input from %s",
370  wanted_name, VSTREAM_PATH(fp));
371  return (conversions);
372  }
373 
374  /*
375  * See if the caller asks for this attribute.
376  */
377  if (wanted_type == ATTR_TYPE_HASH
378  && ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
379  wanted_type = ATTR_TYPE_CLOSE;
380  wanted_name = "(any attribute name or '}')";
381  /* Advance in the input stream. */
382  continue;
383  } else if (wanted_type == ATTR_TYPE_CLOSE
384  && ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
385  /* Advance in the argument list. */
386  wanted_type = -1;
387  break;
388  }
389  if (wanted_type == ATTR_TYPE_HASH
390  || wanted_type == ATTR_TYPE_CLOSE
391  || (wanted_type != ATTR_TYPE_END
392  && strcmp(wanted_name, STR(name_buf)) == 0))
393  break;
394  if ((flags & ATTR_FLAG_EXTRA) != 0) {
395  msg_warn("unexpected attribute %s from %s (expecting: %s)",
396  STR(name_buf), VSTREAM_PATH(fp), wanted_name);
397  return (conversions);
398  }
399 
400  /*
401  * Skip over this attribute. The caller does not ask for it.
402  */
403  while (ch != '\n' && (ch = VSTREAM_GETC(fp)) != VSTREAM_EOF)
404  /* void */ ;
405  }
406 
407  /*
408  * Do the requested conversion.
409  */
410  switch (wanted_type) {
411  case ATTR_TYPE_INT:
412  if (ch != '=') {
413  msg_warn("missing value for number attribute %s from %s",
414  STR(name_buf), VSTREAM_PATH(fp));
415  return (-1);
416  }
417  number = va_arg(ap, unsigned int *);
418  if ((ch = attr_scan_plain_number(fp, number, str_buf, 0,
419  "input attribute value")) < 0)
420  return (-1);
421  break;
422  case ATTR_TYPE_LONG:
423  if (ch != '=') {
424  msg_warn("missing value for number attribute %s from %s",
425  STR(name_buf), VSTREAM_PATH(fp));
426  return (-1);
427  }
428  long_number = va_arg(ap, unsigned long *);
429  if ((ch = attr_scan_plain_long_number(fp, long_number, str_buf,
430  0, "input attribute value")) < 0)
431  return (-1);
432  break;
433  case ATTR_TYPE_STR:
434  if (ch != '=') {
435  msg_warn("missing value for string attribute %s from %s",
436  STR(name_buf), VSTREAM_PATH(fp));
437  return (-1);
438  }
439  string = va_arg(ap, VSTRING *);
440  if ((ch = attr_scan_plain_string(fp, string, 0,
441  "input attribute value")) < 0)
442  return (-1);
443  break;
444  case ATTR_TYPE_DATA:
445  if (ch != '=') {
446  msg_warn("missing value for data attribute %s from %s",
447  STR(name_buf), VSTREAM_PATH(fp));
448  return (-1);
449  }
450  string = va_arg(ap, VSTRING *);
451  if ((ch = attr_scan_plain_data(fp, string, 0,
452  "input attribute value")) < 0)
453  return (-1);
454  break;
455  case ATTR_TYPE_FUNC:
456  scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN);
457  scan_arg = va_arg(ap, void *);
458  if (scan_fn(attr_scan_plain, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0)
459  return (-1);
460  break;
461  case ATTR_TYPE_HASH:
462  case ATTR_TYPE_CLOSE:
463  if (ch != '=') {
464  msg_warn("missing value for string attribute %s from %s",
465  STR(name_buf), VSTREAM_PATH(fp));
466  return (-1);
467  }
468  if ((ch = attr_scan_plain_string(fp, str_buf, 0,
469  "input attribute value")) < 0)
470  return (-1);
471  if (htable_locate(hash_table, STR(name_buf)) != 0) {
472  if ((flags & ATTR_FLAG_EXTRA) != 0) {
473  msg_warn("duplicate attribute %s in input from %s",
474  STR(name_buf), VSTREAM_PATH(fp));
475  return (conversions);
476  }
477  } else if (hash_table->used >= ATTR_HASH_LIMIT) {
478  msg_warn("attribute count exceeds limit %d in input from %s",
480  return (conversions);
481  } else {
482  htable_enter(hash_table, STR(name_buf),
483  mystrdup(STR(str_buf)));
484  }
485  break;
486  case -1:
487  conversions -= 1;
488  break;
489  default:
490  msg_panic("%s: unknown type code: %d", myname, wanted_type);
491  }
492  }
493 }
494 
495 /* attr_scan_plain - read attribute list from stream */
496 
497 int attr_scan_plain(VSTREAM *fp, int flags,...)
498 {
499  va_list ap;
500  int ret;
501 
502  va_start(ap, flags);
503  ret = attr_vscan_plain(fp, flags, ap);
504  va_end(ap);
505  return (ret);
506 }
507 
508 /* attr_scan_more_plain - look ahead for more */
509 
511 {
512  int ch;
513 
514  switch (ch = VSTREAM_GETC(fp)) {
515  case '\n':
516  if (msg_verbose)
517  msg_info("%s: terminator (consumed)", VSTREAM_PATH(fp));
518  return (0);
519  case VSTREAM_EOF:
520  if (msg_verbose)
521  msg_info("%s: EOF", VSTREAM_PATH(fp));
522  return (-1);
523  default:
524  if (msg_verbose)
525  msg_info("%s: non-terminator '%c' (lookahead)",
526  VSTREAM_PATH(fp), ch);
527  (void) vstream_ungetc(fp, ch);
528  return (1);
529  }
530 }
531 
532 #ifdef TEST
533 
534  /*
535  * Proof of concept test program. Mirror image of the attr_scan_plain test
536  * program.
537  */
538 #include <msg_vstream.h>
539 
540 int var_line_limit = 2048;
541 
542 int main(int unused_argc, char **used_argv)
543 {
544  VSTRING *data_val = vstring_alloc(1);
545  VSTRING *str_val = vstring_alloc(1);
546  HTABLE *table = htable_create(1);
547  HTABLE_INFO **ht_info_list;
548  HTABLE_INFO **ht;
549  int int_val;
550  long long_val;
551  long long_val2;
552  int ret;
553 
554  msg_verbose = 1;
555  msg_vstream_init(used_argv[0], VSTREAM_ERR);
556  if ((ret = attr_scan_plain(VSTREAM_IN,
558  RECV_ATTR_INT(ATTR_NAME_INT, &int_val),
559  RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val),
560  RECV_ATTR_STR(ATTR_NAME_STR, str_val),
561  RECV_ATTR_DATA(ATTR_NAME_DATA, data_val),
562  RECV_ATTR_HASH(table),
563  RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val2),
564  ATTR_TYPE_END)) > 4) {
565  vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
566  vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
567  vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
568  vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
569  ht_info_list = htable_list(table);
570  for (ht = ht_info_list; *ht; ht++)
571  vstream_printf("(hash) %s %s\n", ht[0]->key, (char *) ht[0]->value);
572  myfree((void *) ht_info_list);
573  vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val2);
574  } else {
575  vstream_printf("return: %d\n", ret);
576  }
577  if ((ret = attr_scan_plain(VSTREAM_IN,
579  RECV_ATTR_INT(ATTR_NAME_INT, &int_val),
580  RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val),
581  RECV_ATTR_STR(ATTR_NAME_STR, str_val),
582  RECV_ATTR_DATA(ATTR_NAME_DATA, data_val),
583  ATTR_TYPE_END)) == 4) {
584  vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
585  vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
586  vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
587  vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
588  ht_info_list = htable_list(table);
589  for (ht = ht_info_list; *ht; ht++)
590  vstream_printf("(hash) %s %s\n", ht[0]->key, (char *) ht[0]->value);
591  myfree((void *) ht_info_list);
592  } else {
593  vstream_printf("return: %d\n", ret);
594  }
595  if (vstream_fflush(VSTREAM_OUT) != 0)
596  msg_fatal("write error: %m");
597 
598  vstring_free(data_val);
599  vstring_free(str_val);
600  htable_free(table, myfree);
601 
602  return (0);
603 }
604 
605 #endif
int msg_verbose
Definition: msg.c:177
void htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
HTABLE_INFO * htable_locate(HTABLE *table, const char *key)
Definition: htable.c:242
#define ATTR_FLAG_EXTRA
Definition: attr.h:100
int attr_scan_more_plain(VSTREAM *fp)
char * mystrdup(const char *str)
Definition: mymalloc.c:225
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define VSTREAM_OUT
Definition: vstream.h:67
#define ATTR_FLAG_MISSING
Definition: attr.h:99
ssize_t used
Definition: htable.h:27
int main(int argc, char **argv)
Definition: anvil.c:1010
#define VSTREAM_GETC(vp)
Definition: vstream.h:108
#define ATTR_TYPE_FUNC
Definition: attr.h:47
#define ATTR_TYPE_CLOSE
Definition: attr.h:53
int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
#define RECV_ATTR_HASH(val)
Definition: attr.h:73
int attr_scan_plain(VSTREAM *fp, int flags,...)
#define VSTREAM_IN
Definition: vstream.h:66
Definition: htable.h:25
#define STR(x)
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
HTABLE_INFO ** htable_list(HTABLE *table)
Definition: htable.c:330
#define ATTR_TYPE_INT
Definition: attr.h:40
#define ATTR_TYPE_HASH
Definition: attr.h:43
#define vstream_ungetc(vp, ch)
Definition: vstream.h:109
#define vstream_ftimeout(vp)
Definition: vstream.h:124
#define RECV_ATTR_LONG(name, val)
Definition: attr.h:75
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define RECV_ATTR_DATA(name, val)
Definition: attr.h:76
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define ATTR_TYPE_STR
Definition: attr.h:42
int var_line_limit
Definition: mail_params.c:263
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
VSTRING * base64_decode(VSTRING *, const char *, ssize_t)
Definition: base64_code.c:135
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define ATTR_TYPE_LONG
Definition: attr.h:45
#define ATTR_TYPE_DATA
Definition: attr.h:46
int(* ATTR_SCAN_SLAVE_FN)(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *)
Definition: attr.h:32
#define LEN(x)
#define ATTR_NAME_OPEN
Definition: attr.h:54
#define ATTR_FLAG_MORE
Definition: attr.h:101
#define ATTR_NAME_CLOSE
Definition: attr.h:55
#define VSTREAM_ERR
Definition: vstream.h:68
#define ATTR_FLAG_ALL
Definition: attr.h:104
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199
#define ATTR_HASH_LIMIT
Definition: attr.h:57