]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tools/bsmtp.c
- Move test for MaxStartDelay as suggested by Peter.
[bacula/bacula] / bacula / src / tools / bsmtp.c
1 /*
2    Copyright (C) 2000-2004 Kern Sibbald and John Walker
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 as
6    published by the Free Software Foundation; either version 2 of
7    the License, or (at your option) any later version.
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 GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public
15    License along with this program; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17    MA 02111-1307, USA.
18
19  */
20
21 /*
22    Derived from a SMTPclient:
23
24        SMTPclient -- simple SMTP client
25
26        Copyright (C) 1997 Ralf S. Engelschall, All Rights Reserved.
27        rse@engelschall.com
28        www.engelschall.com
29
30    Kern Sibbald, July 2001
31
32    Version $Id$
33
34  */
35
36 #ifdef APCUPSD
37
38 #include "apc.h"
39 #undef main
40 #define my_name_is(x)
41 #define bstrdup(x) strdup(x)
42 UPSINFO myUPS;
43 UPSINFO *core_ups = &myUPS;
44 #define MY_NAME "smtp"
45
46 #else
47
48 #include "bacula.h"
49 #include "jcr.h"
50 #define MY_NAME "bsmtp"
51
52 #endif
53
54 /* Dummy functions */
55 int generate_daemon_event(JCR *jcr, const char *event) 
56    { return 1; }
57
58 #ifndef MAXSTRING
59 #define MAXSTRING 254
60 #endif
61
62 static FILE *sfp;
63 static FILE *rfp;
64
65 static char *from_addr = NULL;
66 static char *cc_addr = NULL;
67 static char *subject = NULL;
68 static char *err_addr = NULL;
69 static const char *mailhost = NULL;
70 static char *reply_addr = NULL;
71 static int mailport = 25;
72 static char my_hostname[MAXSTRING];
73
74
75 /*
76  *  examine message from server
77  */
78 static void get_response(void)
79 {
80     char buf[MAXSTRING];
81
82     Dmsg0(50, "Calling fgets on read socket rfp.\n");
83     buf[3] = 0;
84     while (fgets(buf, sizeof(buf), rfp)) {
85         int len = strlen(buf);
86         if (len > 0) {
87            buf[len-1] = 0;
88         }
89         Dmsg2(10, "%s --> %s\n", mailhost, buf);
90         if (!isdigit((int)buf[0]) || buf[0] > '3') {
91             Pmsg2(0, "Fatal malformed reply from %s: %s\n", mailhost, buf);
92             exit(1);
93         }
94         if (buf[3] != '-') {
95             break;
96         }
97     }
98     return;
99 }
100
101 /*
102  *  say something to server and check the response
103  */
104 static void chat(const char *fmt, ...)
105 {
106     va_list ap;
107
108     va_start(ap, fmt);
109     vfprintf(sfp, fmt, ap);
110     if (debug_level >= 10) {
111        fprintf(stdout, "%s --> ", my_hostname);
112        vfprintf(stdout, fmt, ap);
113     }
114     va_end(ap);
115
116     fflush(sfp);
117     if (debug_level >= 10) {
118        fflush(stdout);
119     }
120     get_response();
121 }
122
123
124 static void usage()
125 {
126    fprintf(stderr,
127 "\n"
128 "Usage: %s [-f from] [-h mailhost] [-s subject] [-c copy] [recipient ...]\n"
129 "       -c          set the Cc: field\n"
130 "       -dnn        set debug level to nn\n"
131 "       -f          set the From: field\n"
132 "       -h          use mailhost:port as the SMTP server\n"
133 "       -s          set the Subject: field\n"
134 "       -?          print this message.\n"
135 "\n", MY_NAME);
136
137    exit(1);
138 }
139
140
141 /*********************************************************************
142  *
143  *  Program to send email
144  */
145 int main (int argc, char *argv[])
146 {
147     char buf[MAXSTRING];
148     struct sockaddr_in sin;
149     struct hostent *hp;
150     int s, r, i, ch;
151     struct passwd *pwd;
152     char *cp, *p;
153     time_t now = time(NULL);
154     struct tm tm;
155
156    my_name_is(argc, argv, "bsmtp");
157
158    while ((ch = getopt(argc, argv, "c:d:f:h:r:s:?")) != -1) {
159       switch (ch) {
160       case 'c':
161          Dmsg1(20, "cc=%s\n", optarg);
162          cc_addr = optarg;
163          break;
164
165       case 'd':                    /* set debug level */
166          debug_level = atoi(optarg);
167          if (debug_level <= 0) {
168             debug_level = 1;
169          }
170          Dmsg1(20, "Debug level = %d\n", debug_level);
171          break;
172
173       case 'f':                    /* from */
174          from_addr = optarg;
175          break;
176
177       case 'h':                    /* smtp host */
178          Dmsg1(20, "host=%s\n", optarg);
179          p = strchr(optarg, ':');
180          if (p) {
181             *p++ = 0;
182             mailport = atoi(p);
183          }
184          mailhost = optarg;
185          break;
186
187       case 's':                    /* subject */
188          Dmsg1(20, "subject=%s\n", optarg);
189          subject = optarg;
190          break;
191
192       case 'r':                    /* reply address */
193          reply_addr = optarg;
194          break;
195
196       case '?':
197       default:
198          usage();
199
200       }
201    }
202    argc -= optind;
203    argv += optind;
204
205    if (argc < 1) {
206       Pmsg0(0, "Fatal error: no recipient given.\n");
207       usage();
208       exit(1);
209    }
210
211    /*
212     *  Determine SMTP server
213     */
214    if (mailhost == NULL) {
215       if ((cp = getenv("SMTPSERVER")) != NULL) {
216          mailhost = cp;
217       } else {
218          mailhost = "localhost";
219       }
220    }
221
222    /*
223     *  Find out my own host name for HELO;
224     *  if possible, get the fully qualified domain name
225     */
226    if (gethostname(my_hostname, sizeof(my_hostname) - 1) < 0) {
227       Pmsg1(0, "Fatal gethostname error: ERR=%s\n", strerror(errno));
228       exit(1);
229    }
230    if ((hp = gethostbyname(my_hostname)) == NULL) {
231       Pmsg2(0, "Fatal gethostbyname for myself failed \"%s\": ERR=%s\n", my_hostname,
232          strerror(errno));
233       exit(1);
234    }
235    strcpy(my_hostname, hp->h_name);
236    Dmsg1(20, "My hostname is: %s\n", my_hostname);
237
238    /*
239     *  Determine from address.
240     */
241    if (from_addr == NULL) {
242       if ((pwd = getpwuid(getuid())) == 0) {
243          sprintf(buf, "userid-%d@%s", (int)getuid(), my_hostname);
244       } else {
245          sprintf(buf, "%s@%s", pwd->pw_name, my_hostname);
246       }
247       from_addr = bstrdup(buf);
248    }
249    Dmsg1(20, "From addr=%s\n", from_addr);
250
251    /*
252     *  Connect to smtp daemon on mailhost.
253     */
254 hp:
255    if ((hp = gethostbyname(mailhost)) == NULL) {
256       Pmsg2(0, "Error unknown mail host \"%s\": ERR=%s\n", mailhost,
257          strerror(errno));
258       if (strcasecmp(mailhost, "localhost") != 0) {
259          Pmsg0(0, "Retrying connection using \"localhost\".\n");
260          mailhost = "localhost";
261          goto hp;
262       }
263       exit(1);
264    }
265
266    if (hp->h_addrtype != AF_INET) {
267       Pmsg1(0, "Fatal error: Unknown address family for smtp host: %d\n", hp->h_addrtype);
268       exit(1);
269    }
270    memset((char *)&sin, 0, sizeof(sin));
271    memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
272    sin.sin_family = hp->h_addrtype;
273    sin.sin_port = htons(mailport);
274    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
275       Pmsg1(0, "Fatal socket error: ERR=%s\n", strerror(errno));
276       exit(1);
277    }
278    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
279       Pmsg2(0, "Fatal connect error to %s: ERR=%s\n", mailhost, strerror(errno));
280       exit(1);
281    }
282    Dmsg0(20, "Connected\n");
283    if ((r = dup(s)) < 0) {
284       Pmsg1(0, "Fatal dup error: ERR=%s\n", strerror(errno));
285       exit(1);
286    }
287    if ((sfp = fdopen(s, "w")) == 0) {
288       Pmsg1(0, "Fatal fdopen error: ERR=%s\n", strerror(errno));
289       exit(1);
290    }
291    if ((rfp = fdopen(r, "r")) == 0) {
292       Pmsg1(0, "Fatal fdopen error: ERR=%s\n", strerror(errno));
293       exit(1);
294    }
295
296    /*
297     *  Send SMTP headers
298     */
299    get_response(); /* banner */
300    chat("helo %s\r\n", my_hostname);
301    chat("mail from:<%s>\r\n", from_addr);
302
303    for (i = 0; i < argc; i++) {
304       Dmsg1(20, "rcpt to: %s\n", argv[i]);
305       chat("rcpt to:<%s>\r\n", argv[i]);
306    }
307
308    if (cc_addr) {
309       chat("rcpt to:<%s>\r\n", cc_addr);
310    }
311    Dmsg0(20, "Data\n");
312    chat("data\r\n");
313
314    /*
315     *  Send message header
316     */
317    fprintf(sfp, "From: %s\r\n", from_addr);
318    if (subject) {
319       fprintf(sfp, "Subject: %s\r\n", subject);
320    }
321    if (reply_addr) {
322       fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
323    }
324    if (err_addr) {
325       fprintf(sfp, "Errors-To: %s\r\n", err_addr);
326    }
327    if ((pwd = getpwuid(getuid())) == 0) {
328       fprintf(sfp, "Sender: userid-%d@%s\r\n", (int)getuid(), my_hostname);
329    } else {
330       fprintf(sfp, "Sender: %s@%s\r\n", pwd->pw_name, my_hostname);
331    }
332
333    fprintf(sfp, "To: %s", argv[0]);
334    for (i = 1; i < argc; i++) {
335       fprintf(sfp, ",%s", argv[i]);
336    }
337
338    fprintf(sfp, "\r\n");
339    if (cc_addr) {
340       fprintf(sfp, "Cc: %s\r\n", cc_addr);
341    }
342
343    /* Add RFC822 date */
344    localtime_r(&now, &tm);
345    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", &tm);
346    fprintf(sfp, "Date: %s\r\n", buf);
347
348    fprintf(sfp, "\r\n");
349
350    /*
351     *  Send message body
352     */
353    while (fgets(buf, sizeof(buf), stdin)) {
354       buf[strlen(buf)-1] = 0;
355       if (strcmp(buf, ".") == 0) { /* quote lone dots */
356          fprintf(sfp, "..\r\n");
357       } else {                     /* pass body through unchanged */
358          fprintf(sfp, "%s\r\n", buf);
359       }
360    }
361
362    /*
363     *  Send SMTP quit command
364     */
365    chat(".\r\n");
366    chat("quit\r\n");
367
368    /*
369     *  Go away gracefully ...
370     */
371    exit(0);
372 }