2 Copyright (C) 2001-2006 Kern Sibbald
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 2 as amended with additional clauses defined in the
7 file LICENSE in the main source directory.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 the file LICENSE for additional details.
16 Derived from a SMTPclient:
18 SMTPclient -- simple SMTP client
20 Copyright (C) 1997 Ralf S. Engelschall, All Rights Reserved.
24 Kern Sibbald, July 2001
35 #define bstrdup(x) strdup(x)
37 UPSINFO *core_ups = &myUPS;
38 #define MY_NAME "smtp"
44 #define MY_NAME "bsmtp"
49 int generate_daemon_event(JCR *jcr, const char *event)
59 static char *from_addr = NULL;
60 static char *cc_addr = NULL;
61 static char *subject = NULL;
62 static char *err_addr = NULL;
63 static const char *mailhost = NULL;
64 static char *reply_addr = NULL;
65 static int mailport = 25;
66 static char my_hostname[MAXSTRING];
70 * examine message from server
72 static void get_response(void)
76 Dmsg0(50, "Calling fgets on read socket rfp.\n");
78 while (fgets(buf, sizeof(buf), rfp)) {
79 int len = strlen(buf);
83 Dmsg2(10, "%s --> %s\n", mailhost, buf);
84 if (!isdigit((int)buf[0]) || buf[0] > '3') {
85 Pmsg2(0, _("Fatal malformed reply from %s: %s\n"), mailhost, buf);
96 * say something to server and check the response
98 static void chat(const char *fmt, ...)
103 vfprintf(sfp, fmt, ap);
104 if (debug_level >= 10) {
105 fprintf(stdout, "%s --> ", my_hostname);
106 vfprintf(stdout, fmt, ap);
111 if (debug_level >= 10) {
122 "Usage: %s [-f from] [-h mailhost] [-s subject] [-c copy] [recipient ...]\n"
123 " -c set the Cc: field\n"
124 " -dnn set debug level to nn\n"
125 " -f set the From: field\n"
126 " -h use mailhost:port as the SMTP server\n"
127 " -s set the Subject: field\n"
128 " -r set the Reply-To: field\n"
129 " -l set the maximum number of lines that should be sent (default: unlimited)\n"
130 " -? print this message.\n"
137 /*********************************************************************
139 * Program to send email
141 int main (int argc, char *argv[])
144 struct sockaddr_in sin;
147 unsigned long maxlines, lines;
150 time_t now = time(NULL);
153 setlocale(LC_ALL, "en_US");
154 bindtextdomain("bacula", LOCALEDIR);
155 textdomain("bacula");
157 my_name_is(argc, argv, "bsmtp");
160 while ((ch = getopt(argc, argv, "c:d:f:h:r:s:l:?")) != -1) {
163 Dmsg1(20, "cc=%s\n", optarg);
167 case 'd': /* set debug level */
168 debug_level = atoi(optarg);
169 if (debug_level <= 0) {
172 Dmsg1(20, "Debug level = %d\n", debug_level);
179 case 'h': /* smtp host */
180 Dmsg1(20, "host=%s\n", optarg);
181 p = strchr(optarg, ':');
189 case 's': /* subject */
190 Dmsg1(20, "subject=%s\n", optarg);
194 case 'r': /* reply address */
199 Dmsg1(20, "maxlines=%s\n", optarg);
200 maxlines = (unsigned long) atol(optarg);
213 Pmsg0(0, _("Fatal error: no recipient given.\n"));
219 * Determine SMTP server
221 if (mailhost == NULL) {
222 if ((cp = getenv("SMTPSERVER")) != NULL) {
225 mailhost = "localhost";
230 * Find out my own host name for HELO;
231 * if possible, get the fully qualified domain name
233 if (gethostname(my_hostname, sizeof(my_hostname) - 1) < 0) {
234 Pmsg1(0, _("Fatal gethostname error: ERR=%s\n"), strerror(errno));
237 if ((hp = gethostbyname(my_hostname)) == NULL) {
238 Pmsg2(0, _("Fatal gethostbyname for myself failed \"%s\": ERR=%s\n"), my_hostname,
242 strcpy(my_hostname, hp->h_name);
243 Dmsg1(20, "My hostname is: %s\n", my_hostname);
246 * Determine from address.
248 if (from_addr == NULL) {
249 if ((pwd = getpwuid(getuid())) == 0) {
250 sprintf(buf, "userid-%d@%s", (int)getuid(), my_hostname);
252 sprintf(buf, "%s@%s", pwd->pw_name, my_hostname);
254 from_addr = bstrdup(buf);
256 Dmsg1(20, "From addr=%s\n", from_addr);
259 * Connect to smtp daemon on mailhost.
262 if ((hp = gethostbyname(mailhost)) == NULL) {
263 Pmsg2(0, _("Error unknown mail host \"%s\": ERR=%s\n"), mailhost,
265 if (strcasecmp(mailhost, "localhost") != 0) {
266 Pmsg0(0, _("Retrying connection using \"localhost\".\n"));
267 mailhost = "localhost";
273 if (hp->h_addrtype != AF_INET) {
274 Pmsg1(0, _("Fatal error: Unknown address family for smtp host: %d\n"), hp->h_addrtype);
277 memset((char *)&sin, 0, sizeof(sin));
278 memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
279 sin.sin_family = hp->h_addrtype;
280 sin.sin_port = htons(mailport);
281 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
282 Pmsg1(0, _("Fatal socket error: ERR=%s\n"), strerror(errno));
285 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
286 Pmsg2(0, _("Fatal connect error to %s: ERR=%s\n"), mailhost, strerror(errno));
289 Dmsg0(20, "Connected\n");
290 if ((r = dup(s)) < 0) {
291 Pmsg1(0, _("Fatal dup error: ERR=%s\n"), strerror(errno));
294 if ((sfp = fdopen(s, "w")) == 0) {
295 Pmsg1(0, _("Fatal fdopen error: ERR=%s\n"), strerror(errno));
298 if ((rfp = fdopen(r, "r")) == 0) {
299 Pmsg1(0, _("Fatal fdopen error: ERR=%s\n"), strerror(errno));
306 get_response(); /* banner */
307 chat("helo %s\r\n", my_hostname);
308 chat("mail from:<%s>\r\n", from_addr);
310 for (i = 0; i < argc; i++) {
311 Dmsg1(20, "rcpt to: %s\n", argv[i]);
312 chat("rcpt to:<%s>\r\n", argv[i]);
316 chat("rcpt to:<%s>\r\n", cc_addr);
322 * Send message header
324 fprintf(sfp, "From: %s\r\n", from_addr);
325 Dmsg1(10, "From: %s\r\n", from_addr);
327 fprintf(sfp, "Subject: %s\r\n", subject);
328 Dmsg1(10, "Subject: %s\r\n", subject);
331 fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
332 Dmsg1(10, "Reply-To: %s\r\n", reply_addr);
335 fprintf(sfp, "Errors-To: %s\r\n", err_addr);
336 Dmsg1(10, "Errors-To: %s\r\n", err_addr);
338 if ((pwd = getpwuid(getuid())) == 0) {
339 fprintf(sfp, "Sender: userid-%d@%s\r\n", (int)getuid(), my_hostname);
340 Dmsg2(10, "Sender: userid-%d@%s\r\n", (int)getuid(), my_hostname);
342 fprintf(sfp, "Sender: %s@%s\r\n", pwd->pw_name, my_hostname);
343 Dmsg2(10, "Sender: %s@%s\r\n", pwd->pw_name, my_hostname);
346 fprintf(sfp, "To: %s", argv[0]);
347 Dmsg1(10, "To: %s", argv[0]);
348 for (i = 1; i < argc; i++) {
349 fprintf(sfp, ",%s", argv[i]);
350 Dmsg1(10, ",%s", argv[i]);
353 fprintf(sfp, "\r\n");
356 fprintf(sfp, "Cc: %s\r\n", cc_addr);
357 Dmsg1(10, "Cc: %s\r\n", cc_addr);
360 /* Add RFC822 date */
361 localtime_r(&now, &tm);
362 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", &tm);
363 fprintf(sfp, "Date: %s\r\n", buf);
364 Dmsg1(10, "Date: %s\r\n", buf);
366 fprintf(sfp, "\r\n");
372 while (fgets(buf, sizeof(buf), stdin)) {
373 if (maxlines > 0 && ++lines > maxlines) {
374 Dmsg1(20, "skip line because of maxlines limit: %lu\n", maxlines);
377 buf[strlen(buf)-1] = 0;
378 if (strcmp(buf, ".") == 0) { /* quote lone dots */
379 fprintf(sfp, "..\r\n");
380 } else { /* pass body through unchanged */
381 fprintf(sfp, "%s\r\n", buf);
385 if (lines > maxlines) {
386 Dmsg1(10, "hit maxlines limit: %lu\n", maxlines);
387 fprintf(sfp, "\r\n[maximum of %lu lines exceeded, skipped %lu lines of output]\r\n", maxlines, lines-maxlines);
391 * Send SMTP quit command
397 * Go away gracefully ...