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