/* Copyright 2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "httpd.h" #include "http_config.h" #include "http_log.h" #include "apr_version.h" #include "mod_smtpd.h" /* mod_smtpd_queue_smtp - a mod_smtpd queue handler that sends messages * to an alternative SMTP server for delivery, so mod_smtpd can easily be * integrated into an existing mail system. */ #define BUFFER_LEN 1024 /* old versions of APR don't have APR_ARRAY_IDX, so define our own copy if * it's not there already. */ #ifndef APR_ARRAY_IDX #define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i]) #endif /* APR 1.0 changed the arguments for apr_socket_create, mask the difference * by using apr_socket_create_ex in its place. */ #if APR_MAJOR_VERSION < 1 #define apr_socket_create apr_socket_create_ex #endif module AP_MODULE_DECLARE_DATA smtpd_queue_smtp_module; typedef struct { const char *host; int port; int on; } smtpd_queue_smtp_config; static void *smtpd_queue_smtp_create_server_config(apr_pool_t *p, server_rec *s) { return apr_pcalloc(p, sizeof(smtpd_queue_smtp_config)); } /* Queue a message by sending it to a remote server for delivery. */ static smtpd_retcode queue_message(smtpd_session_rec *scr) { apr_status_t apr_err = APR_SUCCESS; smtpd_retcode rv = SMTPD_DECLINED; apr_pool_t *subpool; apr_bucket_brigade *body; smtpd_queue_smtp_config *cfg = ap_get_module_config( scr->s->module_config, &smtpd_queue_smtp_module ); if (! cfg->on) return SMTPD_DECLINED; else { if (cfg->host == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, scr->s, "SmtpQueueSmtp enabled but host not set"); return SMTPD_DECLINED; } if (cfg->port == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, scr->s, "SmtpQueueSmtp enabled but port not set"); return SMTPD_DECLINED; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, scr->s, "Queuing message to smtp://%s:%d", cfg->host, cfg->port); } body = apr_brigade_create(scr->per_command_pool, scr->c->bucket_alloc); /* first add on headers */ { const apr_array_header_t *arr; const apr_table_entry_t *elts; apr_bucket *bucket; int i; arr = apr_table_elts(scr->envelope->headers); elts = (const apr_table_entry_t *) arr->elts; for (i = 0; i < arr->nelts; ++i) { char *bucket_str = apr_pstrcat(scr->per_command_pool, elts[i].key, ": ", elts[i].val, "\r\n", NULL); bucket = apr_bucket_pool_create(bucket_str, strlen(bucket_str), scr->per_command_pool, scr->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(body, bucket); } bucket = apr_bucket_immortal_create("\r\n", 2, scr->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(body, bucket); } /* now add on body */ { apr_finfo_t finfo; apr_err = apr_file_info_get(&finfo, APR_FINFO_SIZE, scr->envelope->tfp); APR_BRIGADE_INSERT_TAIL( body, apr_bucket_file_create(scr->envelope->tfp, 0, finfo.size, scr->per_command_pool, scr->c->bucket_alloc)); } smtpd_send_message(scr->s, scr->per_command_pool, cfg->host, cfg->port, scr->envelope->mail_from, apr_table_elts(scr->envelope->rcpt_to), body); /* set queued flags */ { const apr_array_header_t *arr; const apr_table_entry_t *elts; int i; arr = apr_table_elts(scr->envelope->rcpt_to); elts = (const apr_table_entry_t *) arr->elts; for (i = 0; i < arr->nelts; ++i) { apr_table_set(scr->envelope->rcpt_to, elts[i].key, "queued"); } } if (apr_err) ap_log_error(APLOG_MARK, APLOG_ERR, apr_err, scr->s, "Error queuing to smtp server"); return SMTPD_OK; } static void smtpd_queue_smtp_register_hooks(apr_pool_t * p) { smtpd_hook_on_queue(queue_message, NULL, NULL, APR_HOOK_LAST); } static const char *enable_queue_smtp(cmd_parms *cmd, void *baton, int arg) { smtpd_queue_smtp_config *cfg = ap_get_module_config( cmd->server->module_config, &smtpd_queue_smtp_module ); cfg->on = arg; return NULL; } static const char *set_queue_smtp_host(cmd_parms *cmd, void *baton, const char *arg) { smtpd_queue_smtp_config *cfg = ap_get_module_config( cmd->server->module_config, &smtpd_queue_smtp_module ); cfg->host = arg; return NULL; } static const char *set_queue_smtp_port(cmd_parms *cmd, void *baton, const char *arg) { smtpd_queue_smtp_config *cfg = ap_get_module_config( cmd->server->module_config, &smtpd_queue_smtp_module ); cfg->port = atoi(arg); return NULL; } static const command_rec smtpd_queue_smtp_cmds[] = { AP_INIT_FLAG("SmtpQueueSmtp", enable_queue_smtp, NULL, RSRC_CONF, "Enable queuing to another SMTP server. Default: Off"), AP_INIT_TAKE1("SmtpQueueSmtpHost", set_queue_smtp_host, NULL, RSRC_CONF, "Set the hostname for the remote SMTP server."), AP_INIT_TAKE1("SmtpQueueSmtpPort", set_queue_smtp_port, NULL, RSRC_CONF, "Set the port for the remote SMTP server."), { NULL } }; module AP_MODULE_DECLARE_DATA smtpd_queue_smtp_module = { STANDARD20_MODULE_STUFF, NULL, NULL, smtpd_queue_smtp_create_server_config, NULL, smtpd_queue_smtp_cmds, smtpd_queue_smtp_register_hooks };