1 /*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * $Id: mailstream_low.c,v 1.27 2011/05/04 16:09:54 hoa Exp $
34 */
35
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39
40 #include "mailstream_low.h"
41 #include <stdlib.h>
42
43 #ifdef LIBETPAN_MAILSTREAM_DEBUG
44
45 #define STREAM_DEBUG
46
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <string.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54 #include "maillock.h"
55 #ifdef WIN32
56 # include "win_etpan.h"
57 #endif
58 #if defined(ANDROID) || defined(__ANDROID__)
59 #include <sys/select.h>
60 #endif
61
62 #if USE_POLL && defined(HAVE_SYS_POLL_H)
63 #include <sys/poll.h>
64 #endif
65
66 #include "mailstream_cfstream.h"
67 #include "mailstream_compress.h"
68 #include "mailstream_cancel.h"
69
70 #define LOG_FILE "libetpan-stream-debug.log"
71
72 LIBETPAN_EXPORT
73 int mailstream_debug = 0;
74
75 LIBETPAN_EXPORT
76 void (* mailstream_logger)(int direction,
77 const char * str, size_t size) = NULL;
78 LIBETPAN_EXPORT
79 void (* mailstream_logger_id)(mailstream_low * s, int is_stream_data, int direction,
80 const char * str, size_t size) = NULL;
81
82 static inline void mailstream_logger_internal(mailstream_low * s, int is_stream_data, int direction,
83 const char * buffer, size_t size);
84
85 // Will log a buffer.
86 #define STREAM_LOG_ERROR(low, direction, buf, size) \
87 mailstream_logger_internal(low, 2, direction, buf, size); \
88 if (mailstream_debug) { \
89 if (mailstream_logger_id != NULL) { \
90 mailstream_logger_id(low, 2, direction, buf, size); \
91 } \
92 else if (mailstream_logger != NULL) { \
93 mailstream_logger(direction, buf, size); \
94 } \
95 else { \
96 FILE * f; \
97 mode_t old_mask; \
98 \
99 old_mask = umask(0077); \
100 f = fopen(LOG_FILE, "a"); \
101 umask(old_mask); \
102 if (f != NULL) { \
103 maillock_write_lock(LOG_FILE, fileno(f)); \
104 fwrite((buf), 1, (size), f); \
105 maillock_write_unlock(LOG_FILE, fileno(f)); \
106 fclose(f); \
107 } \
108 } \
109 }
110
111 // Will log a buffer.
112 #define STREAM_LOG_BUF(low, direction, buf, size) \
113 mailstream_logger_internal(low, 1, direction, buf, size); \
114 if (mailstream_debug) { \
115 if (mailstream_logger_id != NULL) { \
116 mailstream_logger_id(low, 1, direction, buf, size); \
117 } \
118 else if (mailstream_logger != NULL) { \
119 mailstream_logger(direction, buf, size); \
120 } \
121 else { \
122 FILE * f; \
123 mode_t old_mask; \
124 \
125 old_mask = umask(0077); \
126 f = fopen(LOG_FILE, "a"); \
127 umask(old_mask); \
128 if (f != NULL) { \
129 maillock_write_lock(LOG_FILE, fileno(f)); \
130 fwrite((buf), 1, (size), f); \
131 maillock_write_unlock(LOG_FILE, fileno(f)); \
132 fclose(f); \
133 } \
134 } \
135 }
136
137 // Will log some log text string.
138 #define STREAM_LOG(low, direction, str) \
139 mailstream_logger_internal(low, 0, direction, str, strlen(str)); \
140 if (mailstream_debug) { \
141 if (mailstream_logger_id != NULL) { \
142 mailstream_logger_id(low, 0, direction, str, strlen(str)); \
143 } \
144 else if (mailstream_logger != NULL) { \
145 mailstream_logger(direction, str, strlen(str)); \
146 } \
147 else { \
148 FILE * f; \
149 mode_t old_mask; \
150 \
151 old_mask = umask(0077); \
152 f = fopen(LOG_FILE, "a"); \
153 umask(old_mask); \
154 if (f != NULL) { \
155 maillock_write_lock(LOG_FILE, fileno(f)); \
156 fputs((str), f); \
157 maillock_write_unlock(LOG_FILE, fileno(f)); \
158 fclose(f); \
159 } \
160 } \
161 }
162
163 #else
164
165 #define STREAM_LOG_ERROR(low, direction, buf, size) do { } while (0)
166 #define STREAM_LOG_BUF(low, direction, buf, size) do { } while (0)
167 #define STREAM_LOG(low, direction, buf) do { } while (0)
168
169 #endif
170
171
172 /* general functions */
173
mailstream_low_new(void * data,mailstream_low_driver * driver)174 mailstream_low * mailstream_low_new(void * data,
175 mailstream_low_driver * driver)
176 {
177 mailstream_low * s;
178
179 s = malloc(sizeof(* s));
180 if (s == NULL)
181 return NULL;
182
183 s->data = data;
184 s->driver = driver;
185 s->privacy = 1;
186 s->identifier = NULL;
187 s->timeout = 0;
188 s->logger = NULL;
189 s->logger_context = NULL;
190
191 return s;
192 }
193
mailstream_low_close(mailstream_low * s)194 int mailstream_low_close(mailstream_low * s)
195 {
196 if (s == NULL)
197 return -1;
198 s->driver->mailstream_close(s);
199
200 return 0;
201 }
202
mailstream_low_get_fd(mailstream_low * s)203 int mailstream_low_get_fd(mailstream_low * s)
204 {
205 if (s == NULL)
206 return -1;
207 return s->driver->mailstream_get_fd(s);
208 }
209
mailstream_low_get_cancel(mailstream_low * s)210 struct mailstream_cancel * mailstream_low_get_cancel(mailstream_low * s)
211 {
212 if (s == NULL)
213 return NULL;
214 if (s->driver->mailstream_get_cancel == NULL)
215 return NULL;
216 return s->driver->mailstream_get_cancel(s);
217 }
218
mailstream_low_free(mailstream_low * s)219 void mailstream_low_free(mailstream_low * s)
220 {
221 free(s->identifier);
222 s->identifier = NULL;
223 s->driver->mailstream_free(s);
224 }
225
mailstream_low_read(mailstream_low * s,void * buf,size_t count)226 ssize_t mailstream_low_read(mailstream_low * s, void * buf, size_t count)
227 {
228 ssize_t r;
229
230 if (s == NULL)
231 return -1;
232 r = s->driver->mailstream_read(s, buf, count);
233
234 #ifdef STREAM_DEBUG
235 if (r > 0) {
236 STREAM_LOG(s, 0, "<<<<<<< read <<<<<<\n");
237 STREAM_LOG_BUF(s, 0, buf, r);
238 STREAM_LOG(s, 0, "\n");
239 STREAM_LOG(s, 0, "<<<<<<< end read <<<<<<\n");
240 }
241 #endif
242
243 if (r < 0) {
244 STREAM_LOG_ERROR(s, 4, buf, 0);
245 }
246
247 return r;
248 }
249
mailstream_low_write(mailstream_low * s,const void * buf,size_t count)250 ssize_t mailstream_low_write(mailstream_low * s,
251 const void * buf, size_t count)
252 {
253 ssize_t r;
254
255 if (s == NULL)
256 return -1;
257
258 #ifdef STREAM_DEBUG
259 STREAM_LOG(s, 1, ">>>>>>> send >>>>>>\n");
260 if (s->privacy) {
261 STREAM_LOG_BUF(s, 1, buf, count);
262 }
263 else {
264 STREAM_LOG_BUF(s, 2, buf, count);
265 }
266 STREAM_LOG(s, 1, "\n");
267 STREAM_LOG(s, 1, ">>>>>>> end send >>>>>>\n");
268 #endif
269
270 r = s->driver->mailstream_write(s, buf, count);
271
272 if (r < 0) {
273 STREAM_LOG_ERROR(s, 4 | 1, buf, 0);
274 }
275
276 return r;
277 }
278
mailstream_low_cancel(mailstream_low * s)279 void mailstream_low_cancel(mailstream_low * s)
280 {
281 if (s == NULL)
282 return;
283
284 if (s->driver->mailstream_cancel == NULL)
285 return;
286
287 s->driver->mailstream_cancel(s);
288 }
289
mailstream_low_log_error(mailstream_low * s,const void * buf,size_t count)290 void mailstream_low_log_error(mailstream_low * s,
291 const void * buf, size_t count)
292 {
293 STREAM_LOG_ERROR(s, 0, buf, count);
294 }
295
mailstream_low_set_privacy(mailstream_low * s,int can_be_public)296 void mailstream_low_set_privacy(mailstream_low * s, int can_be_public)
297 {
298 s->privacy = can_be_public;
299 }
300
mailstream_low_set_identifier(mailstream_low * s,char * identifier)301 int mailstream_low_set_identifier(mailstream_low * s,
302 char * identifier)
303 {
304 free(s->identifier);
305 s->identifier = NULL;
306
307 if (identifier != NULL) {
308 s->identifier = identifier;
309 }
310
311 return 0;
312 }
313
mailstream_low_get_identifier(mailstream_low * s)314 const char * mailstream_low_get_identifier(mailstream_low * s)
315 {
316 return s->identifier;
317 }
318
mailstream_low_set_timeout(mailstream_low * s,time_t timeout)319 void mailstream_low_set_timeout(mailstream_low * s,
320 time_t timeout)
321 {
322 s->timeout = timeout;
323 }
324
mailstream_low_get_timeout(mailstream_low * s)325 time_t mailstream_low_get_timeout(mailstream_low * s)
326 {
327 return s->timeout;
328 }
329
mailstream_low_set_logger(mailstream_low * s,void (* logger)(mailstream_low * s,int log_type,const char * str,size_t size,void * context),void * logger_context)330 void mailstream_low_set_logger(mailstream_low * s, void (* logger)(mailstream_low * s, int log_type,
331 const char * str, size_t size, void * context), void * logger_context)
332 {
333 s->logger = logger;
334 s->logger_context = logger_context;
335 }
336
mailstream_logger_internal(mailstream_low * s,int is_stream_data,int direction,const char * buffer,size_t size)337 static inline void mailstream_logger_internal(mailstream_low * s, int is_stream_data, int direction,
338 const char * buffer, size_t size)
339 {
340 int log_type = -1;
341
342 if (s->logger == NULL)
343 return;
344
345 /*
346 stream data:
347 0: log
348 1: buffer
349 2: error
350
351 direction:
352 4|1: send error
353 4: receive error
354 2: sent private data
355 1: sent data
356 0: received data
357 */
358
359 switch (is_stream_data) {
360 case 0: {
361 switch (direction) {
362 case 1:
363 case 2:
364 case 4|1:
365 log_type = MAILSTREAM_LOG_TYPE_INFO_SENT;
366 break;
367 case 0:
368 case 4:
369 log_type = MAILSTREAM_LOG_TYPE_INFO_RECEIVED;
370 break;
371 }
372 break;
373 }
374 case 1: {
375 switch (direction) {
376 case 2:
377 log_type = MAILSTREAM_LOG_TYPE_DATA_SENT_PRIVATE;
378 break;
379 case 1:
380 case 4|1:
381 log_type = MAILSTREAM_LOG_TYPE_DATA_SENT;
382 break;
383 case 0:
384 case 4:
385 default:
386 log_type = MAILSTREAM_LOG_TYPE_DATA_RECEIVED;
387 break;
388 }
389 break;
390 }
391 case 2: {
392 switch (direction) {
393 case 2:
394 case 1:
395 case 4|1:
396 log_type = MAILSTREAM_LOG_TYPE_ERROR_SENT;
397 break;
398 case 4:
399 log_type = MAILSTREAM_LOG_TYPE_ERROR_RECEIVED;
400 break;
401 case 0:
402 log_type = MAILSTREAM_LOG_TYPE_ERROR_PARSE;
403 break;
404 }
405 break;
406 }
407 }
408
409 if (log_type == -1)
410 return;
411
412 s->logger(s, log_type, buffer, size, s->logger_context);
413 }
414
mailstream_low_get_certificate_chain(mailstream_low * s)415 carray * mailstream_low_get_certificate_chain(mailstream_low * s)
416 {
417 if (s == NULL)
418 return NULL;
419
420 if (s->driver->mailstream_get_certificate_chain == NULL)
421 return NULL;
422
423 return s->driver->mailstream_get_certificate_chain(s);
424 }
425
mailstream_low_wait_idle(mailstream_low * low,struct mailstream_cancel * idle,int max_idle_delay)426 int mailstream_low_wait_idle(mailstream_low * low, struct mailstream_cancel * idle,
427 int max_idle_delay)
428 {
429 int fd;
430 int idle_fd;
431 int cancel_fd;
432 int r;
433 #if defined(WIN32)
434 fd_set readfds;
435 #elif USE_POLL
436 struct pollfd pfd[3];
437 #else
438 int maxfd;
439 fd_set readfds;
440 #endif
441
442 if (low->driver == mailstream_cfstream_driver) {
443 return mailstream_low_cfstream_wait_idle(low, max_idle_delay);
444 }
445 else if (low->driver == mailstream_compress_driver) {
446 return mailstream_low_compress_wait_idle(low, idle, max_idle_delay);
447 }
448
449 if (idle == NULL) {
450 return MAILSTREAM_IDLE_ERROR;
451 }
452 if (mailstream_low_get_cancel(low) == NULL) {
453 return MAILSTREAM_IDLE_ERROR;
454 }
455 fd = mailstream_low_get_fd(low);
456 idle_fd = mailstream_cancel_get_fd(idle);
457 cancel_fd = mailstream_cancel_get_fd(mailstream_low_get_cancel(low));
458
459 #if defined(WIN32)
460 FD_ZERO(&readfds);
461 HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
462 WSAEventSelect(fd, event, FD_READ | FD_CLOSE);
463 FD_SET(event, &readfds);
464 FD_SET(idle_fd, &readfds);
465 FD_SET(cancel_fd, &readfds);
466 r = WaitForMultipleObjects(readfds.fd_count, readfds.fd_array, FALSE, max_idle_delay * 1000);
467 WSAEventSelect(fd, event, 0);
468 CloseHandle(event);
469 if (r == WAIT_TIMEOUT) {
470 return MAILSTREAM_IDLE_TIMEOUT;
471 }
472 else if (r == WAIT_OBJECT_0){
473 return MAILSTREAM_IDLE_HASDATA;
474 }
475 else if (r == WAIT_OBJECT_0 + 1){
476 return MAILSTREAM_IDLE_INTERRUPTED;
477 }
478 else if (r == WAIT_OBJECT_0 + 2){
479 return MAILSTREAM_IDLE_CANCELLED;
480 }
481 DWORD i = GetLastError();
482 return MAILSTREAM_IDLE_ERROR;
483 #elif USE_POLL
484 pfd[0].fd = fd;
485 pfd[0].events = POLLIN;
486 pfd[0].revents = 0;
487
488 pfd[1].fd = idle_fd;
489 pfd[1].events = POLLIN;
490 pfd[1].revents = 0;
491
492 pfd[2].fd = cancel_fd;
493 pfd[2].events = POLLIN;
494 pfd[2].revents = 0;
495
496 r = poll(&pfd[0], 3, max_idle_delay * 1000);
497
498 if (r == 0){
499 // timeout
500 return MAILSTREAM_IDLE_TIMEOUT;
501 }
502 else if (r == -1) {
503 // do nothing
504 return MAILSTREAM_IDLE_ERROR;
505 }
506 else {
507 if (pfd[0].revents & POLLIN) {
508 // has something on socket
509 return MAILSTREAM_IDLE_HASDATA;
510 }
511 if (pfd[1].revents & POLLIN) {
512 // idle interrupted
513 mailstream_cancel_ack(idle);
514 return MAILSTREAM_IDLE_INTERRUPTED;
515 }
516 if (pfd[2].revents & POLLIN) {
517 // idle cancelled
518 mailstream_cancel_ack(mailstream_low_get_cancel(low));
519 return MAILSTREAM_IDLE_CANCELLED;
520 }
521 return MAILSTREAM_IDLE_ERROR;
522 }
523 #else
524 FD_ZERO(&readfds);
525 FD_SET(fd, &readfds);
526 FD_SET(idle_fd, &readfds);
527 FD_SET(cancel_fd, &readfds);
528 maxfd = fd;
529 if (idle_fd > maxfd) {
530 maxfd = idle_fd;
531 }
532 if (cancel_fd > maxfd) {
533 maxfd = cancel_fd;
534 }
535 struct timeval delay;
536 delay.tv_sec = max_idle_delay;
537 delay.tv_usec = 0;
538
539 r = select(maxfd + 1, &readfds, NULL, NULL, &delay);
540 if (r == 0) {
541 // timeout
542 return MAILSTREAM_IDLE_TIMEOUT;
543 }
544 else if (r == -1) {
545 // do nothing
546 return MAILSTREAM_IDLE_ERROR;
547 }
548 else {
549 if (FD_ISSET(fd, &readfds)) {
550 // has something on socket
551 return MAILSTREAM_IDLE_HASDATA;
552 }
553 if (FD_ISSET(idle_fd, &readfds)) {
554 // idle interrupted
555 mailstream_cancel_ack(idle);
556 return MAILSTREAM_IDLE_INTERRUPTED;
557 }
558 if (FD_ISSET(cancel_fd, &readfds)) {
559 // idle cancelled
560 mailstream_cancel_ack(mailstream_low_get_cancel(low));
561 return MAILSTREAM_IDLE_CANCELLED;
562 }
563 return MAILSTREAM_IDLE_ERROR;
564 }
565 #endif
566 }
567
mailstream_low_setup_idle(mailstream_low * low)568 int mailstream_low_setup_idle(mailstream_low * low)
569 {
570 if (low->driver->mailstream_setup_idle == NULL)
571 return -1;
572
573 return low->driver->mailstream_setup_idle(low);
574 }
575
mailstream_low_unsetup_idle(mailstream_low * low)576 int mailstream_low_unsetup_idle(mailstream_low * low)
577 {
578 if (low->driver->mailstream_unsetup_idle == NULL)
579 return -1;
580
581 return low->driver->mailstream_unsetup_idle(low);
582 }
583
mailstream_low_interrupt_idle(mailstream_low * low)584 int mailstream_low_interrupt_idle(mailstream_low * low)
585 {
586 if (low->driver->mailstream_interrupt_idle == NULL)
587 return -1;
588
589 return low->driver->mailstream_interrupt_idle(low);
590 }
591
592