Postfix3.3.1
showq_json.c
[詳解]
1 /*++
2 /* NAME
3 /* showq_json 8
4 /* SUMMARY
5 /* JSON queue status formatter
6 /* SYNOPSIS
7 /* void showq_json(
8 /* VSTREAM *showq)
9 /* DESCRIPTION
10 /* This function converts showq(8) daemon output to JSON format.
11 /* DIAGNOSTICS
12 /* Fatal errors: out of memory, malformed showq(8) daemon output.
13 /* LICENSE
14 /* .ad
15 /* .fi
16 /* The Secure Mailer license must be distributed with this software.
17 /* AUTHOR(S)
18 /* Wietse Venema
19 /* IBM T.J. Watson Research
20 /* P.O. Box 704
21 /* Yorktown Heights, NY 10598, USA
22 /*
23 /* Wietse Venema
24 /* Google, Inc.
25 /* 111 8th Avenue
26 /* New York, NY 10011, USA
27 /*--*/
28 
29 /* System library. */
30 
31 #include <sys_defs.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sysexits.h>
36 #include <ctype.h>
37 #include <errno.h>
38 
39 /* Utility library. */
40 
41 #include <vstring.h>
42 #include <vstream.h>
43 #include <stringops.h>
44 #include <mymalloc.h>
45 #include <msg.h>
46 
47 /* Global library. */
48 
49 #include <mail_proto.h>
50 #include <mail_queue.h>
51 #include <mail_date.h>
52 #include <mail_params.h>
53 
54 /* Application-specific. */
55 
56 #include <postqueue.h>
57 
58 #define STR(x) vstring_str(x)
59 #define LEN(x) VSTRING_LEN(x)
60 
61 /* json_quote - quote JSON string */
62 
63 static char *json_quote(VSTRING *result, const char *text)
64 {
65  unsigned char *cp;
66  int ch;
67 
68  /*
69  * We use short escape sequences for common control characters. Note that
70  * RFC 4627 allows "/" (0x2F) to be sent without quoting. Differences
71  * with RFC 4627: we send DEL (0x7f) as \u007F; the result remains RFC
72  * 4627 complaint.
73  */
74  VSTRING_RESET(result);
75  for (cp = (unsigned char *) text; (ch = *cp) != 0; cp++) {
76  if (UNEXPECTED(ISCNTRL(ch))) {
77  switch (ch) {
78  case '\b':
79  VSTRING_ADDCH(result, '\\');
80  VSTRING_ADDCH(result, 'b');
81  break;
82  case '\f':
83  VSTRING_ADDCH(result, '\\');
84  VSTRING_ADDCH(result, 'f');
85  break;
86  case '\n':
87  VSTRING_ADDCH(result, '\\');
88  VSTRING_ADDCH(result, 'n');
89  break;
90  case '\r':
91  VSTRING_ADDCH(result, '\\');
92  VSTRING_ADDCH(result, 'r');
93  break;
94  case '\t':
95  VSTRING_ADDCH(result, '\\');
96  VSTRING_ADDCH(result, 't');
97  break;
98  default:
99  vstring_sprintf(result, "\\u%04X", ch);
100  break;
101  }
102  } else {
103  switch (ch) {
104  case '\\':
105  case '"':
106  VSTRING_ADDCH(result, '\\');
107  /* FALLTHROUGH */
108  default:
109  VSTRING_ADDCH(result, ch);
110  break;
111  }
112  }
113  }
114  VSTRING_TERMINATE(result);
115 
116  /*
117  * Force the result to be UTF-8 (with SMTPUTF8 enabled) or ASCII (with
118  * SMTPUTF8 disabled).
119  */
120  printable(STR(result), '?');
121  return (STR(result));
122 }
123 
124 /* json_message - report status for one message */
125 
126 static void format_json(VSTREAM *showq_stream)
127 {
128  static VSTRING *queue_name = 0;
129  static VSTRING *queue_id = 0;
130  static VSTRING *addr = 0;
131  static VSTRING *why = 0;
132  static VSTRING *quote_buf = 0;
133  long arrival_time;
134  long message_size;
135  int showq_status;
136  int rcpt_count = 0;
137 
138  /*
139  * One-time initialization.
140  */
141  if (queue_name == 0) {
142  queue_name = vstring_alloc(100);
143  queue_id = vstring_alloc(100);
144  addr = vstring_alloc(100);
145  why = vstring_alloc(100);
146  quote_buf = vstring_alloc(100);
147  }
148 
149  /*
150  * Read the message properties and sender address.
151  */
152  if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
153  RECV_ATTR_STR(MAIL_ATTR_QUEUE, queue_name),
154  RECV_ATTR_STR(MAIL_ATTR_QUEUEID, queue_id),
155  RECV_ATTR_LONG(MAIL_ATTR_TIME, &arrival_time),
156  RECV_ATTR_LONG(MAIL_ATTR_SIZE, &message_size),
158  ATTR_TYPE_END) != 5)
159  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
160  vstream_printf("{");
161  vstream_printf("\"queue_name\": \"%s\", ",
162  json_quote(quote_buf, STR(queue_name)));
163  vstream_printf("\"queue_id\": \"%s\", ",
164  json_quote(quote_buf, STR(queue_id)));
165  vstream_printf("\"arrival_time\": %ld, ", arrival_time);
166  vstream_printf("\"message_size\": %ld, ", message_size);
167  vstream_printf("\"sender\": \"%s\", ",
168  json_quote(quote_buf, STR(addr)));
169 
170  /*
171  * Read zero or more (recipient, reason) pair(s) until attr_scan_more()
172  * consumes a terminator. If the showq daemon messes up, don't try to
173  * resynchronize.
174  */
175  vstream_printf("\"recipients\": [");
176  for (rcpt_count = 0; (showq_status = attr_scan_more(showq_stream)) > 0; rcpt_count++) {
177  if (rcpt_count > 0)
178  vstream_printf(", ");
179  vstream_printf("{");
180  if (attr_scan(showq_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
183  ATTR_TYPE_END) != 2)
184  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
185  vstream_printf("\"address\": \"%s\"",
186  json_quote(quote_buf, STR(addr)));
187  if (LEN(why) > 0)
188  vstream_printf(", \"delay_reason\": \"%s\"",
189  json_quote(quote_buf, STR(why)));
190  vstream_printf("}");
191  }
192  vstream_printf("]");
193  if (showq_status < 0)
194  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
195  vstream_printf("}\n");
196  if (vstream_fflush(VSTREAM_OUT) && errno != EPIPE)
197  msg_fatal_status(EX_IOERR, "output write error: %m");
198 }
199 
200 /* showq_json - streaming JSON-format output adapter */
201 
202 void showq_json(VSTREAM *showq_stream)
203 {
204  int showq_status;
205 
206  /*
207  * Emit zero or more queue file objects until attr_scan_more() consumes a
208  * terminator.
209  */
210  while ((showq_status = attr_scan_more(showq_stream)) > 0
211  && vstream_ferror(VSTREAM_OUT) == 0) {
212  format_json(showq_stream);
213  }
214  if (showq_status < 0)
215  msg_fatal_status(EX_SOFTWARE, "malformed showq server response");
216 }
void showq_json(VSTREAM *showq_stream)
Definition: showq_json.c:202
#define VSTREAM_OUT
Definition: vstream.h:67
#define MAIL_ATTR_SIZE
Definition: mail_proto.h:139
#define EX_IOERR
Definition: sys_exits.h:41
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
#define STR(x)
Definition: showq_json.c:58
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
#define EX_SOFTWARE
Definition: sys_exits.h:37
#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
#define MAIL_ATTR_WHY
Definition: mail_proto.h:135
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define MAIL_ATTR_TIME
Definition: mail_proto.h:142
#define attr_scan_more
Definition: attr.h:113
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define ISCNTRL(c)
Definition: sys_defs.h:1747
#define LEN(x)
Definition: showq_json.c:59
#define MAIL_ATTR_RECIP
Definition: mail_proto.h:134
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
NORETURN msg_fatal_status(int status, const char *fmt,...)
Definition: msg.c:272
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
char * printable(char *string, int replacement)
Definition: printable.c:49
#define attr_scan
Definition: attr.h:111
#define vstream_ferror(vp)
Definition: vstream.h:120
#define ATTR_FLAG_MORE
Definition: attr.h:101
#define UNEXPECTED(x)
Definition: sys_defs.h:1639
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103