]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tools/bsmtp.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / tools / bsmtp.c
1 /*
2   Copyright (C) 2001-2006 Kern Sibbald
3
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.
8
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.
13
14  */
15 /*
16    Derived from a SMTPclient:
17
18        SMTPclient -- simple SMTP client
19
20        Copyright (C) 1997 Ralf S. Engelschall, All Rights Reserved.
21        rse@engelschall.com
22        www.engelschall.com
23
24    Kern Sibbald, July 2001
25
26    Version $Id$
27
28  */
29
30 #ifdef APCUPSD
31
32 #include "apc.h"
33 #undef main
34 #define my_name_is(x)
35 #define bstrdup(x) strdup(x)
36 UPSINFO myUPS;
37 UPSINFO *core_ups = &myUPS;
38 #define MY_NAME "smtp"
39
40 #else
41
42 #include "bacula.h"
43 #include "jcr.h"
44 #define MY_NAME "bsmtp"
45
46 #endif
47
48 /* Dummy functions */
49 int generate_daemon_event(JCR *jcr, const char *event) 
50    { return 1; }
51
52 #ifndef MAXSTRING
53 #define MAXSTRING 254
54 #endif
55
56 static FILE *sfp;
57 static FILE *rfp;
58
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];
67
68
69 /*
70  *  examine message from server
71  */
72 static void get_response(void)
73 {
74     char buf[MAXSTRING];
75
76     Dmsg0(50, "Calling fgets on read socket rfp.\n");
77     buf[3] = 0;
78     while (fgets(buf, sizeof(buf), rfp)) {
79         int len = strlen(buf);
80         if (len > 0) {
81            buf[len-1] = 0;
82         }
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);
86             exit(1);
87         }
88         if (buf[3] != '-') {
89             break;
90         }
91     }
92     return;
93 }
94
95 /*
96  *  say something to server and check the response
97  */
98 static void chat(const char *fmt, ...)
99 {
100     va_list ap;
101
102     va_start(ap, fmt);
103     vfprintf(sfp, fmt, ap);
104     if (debug_level >= 10) {
105        fprintf(stdout, "%s --> ", my_hostname);
106        vfprintf(stdout, fmt, ap);
107     }
108     va_end(ap);
109
110     fflush(sfp);
111     if (debug_level >= 10) {
112        fflush(stdout);
113     }
114     get_response();
115 }
116
117
118 static void usage()
119 {
120    fprintf(stderr,
121 _("\n"
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"
131 "\n"), MY_NAME);
132
133    exit(1);
134 }
135
136
137 /*********************************************************************
138  *
139  *  Program to send email
140  */
141 int main (int argc, char *argv[])
142 {
143     char buf[MAXSTRING];
144     struct sockaddr_in sin;
145     struct hostent *hp;
146     int s, r, i, ch;
147     unsigned long maxlines, lines;
148     struct passwd *pwd;
149     char *cp, *p;
150     time_t now = time(NULL);
151     struct tm tm;
152     
153    setlocale(LC_ALL, "en_US");
154    bindtextdomain("bacula", LOCALEDIR);
155    textdomain("bacula");
156
157    my_name_is(argc, argv, "bsmtp");
158    maxlines = 0;
159
160    while ((ch = getopt(argc, argv, "c:d:f:h:r:s:l:?")) != -1) {
161       switch (ch) {
162       case 'c':
163          Dmsg1(20, "cc=%s\n", optarg);
164          cc_addr = optarg;
165          break;
166
167       case 'd':                    /* set debug level */
168          debug_level = atoi(optarg);
169          if (debug_level <= 0) {
170             debug_level = 1;
171          }
172          Dmsg1(20, "Debug level = %d\n", debug_level);
173          break;
174
175       case 'f':                    /* from */
176          from_addr = optarg;
177          break;
178
179       case 'h':                    /* smtp host */
180          Dmsg1(20, "host=%s\n", optarg);
181          p = strchr(optarg, ':');
182          if (p) {
183             *p++ = 0;
184             mailport = atoi(p);
185          }
186          mailhost = optarg;
187          break;
188
189       case 's':                    /* subject */
190          Dmsg1(20, "subject=%s\n", optarg);
191          subject = optarg;
192          break;
193
194       case 'r':                    /* reply address */
195          reply_addr = optarg;
196          break;
197
198       case 'l':
199          Dmsg1(20, "maxlines=%s\n", optarg);
200          maxlines = (unsigned long) atol(optarg);
201          break;
202
203       case '?':
204       default:
205          usage();
206
207       }
208    }
209    argc -= optind;
210    argv += optind;
211
212    if (argc < 1) {
213       Pmsg0(0, _("Fatal error: no recipient given.\n"));
214       usage();
215       exit(1);
216    }
217
218    /*
219     *  Determine SMTP server
220     */
221    if (mailhost == NULL) {
222       if ((cp = getenv("SMTPSERVER")) != NULL) {
223          mailhost = cp;
224       } else {
225          mailhost = "localhost";
226       }
227    }
228
229    /*
230     *  Find out my own host name for HELO;
231     *  if possible, get the fully qualified domain name
232     */
233    if (gethostname(my_hostname, sizeof(my_hostname) - 1) < 0) {
234       Pmsg1(0, _("Fatal gethostname error: ERR=%s\n"), strerror(errno));
235       exit(1);
236    }
237    if ((hp = gethostbyname(my_hostname)) == NULL) {
238       Pmsg2(0, _("Fatal gethostbyname for myself failed \"%s\": ERR=%s\n"), my_hostname,
239          strerror(errno));
240       exit(1);
241    }
242    strcpy(my_hostname, hp->h_name);
243    Dmsg1(20, "My hostname is: %s\n", my_hostname);
244
245    /*
246     *  Determine from address.
247     */
248    if (from_addr == NULL) {
249       if ((pwd = getpwuid(getuid())) == 0) {
250          sprintf(buf, "userid-%d@%s", (int)getuid(), my_hostname);
251       } else {
252          sprintf(buf, "%s@%s", pwd->pw_name, my_hostname);
253       }
254       from_addr = bstrdup(buf);
255    }
256    Dmsg1(20, "From addr=%s\n", from_addr);
257
258    /*
259     *  Connect to smtp daemon on mailhost.
260     */
261 hp:
262    if ((hp = gethostbyname(mailhost)) == NULL) {
263       Pmsg2(0, _("Error unknown mail host \"%s\": ERR=%s\n"), mailhost,
264          strerror(errno));
265       if (strcasecmp(mailhost, "localhost") != 0) {
266          Pmsg0(0, _("Retrying connection using \"localhost\".\n"));
267          mailhost = "localhost";
268          goto hp;
269       }
270       exit(1);
271    }
272
273    if (hp->h_addrtype != AF_INET) {
274       Pmsg1(0, _("Fatal error: Unknown address family for smtp host: %d\n"), hp->h_addrtype);
275       exit(1);
276    }
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));
283       exit(1);
284    }
285    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
286       Pmsg2(0, _("Fatal connect error to %s: ERR=%s\n"), mailhost, strerror(errno));
287       exit(1);
288    }
289    Dmsg0(20, "Connected\n");
290    if ((r = dup(s)) < 0) {
291       Pmsg1(0, _("Fatal dup error: ERR=%s\n"), strerror(errno));
292       exit(1);
293    }
294    if ((sfp = fdopen(s, "w")) == 0) {
295       Pmsg1(0, _("Fatal fdopen error: ERR=%s\n"), strerror(errno));
296       exit(1);
297    }
298    if ((rfp = fdopen(r, "r")) == 0) {
299       Pmsg1(0, _("Fatal fdopen error: ERR=%s\n"), strerror(errno));
300       exit(1);
301    }
302
303    /*
304     *  Send SMTP headers
305     */
306    get_response(); /* banner */
307    chat("helo %s\r\n", my_hostname);
308    chat("mail from:<%s>\r\n", from_addr);
309
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]);
313    }
314
315    if (cc_addr) {
316       chat("rcpt to:<%s>\r\n", cc_addr);
317    }
318    Dmsg0(20, "Data\n");
319    chat("data\r\n");
320
321    /*
322     *  Send message header
323     */
324    fprintf(sfp, "From: %s\r\n", from_addr);
325    Dmsg1(10, "From: %s\r\n", from_addr);
326    if (subject) {
327       fprintf(sfp, "Subject: %s\r\n", subject);
328       Dmsg1(10, "Subject: %s\r\n", subject);
329    }
330    if (reply_addr) {
331       fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
332       Dmsg1(10, "Reply-To: %s\r\n", reply_addr);
333    }
334    if (err_addr) {
335       fprintf(sfp, "Errors-To: %s\r\n", err_addr);
336       Dmsg1(10, "Errors-To: %s\r\n", err_addr);
337    }
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);
341    } else {
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);
344    }
345
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]);
351    }
352
353    fprintf(sfp, "\r\n");
354    Dmsg0(10, "\r\n");
355    if (cc_addr) {
356       fprintf(sfp, "Cc: %s\r\n", cc_addr);
357       Dmsg1(10, "Cc: %s\r\n", cc_addr);
358    }
359
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);
365
366    fprintf(sfp, "\r\n");
367
368    /*
369     *  Send message body
370     */
371    lines = 0;
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);
375          continue;
376       }
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);
382       }
383    }
384
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);
388    }
389
390    /*
391     *  Send SMTP quit command
392     */
393    chat(".\r\n");
394    chat("quit\r\n");
395
396    /*
397     *  Go away gracefully ...
398     */
399    exit(0);
400 }