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