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