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