1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
15  *
16  *  Copyright (C) 2006-2016 XNeur Team
17  *
18  */
19 
20 #include <string.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <netdb.h>
31 
32 #include "log.h"
33 
34 #define CMDCOUNT 6
35 char *mail[CMDCOUNT] = {	"EHLO xneur.ru\n",
36 							"MAIL FROM:xneurlog@xneur.ru\n",
37 				      		"RCPT TO:",
38 							"DATA\n",
39 							".\n",
40 		  				    "QUIT\n"	};
41 
42 #define FROM 		"From: <xneurlog@xneur.ru>\n"
43 #define SUBJ 		"Subject: Log Archive\n"
44 #define MIME 		"MIME-Version: 1.0\n"
45 #define CONT_MIX 	"Content-Type: multipart/mixed; boundary=\"----------D675117161112F6\"\n\n"
46 #define BOUN 		"------------D675117161112F6\n"
47 #define BOUN_END	"------------D675117161112F6--\n\n"
48 #define CONT_TXT 	"Content-Type: text/plain; charset=utf-8\n\n"
49 #define TEXT		"Xneur log in attachment\n\n"
50 #define CONT_APP 	"Content-Type: application/x-gzip; name=\"%s\"\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=\"%s\"\n\n"
51 
52 #define DEFAULT_BUFLEN 1024
53 
encodeblock(unsigned char in[3],unsigned char out[4],int len)54 void encodeblock(unsigned char in[3], unsigned char out[4], int len)
55 {
56 	const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
57 
58     out[0] = cb64[ in[0] >> 2 ];
59     out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
60     out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
61     out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
62 }
63 
encode_base64(FILE * infile,char * base64text)64 void encode_base64(FILE *infile, char *base64text)
65 {
66 	int linesize = 72;
67 
68 	unsigned char in[3], out[4];
69 	int i, j = 0, len, blocksout = 0;
70 
71 	while (!feof(infile))
72 	{
73 		len = 0;
74 
75 		for (i = 0; i < 3; i++)
76 		{
77 			in[i] = (unsigned char) getc(infile);
78 			if (!feof(infile))
79                 len++;
80 			else
81                 in[i] = 0;
82 		}
83 		if (len)
84 		{
85 			encodeblock(in, out, len);
86 			for (i = 0; i < 4; i++)
87 				base64text[j++] = out[i];
88 			blocksout++;
89 		}
90 		if (blocksout >= (linesize/4) || feof(infile))
91 		{
92 			if (blocksout)
93 				base64text[j++] = '\n';
94 			blocksout = 0;
95 		}
96 	}
97 }
98 
send_packet(int s,const void * msg,size_t len,int flags)99 static void send_packet(int s, const void *msg, size_t len, int flags)
100 {
101 	ssize_t count = send(s, msg, len, flags);
102 	if (count == -1)
103 		log_message (ERROR, _("Lost the package when sending mail."));
104 }
105 
send_mail_with_attach(char * file,char host[],int port,char rcpt[])106 void send_mail_with_attach(char *file, char host[], int port, char rcpt[])
107 {
108 	if (host == NULL)
109 		return;
110 	if (rcpt == NULL)
111 		return;
112 	if (file == NULL)
113 		return;
114 
115 	int fd, i;
116 
117 	struct sockaddr_in sock;
118 	struct hostent *hp;
119 
120 	sock.sin_family = AF_INET;
121 	//sock.sin_addr.s_addr = inet_addr(host);
122 	if (inet_aton(host, &sock.sin_addr) != 1)
123 	{
124 		hp = gethostbyname(host);
125 		if (!hp)
126 		{
127 			log_message(ERROR, _("Unknown host %s\n"), host);
128 			return;
129 		}
130 		memcpy(&sock.sin_addr, hp->h_addr, 4);
131 	}
132 	sock.sin_port = htons(port);
133 	memset(&sock.sin_zero, '\0', 8);
134 
135 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
136 	{
137 		log_message(ERROR, _("Unable open socket!"));
138 		return;
139 	}
140 
141 	if (connect(fd, (struct sockaddr *)&sock, sizeof(struct sockaddr)) == -1)
142 	{
143 		close(fd);
144 		log_message(ERROR, _("Unable to connect to %s"), (char *)inet_ntoa(sock.sin_addr));
145 		return;
146 	}
147 
148 	FILE *stream = fopen(file, "rb");
149 	if (stream == NULL)
150 	{
151 		log_message (ERROR, _("Can't open to read file \"%s\""), file);
152 		close(fd);
153 		return;
154 	}
155 
156 	struct stat sb;
157 	if (stat(file, &sb) != 0)
158 	{
159 		close(fd);
160 		fclose(stream);
161 		log_message (ERROR, _("Can't get state of file \"%s\""), file);
162 		return;
163 	}
164 
165 	if (sb.st_size < 0)
166 	{
167 		close(fd);
168 		fclose(stream);
169 		log_message (ERROR, _("Can't get state of file \"%s\""), file);
170 		return;
171 	}
172 
173 	do {
174 		file = strstr(file, "/");
175 		if (file == NULL)
176 		{
177 			close(fd);
178 			fclose(stream);
179 			return;
180 		}
181 		file++;
182 	} while (strstr(file, "/") != NULL);
183 
184 	for (i = 0; i < CMDCOUNT; i++)
185 	{
186 		send_packet(fd, mail[i], strlen(mail[i]), 0);
187 		if (i == 2)
188 		{
189 			send_packet(fd, rcpt, strlen(rcpt), 0);
190 			send_packet(fd, "\n", sizeof(char), 0);
191 		}
192 		if (i == 3)
193 		{
194 			send_packet(fd, FROM, strlen(FROM), 0);
195 			send_packet(fd, "To: ", 4, 0);
196 			send_packet(fd, rcpt, strlen(rcpt), 0);
197 			send_packet(fd, "\n", sizeof(char), 0);
198 			send_packet(fd, SUBJ, strlen(SUBJ), 0);
199 			send_packet(fd, MIME, strlen(MIME), 0);
200 			send_packet(fd, CONT_MIX, strlen(CONT_MIX), 0);
201 			send_packet(fd, BOUN, strlen(BOUN), 0);
202 			send_packet(fd, CONT_TXT, strlen(CONT_TXT), 0);
203 			send_packet(fd, TEXT, strlen(TEXT), 0);
204 			send_packet(fd, BOUN, strlen(BOUN), 0);
205 			char *cont_app = malloc((strlen(CONT_APP)+ 2*strlen(file) + 5) * sizeof(char));
206 			sprintf (cont_app, CONT_APP, file, file);
207 			send_packet(fd, cont_app, strlen(cont_app), 0);
208 			free(cont_app);
209 			char *base64text = malloc((sb.st_size*2) * sizeof(char));
210 			encode_base64(stream, base64text);
211 			send_packet(fd, base64text, strlen(base64text), 0);
212 			free(base64text);
213 
214 			send_packet(fd, BOUN_END, strlen(BOUN_END), 0);
215 		}
216 	}
217 
218 	sleep(5);
219 	char recvbuf[DEFAULT_BUFLEN];
220     int recvbuflen = DEFAULT_BUFLEN;
221 	int result = 0;
222 	do {
223 		result = recv(fd, recvbuf, recvbuflen, 0);
224 		if (result < 0)
225 		{
226 			close(fd);
227 			fclose(stream);
228 			log_message (ERROR, _("Mail server return Error %d"), result);
229 			return;
230 		}
231 		recvbuf[result] = '\0';
232 		/*if ( result > 0 )
233 			log_message (DEBUG, "Mail server return answer:\n%s\n", recvbuf, result);
234 		else if ( result == 0 )
235 			log_message (ERROR, "Connection closed");
236 		else
237 			log_message (ERROR, "Connection Error %d", result);*/
238 	} while( result > 0 );
239 
240 	close(fd);
241 	fclose(stream);
242 }
243