"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "mod_sendmail.c" see the
Fossies "Dox" file reference documentation.
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Provides a restful interface to gate email messages through to sendmail.
19 *
20 * A return mechanism is provided to report whether messages have been
21 * delivered, using VERP and DSN.
22 *
23 *
24 */
25 #include <apr_lib.h>
26 #include <apr_sha1.h>
27 #include <apr_strings.h>
28 #include <apr_hash.h>
29 #include <apr_uuid.h>
30
31 #include "httpd.h"
32 #include "http_config.h"
33 #include "http_core.h"
34 #include "http_log.h"
35 #include "http_protocol.h"
36 #include "http_request.h"
37 #include "util_script.h"
38
39 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
40 #include "ap_expr.h"
41 #endif
42
43 #define DEFAULT_HASH_TIMEOUT 86400
44 #define DEFAULT_SALT_LENGTH 4
45 #define DEFAULT_PROGNAME "/usr/lib/sendmail"
46
47 typedef struct
48 {
49 const char *progname;
50 int progname_set;
51 apr_array_header_t *args;
52 const char *location;
53 int location_set;
54 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
55 ap_expr_info_t *dsn_location;
56 #else
57 const char *dsn_location;
58 #endif
59 int dsn_location_set;
60 const char *sendermail;
61 int sendermail_set;
62 const char *sendername;
63 int sendername_set;
64 } sendmail_config_rec;
65
66 typedef struct
67 {
68 request_rec *r;
69 apr_file_t *file;
70 int found;
71 } sendmail_array_rec;
72
73 static void *create_sendmail_dir_config(apr_pool_t *p, char *d)
74 {
75 sendmail_config_rec *conf = apr_pcalloc(p, sizeof(sendmail_config_rec));
76
77 conf->progname = DEFAULT_PROGNAME;
78 conf->args = apr_array_make(p, 8, sizeof(const char * const *));
79 conf->location = NULL;
80
81 return conf;
82 }
83
84 static void *merge_sendmail_dir_config(apr_pool_t *p, void *basev, void *addv)
85 {
86 sendmail_config_rec *new = (sendmail_config_rec *) apr_pcalloc(p,
87 sizeof(sendmail_config_rec));
88 sendmail_config_rec *add = (sendmail_config_rec *) addv;
89 sendmail_config_rec *base = (sendmail_config_rec *) basev;
90
91 new->progname = (add->progname_set == 0) ? base->progname : add->progname;
92 new->progname_set = add->progname_set || base->progname_set;
93 new->args = apr_array_append(p, add->args, base->args);
94 new->location = (add->location_set == 0) ? base->location : add->location;
95 new->location_set = add->location_set || base->location_set;
96 new->dsn_location = (add->dsn_location_set == 0) ? base->dsn_location
97 : add->dsn_location;
98 new->dsn_location_set = add->dsn_location_set || base->dsn_location_set;
99 new->sendermail = (add->sendermail_set == 0) ? base->sendermail
100 : add->sendermail;
101 new->sendermail_set = add->sendermail_set || base->sendermail_set;
102 new->sendername = (add->sendername_set == 0) ? base->sendername
103 : add->sendername;
104 new->sendername_set = add->sendername_set || base->sendername_set;
105
106 return new;
107 }
108
109 static const char *set_progname(cmd_parms *cmd, void *dconf, const char *arg)
110 {
111 sendmail_config_rec *conf = dconf;
112
113 conf->progname = arg;
114 conf->progname_set = 1;
115
116 return NULL;
117 }
118
119 static const char *set_args(cmd_parms *cmd, void *dconf, const char *arg)
120 {
121 sendmail_config_rec *conf = dconf;
122 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
123 ap_expr_info_t **array = apr_array_push(conf->args);
124 const char *err;
125
126 *array = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
127 &err, NULL);
128 if (err) {
129 return apr_psprintf(cmd->pool,
130 "Could not parse SendmailArgument expression '%s': %s",
131 arg, err);
132 }
133
134 #else
135 const char **array = apr_array_push(conf->args);
136
137 *array = arg;
138 #endif
139
140 return NULL;
141 }
142
143 static const char *set_location(cmd_parms *cmd, void *dconf, const char *arg)
144 {
145 sendmail_config_rec *conf = dconf;
146 conf->location = arg;
147 conf->location_set = 1;
148
149 return NULL;
150 }
151
152 static const char *set_dsn_location(cmd_parms *cmd, void *dconf,
153 const char *arg)
154 {
155 sendmail_config_rec *conf = dconf;
156 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
157 const char *err;
158
159 conf->dsn_location = ap_expr_parse_cmd(cmd, arg, AP_EXPR_FLAG_STRING_RESULT,
160 &err, NULL);
161 if (err) {
162 return apr_psprintf(cmd->pool,
163 "Could not parse SendmailDSNLocation expression '%s': %s",
164 arg, err);
165 }
166
167 #else
168 conf->dsn_location = arg;
169 #endif
170 conf->dsn_location_set = 1;
171
172 return NULL;
173 }
174
175 static const char *set_sender_mail(cmd_parms *cmd, void *dconf, const char *arg)
176 {
177 sendmail_config_rec *conf = dconf;
178
179 conf->sendermail = arg;
180 conf->sendermail_set = 1;
181
182 return NULL;
183 }
184
185 static const char *set_sender_name(cmd_parms *cmd, void *dconf, const char *arg)
186 {
187 sendmail_config_rec *conf = dconf;
188
189 conf->sendername = arg;
190 conf->sendername_set = 1;
191
192 return NULL;
193 }
194
195 static const command_rec sendmail_cmds[] =
196 {
197 AP_INIT_TAKE1("SendmailName",
198 set_progname, NULL, RSRC_CONF | ACCESS_CONF,
199 "Set to the path and name of the sendmail binary."),
200 AP_INIT_ITERATE(
201 "SendmailArguments", set_args, NULL, RSRC_CONF | ACCESS_CONF,
202 "Set to the arguments to pass to the sendmail binary."),
203 AP_INIT_TAKE1("SendmailLocation",
204 set_location, NULL, RSRC_CONF | ACCESS_CONF,
205 "Set to the location of the sendmail service."),
206 AP_INIT_TAKE1("SendmailDSNLocation",
207 set_dsn_location, NULL, RSRC_CONF | ACCESS_CONF,
208 "Set to the location of the delivery status notification service."),
209 AP_INIT_TAKE1("SendmailSenderMail",
210 set_sender_mail, NULL, RSRC_CONF | ACCESS_CONF,
211 "Set to the name of the variable for the from address."),
212 AP_INIT_TAKE1("SendmailSenderName",
213 set_sender_name, NULL, RSRC_CONF | ACCESS_CONF,
214 "Set to the name of the variable for the from name."),
215 { NULL } };
216
217 module AP_MODULE_DECLARE_DATA sendmail_module;
218
219 static void log_message(request_rec *r, apr_status_t status,
220 const char *message)
221 {
222 apr_table_setn(r->notes, "error-notes", apr_pstrcat(r->pool,
223 "The sendmail gateway could not accept the mail: ", ap_escape_html(
224 r->pool, message), NULL));
225
226 /* Allow "error-notes" string to be printed by ap_send_error_response() */
227 apr_table_setn(r->notes, "verbose-error-to", "*");
228
229 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, "%s", message);
230 }
231
232 static int contains_do(void *rec, const char *key, const char *value)
233 {
234 sendmail_array_rec *arr = (sendmail_array_rec *) rec;
235 arr->found = 1;
236 return 1;
237 }
238
239 static int header_do(void *rec, const char *key, const char *value)
240 {
241 sendmail_array_rec *arr = (sendmail_array_rec *) rec;
242 apr_size_t len;
243
244 len = apr_file_printf(arr->file, "%s: %s" CRLF, key, value);
245
246 if (len <= 0) {
247 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, arr->r,
248 "error writing header to sendmail");
249 return 0;
250 }
251
252 return 1;
253 }
254
255 static int pipe_to_sendmail(request_rec *r, sendmail_config_rec *conf,
256 const char *message_id)
257 {
258
259 const char **buf;
260 const char * const *args;
261 const char * const *env;
262 apr_proc_t *procnew;
263 apr_status_t status;
264 apr_procattr_t *procattr;
265 apr_bucket_brigade *bb;
266 sendmail_array_rec arr;
267 int seen_eos, child_stopped_reading = 0, rv, i;
268 const char *data, *from, *sender;
269 apr_size_t len;
270 int exitcode;
271 apr_exit_why_e exitwhy;
272 static const char
273 *strip_headers[] =
274 { "Cache-Control", "Connection", "Pragma", "Trailer",
275 "Transfer-Encoding", "Upgrade", "Warning", "Accept",
276 "Accept-Charset", "Accept-Encoding", "Accept-Language",
277 "Authorization", "Expect", "Host", "If-Match",
278 "If-Modified-Since", "If-None-Match", "If-Range",
279 "If-Unmodified-Since", "Max-Forwards",
280 "Proxy-Authorization", "Range", "Referer", "TE",
281 "User-Agent", NULL };
282 apr_table_t *headers = apr_table_copy(r->pool, r->headers_in);
283 char date_str[APR_RFC822_DATE_LEN];
284
285 /* remove hop by hop headers */
286 for (i = 0; strip_headers[i]; i++) {
287 apr_table_unset(headers, strip_headers[i]);
288 }
289
290 if (!conf->progname) {
291
292 /* sendmail binary not specified, bail out */
293 log_message(r, APR_SUCCESS, "sendmail binary name not specified");
294
295 return HTTP_INTERNAL_SERVER_ERROR;
296
297 }
298
299 if (((status = apr_procattr_create(&procattr, r->pool)) != APR_SUCCESS)
300 || ((status = apr_procattr_io_set(procattr, APR_CHILD_BLOCK,
301 APR_CHILD_BLOCK, APR_CHILD_BLOCK)) != APR_SUCCESS)
302 || ((status = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(
303 r->pool, conf->progname))) != APR_SUCCESS) || ((status
304 = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV))
305 != APR_SUCCESS) ||
306
307 ((status = apr_procattr_detach_set(procattr, 0)) != APR_SUCCESS)
308 || ((status = apr_procattr_addrspace_set(procattr, 0))
309 != APR_SUCCESS)) {
310
311 /* Something bad happened, tell the world. */
312 log_message(r, status, apr_psprintf(r->pool,
313 "couldn't set child process attributes: %s", conf->progname));
314
315 return HTTP_INTERNAL_SERVER_ERROR;
316
317 }
318
319 env = (const char * const *) ap_create_environment(r->pool,
320 r->subprocess_env);
321
322 procnew = apr_pcalloc(r->pool, sizeof(*procnew));
323
324 buf = apr_pcalloc(r->pool, sizeof(char *) * (conf->args->nelts + 2));
325 args = memcpy(buf, &conf->progname, sizeof(char *));
326 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
327 for (i = 0; i < conf->args->nelts; i++) {
328 const char *err;
329 *(buf + i + 1) = ap_expr_str_exec(r,
330 conf->dsn_location, &err);
331 if (err) {
332 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02339)
333 "Can't evaluate SendmailArgument expression: %s", err);
334 return HTTP_INTERNAL_SERVER_ERROR;
335 }
336 }
337 #else
338 memcpy(buf + 1, conf->args->elts, sizeof(char *)
339 * conf->args->nelts);
340 #endif
341
342 status = apr_proc_create(procnew, conf->progname, args, env, procattr,
343 r->pool);
344 if (status != APR_SUCCESS) {
345
346 log_message(r, status, apr_psprintf(r->pool, "Could not crank up '%s'",
347 conf->progname));
348
349 return HTTP_INTERNAL_SERVER_ERROR;
350
351 }
352
353 apr_pool_note_subprocess(r->pool, procnew, APR_KILL_AFTER_TIMEOUT);
354
355 if (!procnew->out) {
356
357 log_message(r, APR_EBADF,
358 "Timeout could not be set reading request entity data");
359
360 return HTTP_INTERNAL_SERVER_ERROR;
361
362 }
363 apr_file_pipe_timeout_set(procnew->out, r->server->timeout);
364
365 if (!procnew->in) {
366
367 log_message(r, APR_EBADF,
368 "Timeout could not be set reading request entity data");
369
370 return HTTP_INTERNAL_SERVER_ERROR;
371
372 }
373 apr_file_pipe_timeout_set(procnew->in, r->server->timeout);
374
375 if (!procnew->err) {
376
377 log_message(r, APR_EBADF,
378 "Timeout could not be set reading request entity data");
379
380 return HTTP_INTERNAL_SERVER_ERROR;
381
382 }
383 apr_file_pipe_timeout_set(procnew->err, r->server->timeout);
384
385 arr.r = r;
386 arr.file = procnew->in;
387 arr.found = 0;
388
389 /* sanity check - no to or cc, bail out */
390 rv = apr_table_do(contains_do, &arr, headers, "To", "CC", NULL);
391 if (!arr.found) {
392
393 log_message(r, APR_SUCCESS,
394 "No 'To' or 'CC' was present in the request");
395
396 return HTTP_BAD_REQUEST;
397 }
398
399 sender = apr_table_get(headers, "Sender");
400 if (conf->sendermail) {
401 const char *mail = apr_table_get(r->subprocess_env, conf->sendermail);
402 const char *name = conf->sendername ? apr_table_get(r->subprocess_env,
403 conf->sendername) : NULL;
404
405 if (!mail) {
406
407 log_message(
408 r,
409 APR_SUCCESS,
410 apr_psprintf(
411 r->pool,
412 "No '%s' was present in the request subprocess environment",
413 conf->sendermail));
414
415 return HTTP_BAD_REQUEST;
416 }
417
418 if (name && strchr(name, ',')) {
419 name = apr_psprintf(r->pool, "\"%s\"", name);
420 }
421
422 if (name) {
423 sender = apr_psprintf(r->pool, "%s <%s>", name, mail);
424 }
425 else {
426 sender = mail;
427 }
428 apr_table_setn(headers, "Sender", sender);
429
430 }
431
432 /* when sender and from are the same, collapse to only have from */
433 from = apr_table_get(headers, "From");
434 if (sender && from) {
435 if (!strcmp(sender, from)) {
436 apr_table_unset(headers, "Sender");
437 }
438 }
439
440 /* sanity check - did we have a from? */
441 if (!from) {
442
443 log_message(r, APR_SUCCESS, "No 'From' was present in the request");
444
445 return HTTP_BAD_REQUEST;
446 }
447
448 /* add a received header */
449 ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_DOUBLE_REV,
450 NULL);
451 apr_rfc822_date(date_str, apr_time_now());
452 #if AP_MODULE_MAGIC_AT_LEAST(20111125,0)
453 header_do(&arr, "Received", apr_pstrcat(r->pool, "from [",
454 r->useragent_ip, "] (",
455 strcmp(r->useragent_ip, r->connection->client_ip) ||
456 !r->connection->remote_host ? r->connection->remote_host
457 : r->useragent_ip, " [", r->useragent_ip,
458 "])\n\t", r->user ? "(Authenticated sender: " : "",
459 r->user ? r->user : "", r->user ? ")\n\t" : "", "by ",
460 r->server->server_hostname ? r->server->server_hostname
461 : r->connection->local_ip, " (mod_sendmail)\n\tfor ", from,
462 "; ", date_str, NULL));
463 #else
464 header_do(&arr, "Received", apr_pstrcat(r->pool, "from [",
465 r->connection->remote_ip, "] (",
466 r->connection->remote_host ? r->connection->remote_host
467 : r->connection->remote_ip, " [", r->connection->remote_ip,
468 "])\n\t", r->user ? "(Authenticated sender: " : "",
469 r->user ? r->user : "", r->user ? ")\n\t" : "", "by ",
470 r->server->server_hostname ? r->server->server_hostname
471 : r->connection->local_ip, " (mod_sendmail)\n\tfor ", from,
472 "; ", date_str, NULL));
473 #endif
474
475 /* message-id from the URL */
476 if (message_id) {
477 apr_table_set(headers, "Message-ID", message_id);
478 }
479
480 /* message-id missing? add our own */
481 if (!message_id && !(message_id = apr_table_get(headers, "Message-ID"))) {
482 char buffer[APR_UUID_FORMATTED_LENGTH + 1];
483 apr_uuid_t uuid;
484 apr_uuid_get(&uuid);
485 apr_uuid_format(buffer, &uuid);
486
487 message_id = apr_psprintf(r->pool, "<%s@%s>", buffer,
488 r->server->server_hostname);
489
490 len = apr_file_printf(procnew->in, "Message-ID: %s" CRLF, message_id);
491
492 if (len <= 0) {
493 /* silly script stopped reading, soak up remaining message */
494 child_stopped_reading = 1;
495
496 log_message(r, status, "Sendmail stopped reading message, aborting");
497
498 }
499
500 }
501
502 /* pass headers to sendmail */
503 rv = apr_table_do(header_do, &arr, headers, NULL);
504 if (!rv) {
505 /* we expect the error to be logged already */
506 return HTTP_INTERNAL_SERVER_ERROR;
507 }
508
509 len = apr_file_printf(procnew->in, CRLF);
510
511 if (len <= 0) {
512 /* silly script stopped reading, soak up remaining message */
513 child_stopped_reading = 1;
514
515 log_message(r, status, "Sendmail stopped reading message, aborting");
516
517 }
518
519 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
520 seen_eos = 0;
521 do {
522 apr_bucket *bucket;
523
524 status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
525 APR_BLOCK_READ, HUGE_STRING_LEN);
526
527 if (status != APR_SUCCESS) {
528 if (APR_STATUS_IS_TIMEUP(status)) {
529 log_message(r, status,
530 "Timeout during reading request entity data");
531 return HTTP_REQUEST_TIME_OUT;
532 }
533 log_message(r, status, "Error reading request entity data");
534 return HTTP_INTERNAL_SERVER_ERROR;
535 }
536
537 for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket
538 = APR_BUCKET_NEXT(bucket)) {
539
540 if (APR_BUCKET_IS_EOS(bucket)) {
541 seen_eos = 1;
542 break;
543 }
544
545 /* We can't do much with this. */
546 if (APR_BUCKET_IS_FLUSH(bucket)) {
547 continue;
548 }
549
550 /* If the child stopped, we still must read to EOS. */
551 if (child_stopped_reading) {
552 continue;
553 }
554
555 /* read */
556 apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
557
558 /* Keep writing data to the child until done or too much time
559 * elapses with no progress or an error occurs.
560 */
561 status = apr_file_write_full(procnew->in, data, len, NULL);
562
563 if (status != APR_SUCCESS) {
564
565 /* silly script stopped reading, soak up remaining message */
566 child_stopped_reading = 1;
567
568 log_message(r, status,
569 "Sendmail stopped reading message, aborting");
570
571 }
572
573 }
574 apr_brigade_cleanup(bb);
575 } while (!seen_eos);
576
577 /* Is this flush really needed? */
578 apr_file_flush(procnew->in);
579 apr_file_close(procnew->in);
580
581 status = APR_SUCCESS;
582 while (APR_SUCCESS == status) {
583 char err[MAX_STRING_LEN];
584
585 status = apr_file_read_full(procnew->err, err, sizeof(err), &len);
586
587 if (status == APR_SUCCESS && len > 0) {
588 log_message(r, status, apr_psprintf(r->pool, "%s: %s",
589 conf->progname, apr_pstrmemdup(r->pool, err, len)));
590 }
591
592 }
593
594 /* how did sendmail do? */
595 apr_proc_wait(procnew, &exitcode, &exitwhy, APR_WAIT);
596 if (exitcode || APR_PROC_EXIT != exitwhy) {
597 log_message(
598 r,
599 APR_SUCCESS,
600 apr_psprintf(
601 r->pool,
602 "%s %s with code %d",
603 conf->progname,
604 APR_PROC_EXIT == exitwhy ? "exited normally"
605 : APR_PROC_SIGNAL == exitwhy ? "exited due to a signal"
606 : APR_PROC_SIGNAL_CORE == exitwhy ? "exited and dumped a core file"
607 : "exited", exitcode));
608 return HTTP_INTERNAL_SERVER_ERROR;
609 }
610
611 /* did the client bail out? */
612 if (child_stopped_reading) {
613 return HTTP_INTERNAL_SERVER_ERROR;
614 }
615
616 /* add a Location header to the message status */
617 if (conf->dsn_location) {
618 #if AP_MODULE_MAGIC_AT_LEAST(20071108,10)
619 const char *err;
620 const char *dsn_location = ap_expr_str_exec(r,
621 conf->dsn_location, &err);
622 if (!err) {
623 apr_table_set(r->headers_out, "Location", apr_pstrcat(r->pool,
624 dsn_location, "/", ap_escape_path_segment(r->pool,
625 message_id), "/", NULL));
626 }
627 else {
628 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02339)
629 "Can't evaluate SendmailDSNLocation expression: %s", err);
630 return HTTP_INTERNAL_SERVER_ERROR;
631 }
632 #else
633 apr_table_set(r->headers_out, "Location", apr_pstrcat(r->pool,
634 conf->dsn_location, "/", ap_escape_path_segment(r->pool,
635 message_id), "/", NULL));
636 #endif
637 return HTTP_SEE_OTHER;
638 }
639
640 return HTTP_OK;
641 }
642
643 static int wadl_description(request_rec *r, sendmail_config_rec *conf)
644 {
645
646 ap_set_content_type(r, "application/vnd.sun.wadl+xml");
647
648 ap_rprintf(
649 r,
650 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
651 "<ns1:application xmlns:ns1=\"http://wadl.dev.java.net/2009/02\"\n"
652 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
653 "xsi:schemaLocation=\"http://wadl.dev.java.net/2009/02 file:wadl.xsd\">\n"
654 "<ns1:resources base=\"%s\">\n"
655 "<ns1:resource path=\"/\">\n"
656 "<ns1:method name=\"POST\" id=\"sendmail\">\n"
657 "<ns1:request>\n"
658 "<ns1:param name=\"Message-Id\" type=\"xsi:string\" style=\"header\" required=\"false\">\n"
659 "<ns1:doc>If the caller wants to specify an explicit Message-Id, the caller should\n"
660 "pass it as a Message-Id header. If no header is provided, a message id will be\n"
661 "generated automatically, and returned in the Location header.</ns1:doc>\n"
662 "</ns1:param>\n"
663 "<ns1:param name=\"To\" type=\"xsi:string\" style=\"header\" required=\"true\">\n"
664 "<ns1:doc>The recipient of the message. Can be specified more than once to send\n"
665 "to more than one recipient.</ns1:doc>\n"
666 "</ns1:param>\n"
667 "<ns1:param name=\"CC\" type=\"xsi:string\" style=\"header\" required=\"false\">\n"
668 "<ns1:doc>The CC recipient of the message. Can be specified more than once to\n"
669 "send to more than one CC recipient.</ns1:doc>\n"
670 "</ns1:param>\n"
671 "</ns1:request>\n"
672 "<ns1:response status=\"500\">\n"
673 "<ns1:representation mediaType=\"text/html\">\n"
674 "<ns1:doc>If an internal error occurred while trying to send the mail, 500\n"
675 "Internal Server Error will be returned, and the server error log will contain\n"
676 "full details of the error.</ns1:doc>\n"
677 "</ns1:representation>\n"
678 "</ns1:response>\n"
679 "<ns1:response status=\"408\">\n"
680 "<ns1:representation mediaType=\"text/html\">\n"
681 "<ns1:doc>If an attempt to read from the caller times out, 408 Request Timed Out\n"
682 "will be returned.</ns1:doc>\n"
683 "</ns1:representation>\n"
684 "</ns1:response>\n"
685 "<ns1:response status=\"400\">\n"
686 "<ns1:representation mediaType=\"text/html\">\n"
687 "<ns1:doc>If no To or CC header was provided with the request, 400 Bad Request\n"
688 "will be returned.</ns1:doc>\n"
689 "</ns1:representation>\n"
690 "</ns1:response>\n"
691 "<ns1:response status=\"303\">\n"
692 "<ns1:doc>If mail sending is successful, and a processdsn URL has been defined,\n"
693 "303 See Other will be returned.</ns1:doc>\n"
694 "<ns1:representation mediaType=\"text/html\">\n"
695 "<ns1:param name=\"Location\" type=\"xsi:string\" style=\"header\">\n"
696 "<ns1:doc>The URL of the processdsn service where status of the message can\n"
697 "be tracked.</ns1:doc>\n"
698 "</ns1:param>\n"
699 "</ns1:representation>\n"
700 "</ns1:response>\n"
701 "<ns1:response status=\"200\">\n"
702 "<ns1:representation mediaType=\"text/html\">\n"
703 "<ns1:doc>If mail sending is successful, and a processdsn URL has not been defined,\n"
704 "200 OK will be returned.</ns1:doc>\n"
705 "</ns1:representation>\n"
706 "</ns1:response>\n"
707 "</ns1:method>\n"
708 "</ns1:resource>\n"
709 "</ns1:resources>\n"
710 "</ns1:application>\n", conf->location ? conf->location
711 : apr_pstrcat(r->pool, ap_http_scheme(r), "://",
712 r->server->server_hostname, r->uri, NULL));
713
714 return OK;
715 }
716
717 static int sendmail_handler(request_rec *r)
718 {
719
720 sendmail_config_rec *conf = ap_get_module_config(r->per_dir_config,
721 &sendmail_module);
722
723 if (!conf) {
724 return DECLINED;
725 }
726
727 if (strcmp(r->handler, "sendmail")) {
728 return DECLINED;
729 }
730
731 /* A POST to / should send the email, OPTIONS should return the WADL */
732 ap_allow_methods(r, 1, "POST", "OPTIONS", NULL);
733 if (!strcmp(r->method, "POST")) {
734 return pipe_to_sendmail(r, conf, NULL);
735 }
736 else if (!strcmp(r->method, "OPTIONS")) {
737 return wadl_description(r, conf);
738 }
739 else {
740 return HTTP_METHOD_NOT_ALLOWED;
741 }
742
743 }
744
745 static void register_hooks(apr_pool_t *p)
746 {
747 ap_hook_handler(sendmail_handler, NULL, NULL, APR_HOOK_MIDDLE);
748 }
749
750 module AP_MODULE_DECLARE_DATA sendmail_module =
751 {
752 STANDARD20_MODULE_STUFF,
753 create_sendmail_dir_config, /* dir config creater */
754 merge_sendmail_dir_config, /* dir merger --- default is to override */
755 NULL, /* server config */
756 NULL, /* merge server config */
757 sendmail_cmds, /* command apr_table_t */
758 register_hooks /* register hooks */
759 };