/* Module to send mail using a "sendmail" program. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #include "services.h" #include "modules.h" #include "conffile.h" #include "language.h" #include "mail.h" #include "mail-local.h" #include /* for WIFEXITED(), etc. */ /*************************************************************************/ static Module *module; static char *SendmailPath; static Module *module_mail_main; static typeof(low_send) *low_send_p; /*************************************************************************/ /***************************** Mail sending ******************************/ /*************************************************************************/ static int send_sendmail(const char *from, const char *fromname, const char *to, const char *subject, const char *body) { FILE *pipe; char cmd[PATH_MAX+4]; char buf[BUFSIZE], *s; int res; time_t t; snprintf(cmd, sizeof(cmd), "%s -t", SendmailPath); pipe = popen(cmd, "w"); if (!pipe) { module_log_perror("Unable to execute %s", SendmailPath); return -1; } /* Quote all double-quotes in from-name string */ if (*fromname) { s = buf; while (s < buf+sizeof(buf)-2 && *fromname) { if (*fromname == '"') *s++ = '\\'; *s++ = *fromname++; } *s = 0; fprintf(pipe, "From: %s <%s>\n", buf, from); } else { fprintf(pipe, "From: %s\n", from); } time(&t); if (!strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", gmtime(&t))) strscpy(buf, "Thu, 1 Jan 1970 00:00:00", sizeof(buf)); fprintf(pipe, "To: %s\nSubject: %s\nDate: %s +0000\n\n%s\n", to, subject, buf, body); res = pclose(pipe); if (res == -1) { module_log_perror("pclose() failed"); } else if (res != 0) { if (debug >= 2) module_log("debug: sendmail exit code = %04X\n", res); module_log("%s exited with %s %d%s", SendmailPath, WIFEXITED(res) ? "code" : "signal", WIFEXITED(res) ? WEXITSTATUS(res) : WTERMSIG(res), WIFEXITED(res) && WEXITSTATUS(res)==127 ? " (unable to execute program?)" : ""); return -1; } return 0; } /*************************************************************************/ /***************************** Module stuff ******************************/ /*************************************************************************/ const int32 module_version = MODULE_VERSION_CODE; static int do_SendmailPath(const char *filename, int linenum, char *param); ConfigDirective module_config[] = { { "SendmailPath", { { CD_FUNC, CF_DIRREQ, do_SendmailPath } } }, { NULL } }; /*************************************************************************/ static int do_SendmailPath(const char *filename, int linenum, char *param) { static char *new_SendmailPath = NULL; if (filename) { /* Check parameter for validity and save */ if (*param != '/') { config_error(filename, linenum, "SendmailPath value must begin with a slash (`/')"); return 0; } free(new_SendmailPath); new_SendmailPath = strdup(param); if (!new_SendmailPath) { config_error(filename, linenum, "Out of memory"); return 0; } } else if (linenum == CDFUNC_SET) { /* Copy new values to config variables and clear */ if (new_SendmailPath) { /* paranoia */ free(SendmailPath); SendmailPath = new_SendmailPath; } else { free(new_SendmailPath); } new_SendmailPath = NULL; } else if (linenum == CDFUNC_DECONFIG) { /* Reset to defaults */ free(SendmailPath); SendmailPath = NULL; } return 1; } /*************************************************************************/ static int do_load_module(Module *mod, const char *modname) { if (strcmp(modname, "mail/main") == 0) { module_mail_main = mod; low_send_p = get_module_symbol(mod, "low_send"); if (low_send_p) *low_send_p = send_sendmail; else module_log("Unable to find `low_send' symbol, cannot send mail"); } return 0; } /*************************************************************************/ static int do_unload_module(Module *mod) { if (mod == module_mail_main) { if (low_send_p) *low_send_p = NULL; low_send_p = NULL; module_mail_main = NULL; } return 0; } /*************************************************************************/ int init_module(Module *module_) { Module *tmpmod; module = module_; if (!add_callback(NULL, "load module", do_load_module) || !add_callback(NULL, "unload module", do_unload_module) ) { module_log("Unable to add callbacks"); exit_module(0); return 0; } tmpmod = find_module("mail/main"); if (tmpmod) do_load_module(tmpmod, "mail/main"); return 1; } /*************************************************************************/ int exit_module(int shutdown_unused) { #ifdef CLEAN_COMPILE shutdown_unused = shutdown_unused; #endif if (module_mail_main) do_unload_module(module_mail_main); remove_callback(NULL, "unload module", do_unload_module); remove_callback(NULL, "load module", do_load_module); return 1; } /*************************************************************************/