1 /*
2 * smtp.c
3 * this file contains the communucation with the server
4 */
5
6 /*
7 * This file is part of smtpmail.
8 *
9 * smtpmail is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * Foobar is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Foobar; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24
25 #include <netdb.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <netinet/in.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #include <errno.h>
37 #include "types.h"
38
39 extern int encode64 (const char *_in, unsigned inlen,
40 char *_out, unsigned outmax, unsigned *outlen);
41 /*
42 * this function is taken from hostname 2.10
43 * writen by Peter Tobias tobias@et-inf.fho-emden.de
44 */
45 char *
localhost(void)46 localhost (void)
47 {
48 struct hostent *hs;
49 static char *buf = 0;
50 static size_t buf_len = 0;
51 int myerror = 0;
52 if (! buf)
53 {
54 do {
55 errno = 0;
56
57 if (buf) {
58 buf_len += buf_len;
59 buf = realloc (buf, buf_len);
60 } else {
61 buf_len = 128; /* Initial guess */
62 buf = malloc (buf_len);
63 }
64
65 if (! buf)
66 {
67 errno = ENOMEM;
68 return 0;
69 }
70 } while (((myerror = gethostname(buf, buf_len)) == 0 && !memchr (buf, '\0', buf_len))
71 || errno == ENAMETOOLONG);
72
73 if (myerror)
74 /* gethostname failed, abort. */
75 {
76 free (buf);
77 buf = 0;
78 }
79 }
80 hs = gethostbyname(buf);
81 return hs->h_name;
82 }
83
84 int
get_host(char ** name)85 get_host (char **name)
86 {
87 struct hostent *he;
88 char str[16];
89 char **ret;
90 struct in_addr in;
91 he = gethostbyname (*name);
92 if (he == NULL)
93 {
94 fprintf (stderr, "gethostbyname: %s\n", *name);
95 return 1;
96 }
97 ret = he->h_addr_list;
98 memcpy (&in.s_addr, *ret, sizeof (in.s_addr));
99 *name = (char *) realloc (*name, sizeof (str));
100 sprintf (*name, inet_ntoa (in));
101 return 0;
102 }
103
104 int
mod_buf(char * in,int len)105 mod_buf (char *in, int len)
106 {
107 int i;
108 int outlen;
109 outlen = strlen (in) - len;
110 if (outlen < 0)
111 return 1;
112 for (i = 0; i < outlen; i++)
113 {
114 in[i] = in[len + i];
115 }
116 in[i + 1] = '\0';
117 return 0;
118 }
119
120 int
send_wait(int fd,char * send,const char * search,mail_opt * opts)121 send_wait (int fd, char *send, const char *search, mail_opt *opts)
122 {
123 char buff[256];
124 int n;
125 size_t nbytes;
126 int ok = 1;
127 if (send)
128 { /* send the data */
129 if(opts != NULL && opts->verbose > 1)
130 fprintf(stderr, send);
131 while ((nbytes = write (fd, send, strlen (send))) < strlen (send))
132 {
133 if(opts != NULL && opts->verbose > 2)
134 fprintf(stderr, "%s\n\n", send);
135 mod_buf (send, nbytes);
136 }
137 }
138 if (search)
139 {
140 if(opts != NULL && opts->verbose > 1)
141 fprintf(stderr, "search\n");
142 n = read (fd, buff, 255);
143 buff[n] = '\0';
144 if(opts != NULL && opts->verbose > 1)
145 fprintf(stderr, buff);
146 if (strncmp (buff, search, strlen (search)) == 0)
147 ok = 0;
148 }
149 else
150 {
151 ok = 0;
152 }
153 if(opts != NULL && opts->verbose > 1)
154 fprintf(stderr, "send return\n");
155 return ok;
156 }
157
158 char *
extract_addr(char * orig)159 extract_addr(char *orig)
160 {
161 char *ret;
162 int i;
163
164 if((ret = index(orig, '<')) == NULL)
165 return orig;
166 ret++;
167 for(i = 0; i < strlen(ret); i++)
168 {
169 if(ret[i] == '>')
170 {
171 ret[i] = '\0';
172 break;
173 }
174 }
175 return ret;
176 }
177
178 int
send_mail(mail_opt * opts)179 send_mail (mail_opt * opts)
180 {
181 int sock;
182 struct sockaddr_in srv_addr;
183 char buff[1024];
184 int i;
185 unsigned foo;
186 /* get the ip of the mailhost */
187 get_host (&(opts->host));
188 /* connect and search for 220 */
189 sock = socket (AF_INET, SOCK_STREAM, 0);
190 bzero (&srv_addr, sizeof (srv_addr));
191 srv_addr.sin_family = AF_INET;
192 srv_addr.sin_port = htons (25);
193 inet_pton (AF_INET, opts->host, &srv_addr.sin_addr);
194 if (connect (sock, (struct sockaddr *) &srv_addr, sizeof (srv_addr)) < 0)
195 {
196 fprintf (stderr, "connect failure\n");
197 _exit (1);
198 }
199 if (send_wait (sock, NULL, "220", opts))
200 _exit (1);
201 sprintf(buff, "HELO %s\r\n", localhost());
202 if(send_wait (sock, buff, "250", opts))
203 {
204 fprintf(stderr, "HELO failed\n");
205 _exit(1);
206 }
207 if (opts->pass)
208 {
209 if (send_wait (sock, "auth login\r\n", "334", opts))
210 _exit (1);
211 encode64 (opts->user, strlen (opts->user), buff, 255, &foo);
212 sprintf (buff, "%s\r\n", buff);
213 if (send_wait (sock, buff, "334", opts))
214 _exit (1);
215 encode64 (opts->pass, strlen (opts->pass), buff, 255, &foo);
216 sprintf (buff, "%s\r\n", buff);
217 if (send_wait (sock, buff, "235", opts))
218 _exit (1);
219 }
220 /* MAIL FROM: and search for 250 */
221 sprintf (buff, "mail from: %s\r\n", extract_addr(opts->sender));
222 if (send_wait (sock, buff, "250", opts))
223 {
224 fprintf (stderr, "mail from failed\n");
225 _exit (1);
226 }
227 /*
228 * RCPT TO: and search for 250
229 * do this for every rcpt, cc and bcc
230 */
231 for (i = 0; i < opts->rcpt_count; i++)
232 {
233 sprintf (buff, "rcpt to: %s\r\n", extract_addr(opts->rcpt_addr[i]));
234 if (send_wait (sock, buff, "250", opts))
235 {
236 fprintf (stderr, "%s failed\n", buff);
237 _exit (1);
238 }
239 }
240 for (i = 0; i < opts->cc_count; i++)
241 {
242 sprintf (buff, "rcpt to: %s\r\n", extract_addr(opts->cc_addr[i]));
243 if (send_wait (sock, buff, "250", opts))
244 {
245 fprintf (stderr, "%s failed\n", buff);
246 _exit (1);
247 }
248 }
249 for (i = 0; i < opts->bcc_count; i++)
250 {
251 sprintf (buff, "rcpt to: %s\r\n", extract_addr(opts->bcc_addr[i]));
252 if (send_wait (sock, buff, "250", opts))
253 {
254 fprintf (stderr, "%s failed\n", buff);
255 _exit (1);
256 }
257 }
258 /* DATA and search for 354 */
259 if (send_wait (sock, "data\r\n", "354", opts))
260 _exit (1);
261 /* send the mail */
262 if (send_wait (sock, opts->msg, NULL, opts))
263 _exit (1);
264 /* end the mail with '.' andsearch for 250 */
265 if (send_wait (sock, "\r\n.\r\n", "250", opts))
266 _exit (1);
267 /* QUIT */
268 //send_wait (sock, "quit\r\n", NULL);
269 write(sock, "quit\r\n", strlen("quit\r\n"));
270 //close (sock);
271 return 0;
272 }
273