/[pkg-mixmaster]/trunk/Mix/Src/mail.c
ViewVC logotype

Contents of /trunk/Mix/Src/mail.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 122 - (hide annotations) (download)
Wed Aug 7 17:27:01 2002 UTC (10 years, 9 months ago) by weaselp
File MIME type: text/plain
File size: 16143 byte(s)
Make sure files are closed
1 rabbi 1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
2    
3     Mixmaster may be redistributed and modified under certain conditions.
4     This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5     ANY KIND, either express or implied. See the file COPYRIGHT for
6     details.
7    
8     Socket-based mail transport services
9 weaselp 122 $Id: mail.c,v 1.7 2002/08/07 17:27:01 weaselp Exp $ */
10 rabbi 1
11    
12     #include "mix3.h"
13     #include <stdio.h>
14     #include <stdlib.h>
15     #include <string.h>
16    
17     #if defined(UNIX) && defined(USE_SOCK)
18     #include <unistd.h>
19     #include <sys/types.h>
20     #include <sys/socket.h>
21     #include <netinet/in.h>
22     #include <arpa/inet.h>
23     #include <netdb.h>
24     #include <fcntl.h>
25     #endif
26    
27     int sendinfofile(char *name, char *logname, BUFFER *address, BUFFER *header)
28     {
29 weaselp 122 FILE *f = NULL, *log = NULL;
30 rabbi 1 BUFFER *msg, *addr;
31     char line[LINELEN];
32     int ret = -1;
33    
34     if (bufeq(address, ANONNAME))
35     return (0); /* don't reply to our own anon messages */
36     f = mix_openfile(name, "r");
37     if (f == NULL)
38     return (-1);
39    
40     addr = buf_new();
41     rfc822_addr(address, addr);
42     if (addr->length == 0)
43     buf_set(addr, address), buf_nl(addr);
44    
45     if (logname != NULL) {
46     if ((log = mix_openfile(logname, "r+")) != NULL) {
47     /* log recipients to prevent mail loop */
48     while (fgets(line, sizeof(line), log) != NULL)
49     if (strieq(line, addr->data))
50     goto end;
51     } else if ((log = mix_openfile(logname, "w")) == NULL) {
52     errlog(ERRORMSG, "Can't create %s.\n", logname);
53     ret = -1;
54     goto end;
55     }
56     fprintf(log, "%s", addr->data);
57     }
58     msg = buf_new();
59     if (header)
60     buf_cat(msg, header), buf_nl(msg);
61     while (fgets(line, sizeof(line), f) != NULL) {
62     if (streq(line, "DESTINATION-BLOCK\n"))
63     buf_appendf(msg, "destination-block %b", addr);
64     else
65     buf_appends(msg, line);
66     }
67     ret = sendmail(msg, REMAILERNAME, address);
68     buf_free(msg);
69     end:
70 weaselp 122 if (f)
71     fclose(f);
72 rabbi 1 if (log)
73     fclose(log);
74     buf_free(addr);
75     return (ret);
76     }
77    
78     int smtpsend(BUFFER *head, BUFFER *message, char *from);
79    
80 weaselp 116
81     int sendmail_loop(BUFFER *message, char *from, BUFFER *address)
82     {
83     BUFFER *msg;
84     int err;
85    
86     msg = buf_new();
87     buf_appendf(msg, "X-Loop: %s\n", REMAILERADDR);
88     buf_cat(msg, message);
89     err = sendmail(msg, from, address);
90     buf_free(msg);
91    
92     return(err);
93 weaselp 121 }
94 weaselp 116
95 rabbi 1 int sendmail(BUFFER *message, char *from, BUFFER *address)
96     {
97     /* returns: 0: ok 1: problem, try again -1: failed */
98    
99     BUFFER *head, *block;
100     FILE *f;
101     int err = -1;
102    
103     head = buf_new();
104    
105     block = readdestblk( );
106     if ( !block ) block = buf_new( );
107    
108     if (address != NULL &&
109     (address->length == 0 || doblock(address, block, 1) == -1))
110     goto end;
111    
112     if (from != NULL) {
113     buf_setf(head, "From: %s", from);
114     hdr_encode(head, 255);
115     buf_nl(head);
116     }
117     if (address != NULL)
118     buf_appendf(head, "To: %b\n", address);
119    
120     buf_rewind(message);
121    
122     if (SMTPRELAY[0])
123     err = smtpsend(head, message, from);
124     else if (strieq(SENDMAIL, "outfile")) {
125     char path[PATHMAX];
126     FILE *f = NULL;
127     int i;
128    
129     for (i = 0; i < 10000; i++) {
130 rabbi 11 sprintf(path, "%s%cout%i.txt", POOLDIR, DIRSEP, i);
131 rabbi 1 f = fopen(path, "r");
132     if (f)
133     fclose(f);
134     else
135     break;
136     }
137     f = fopen(path, "w");
138     if (f != NULL) {
139     err = buf_write(head, f);
140     err = buf_write(message, f);
141     fclose(f);
142     } else
143     errlog(ERRORMSG, "Can't create %s!\n", path);
144     } else {
145     if (SENDANONMAIL[0] != '\0' && (from == NULL || streq(from, ANONNAME)))
146     f = openpipe(SENDANONMAIL);
147     else
148     f = openpipe(SENDMAIL);
149     if (f != NULL) {
150     err = buf_write(head, f);
151     err = buf_write(message, f);
152     closepipe(f);
153     }
154     }
155     if (err != 0)
156     err = 1; /* error while sending, retry later */
157     end:
158     buf_free(block);
159     buf_free(head);
160     return (err);
161     }
162    
163     /* socket communication **********************************************/
164    
165     #ifdef USE_SOCK
166     #ifdef WIN32
167     WSADATA w;
168    
169     int sock_init()
170     {
171     if (WSAStartup(MAKEWORD(2, 0), &w) != 0) {
172     errlog(ERRORMSG, "Unable to initialize WINSOCK.\n");
173     return 0;
174     }
175     return 1;
176     }
177    
178     void sock_exit(void)
179     {
180     WSACleanup();
181     }
182     #endif
183    
184     SOCKET opensocket(char *hostname, int port)
185     {
186     struct hostent *hp;
187     struct sockaddr_in server;
188     SOCKET s;
189    
190     if ((hp = gethostbyname(hostname)) == NULL)
191     return (INVALID_SOCKET);
192    
193     memset((char *) &server, 0, sizeof(server));
194     server.sin_family = AF_INET;
195     server.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
196     server.sin_port = htons((unsigned short) port);
197    
198     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
199     if (s != INVALID_SOCKET)
200     if (connect(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
201     closesocket(s);
202     return (INVALID_SOCKET);
203     }
204     return (s);
205     }
206    
207     #ifndef WIN32
208     int closesocket(SOCKET s)
209     {
210     return (close(s));
211     }
212     #endif
213    
214     int sock_getline(SOCKET s, BUFFER *line)
215     {
216     char c;
217     int ok;
218    
219     buf_clear(line);
220     while ((ok = recv(s, &c, 1, 0)) > 0) {
221     if (c == '\n')
222     break;
223     if (c != '\r')
224     buf_appendc(line, c);
225     }
226     if (ok <= 0)
227     return (-1);
228     if (line->length == 0)
229     return (1);
230     return (0);
231     }
232    
233     int sock_cat(SOCKET s, BUFFER *b)
234     {
235     int p = 0, n;
236    
237     do {
238     n = send(s, b->data, b->length, 0);
239     if (n < 0)
240     return (-1);
241     p += n;
242     } while (p < b->length);
243     return (0);
244     }
245     #else
246     SOCKET opensocket(char *hostname, int port)
247     {
248     return (INVALID_SOCKET);
249     }
250    
251     int closesocket(SOCKET s)
252     {
253     return (INVALID_SOCKET);
254     }
255    
256     int sock_getline(SOCKET s, BUFFER *line)
257     {
258     return (-1);
259     }
260    
261     int sock_cat(SOCKET s, BUFFER *b)
262     {
263     return (-1);
264     }
265     #endif
266    
267     /* send messages by SMTP ************************************************/
268    
269     static int sock_getsmtp(SOCKET s, BUFFER *line)
270     {
271     int ret;
272    
273     do
274     ret = sock_getline(s, line);
275     while (line->length >= 4 && line->data[3] == '-');
276     return (ret);
277     }
278    
279     SOCKET smtp_open(void)
280     {
281     int s = INVALID_SOCKET;
282     BUFFER *line;
283    
284     #ifdef USE_SOCK
285     if (SMTPRELAY[0] != '\0')
286     s = opensocket(SMTPRELAY, 25);
287     if (s != INVALID_SOCKET) {
288     line = buf_new();
289     sock_getsmtp(s, line);
290     if (line->data[0] != '2') {
291     errlog(ERRORMSG, "SMTP relay not ready. %b\n", line);
292     closesocket(s);
293     s = INVALID_SOCKET;
294     } else {
295     errlog(DEBUGINFO, "Opening SMTP connection.\n");
296     buf_sets(line, "HELO ");
297     if (HELONAME[0])
298     buf_appends(line, HELONAME);
299     else if (strchr(ENVFROM, '@'))
300     buf_appends(line, strchr(ENVFROM, '@') + 1);
301     else {
302     struct sockaddr_in sa;
303     int len = sizeof(sa);
304     struct hostent *hp;
305    
306     if (getsockname(s, (struct sockaddr *) &sa, &len) == 0 &&
307     (hp = gethostbyaddr((char *) &sa.sin_addr, sizeof(sa.sin_addr),
308     AF_INET)) != NULL)
309     buf_appends(line, (char *) hp->h_name);
310     else if (strchr(REMAILERADDR, '@'))
311     buf_appends(line, strchr(REMAILERADDR, '@') + 1);
312     else
313     buf_appends(line, SHORTNAME);
314     }
315     buf_appends(line, "\r\n");
316     sock_cat(s, line);
317     sock_getsmtp(s, line);
318     if (line->data[0] != '2') {
319     errlog(ERRORMSG, "SMTP relay refuses HELO: %b\n", line);
320     closesocket(s);
321     s = INVALID_SOCKET;
322     }
323     }
324     buf_free(line);
325     }
326     #endif
327     return (s);
328     }
329    
330     int smtp_close(SOCKET s)
331     {
332     BUFFER *line;
333     int ret = -1;
334    
335     #ifdef USE_SOCK
336     line = buf_new();
337     buf_sets(line, "QUIT\r\n");
338     sock_cat(s, line);
339     if (sock_getsmtp(s, line) == 0 && line->data[0] == '2') {
340     errlog(DEBUGINFO, "Closing SMTP connection.\n");
341     ret = 0;
342     } else
343     errlog(WARNING, "SMTP quit failed: %b\n", line);
344     closesocket(s);
345     buf_free(line);
346     #endif
347     return (ret);
348     }
349    
350     int smtp_send(SOCKET relay, BUFFER *head, BUFFER *message, char *from)
351     {
352     BUFFER *rcpt, *line, *field, *content;
353     int ret = -1;
354    
355     #ifdef USE_SOCK
356     line = buf_new();
357     field = buf_new();
358     content = buf_new();
359     rcpt = buf_new();
360    
361     while (buf_getheader(head, field, content) == 0)
362     if (bufieq(field, "to"))
363 rabbi 29 #ifdef BROKEN_MTA
364     if (!bufifind(rcpt, content->data))
365     /* Do not add the same recipient twice.
366     Needed for brain-dead MTAs. */
367     #endif //BROKEN_MTA
368     rfc822_addr(content, rcpt);
369 rabbi 1 buf_rewind(head);
370    
371 weaselp 116 while (buf_isheader(message) && buf_getheader(message, field, content) == 0) {
372 rabbi 1 if (bufieq(field, "to") || bufieq(field, "cc") || bufieq(field, "bcc")) {
373 rabbi 29 #ifdef BROKEN_MTA
374     if (!bufifind(rcpt, content->data))
375     /* Do not add the same recipient twice.
376     Needed for brain-dead MTAs. */
377     #endif //BROKEN_MTA
378     rfc822_addr(content, rcpt);
379 rabbi 1 }
380     if (!bufieq(field, "bcc"))
381     buf_appendheader(head, field, content);
382     }
383     buf_nl(head);
384    
385     buf_clear(content);
386     if (from) {
387     buf_sets(line, from);
388     rfc822_addr(line, content);
389     buf_chop(content);
390     }
391     if (bufieq(content, REMAILERADDR) || bufieq(content, ANONADDR))
392     buf_clear(content);
393     if (content->length == 0)
394     buf_sets(content, ENVFROM[0] ? ENVFROM : ANONADDR);
395    
396     buf_setf(line, "MAIL FROM:<%b>\r\n", content);
397     sock_cat(relay, line);
398     sock_getsmtp(relay, line);
399     if (!line->data[0] == '2') {
400     errlog(ERRORMSG, "SMTP relay does not accept mail: %b\n", line);
401     goto end;
402     }
403     while (buf_getline(rcpt, content) == 0) {
404     buf_setf(line, "RCPT TO:<%b>\r\n", content);
405     sock_cat(relay, line);
406     sock_getsmtp(relay, line);
407     if (bufleft(line, "421")) {
408     errlog(ERRORMSG, "SMTP relay error: %b\n", line);
409     goto end;
410     }
411     }
412    
413     buf_sets(line, "DATA\r\n");
414     sock_cat(relay, line);
415     sock_getsmtp(relay, line);
416     if (!bufleft(line, "354")) {
417     errlog(WARNING, "SMTP relay does not accept message: %b\n", line);
418     goto end;
419     }
420     while (buf_getline(head, line) >= 0) {
421     buf_appends(line, "\r\n");
422     if (bufleft(line, ".")) {
423     buf_setf(content, ".%b", line);
424     buf_move(line, content);
425     }
426     sock_cat(relay, line);
427     }
428     while (buf_getline(message, line) >= 0) {
429     buf_appends(line, "\r\n");
430     if (bufleft(line, ".")) {
431     buf_setf(content, ".%b", line);
432     buf_move(line, content);
433     }
434     sock_cat(relay, line);
435     }
436     buf_sets(line, ".\r\n");
437     sock_cat(relay, line);
438     sock_getsmtp(relay, line);
439     if (bufleft(line, "2"))
440     ret = 0;
441     else
442     errlog(WARNING, "SMTP relay will not send message: %b\n", line);
443     end:
444     buf_free(line);
445     buf_free(field);
446     buf_free(content);
447     buf_free(rcpt);
448     #endif
449     return (ret);
450     }
451    
452     static SOCKET sendmail_state = INVALID_SOCKET;
453    
454     void sendmail_begin(void)
455     {
456     /* begin mail sending session */
457     if (sendmail_state == INVALID_SOCKET)
458     sendmail_state = smtp_open();
459     }
460     void sendmail_end(void)
461     {
462     /* end mail sending session */
463     if (sendmail_state != INVALID_SOCKET) {
464     smtp_close(sendmail_state);
465     sendmail_state = INVALID_SOCKET;
466     }
467     }
468    
469     int smtpsend(BUFFER *head, BUFFER *message, char *from)
470     {
471     SOCKET s;
472     int ret = -1;
473    
474     if (sendmail_state != INVALID_SOCKET)
475     ret = smtp_send(sendmail_state, head, message, from);
476     else {
477     s = smtp_open();
478     if (s != INVALID_SOCKET) {
479     ret = smtp_send(s, head, message, from);
480     smtp_close(s);
481     }
482     }
483     return (ret);
484     }
485    
486     /* retrieve mail with POP3 **********************************************/
487     #ifdef USE_SOCK
488     int pop3_close(SOCKET s);
489    
490     #define POP3_ANY 0
491     #define POP3_APOP 1
492     #define POP3_PASS 2
493    
494     SOCKET pop3_open(char *user, char *host, char *pass, int auth)
495     {
496     SOCKET server = INVALID_SOCKET;
497     BUFFER *line;
498     int authenticated = 0;
499     char c, md[33];
500    
501     line = buf_new();
502     server = opensocket(host, 110);
503     if (server == INVALID_SOCKET)
504     errlog(NOTICE, "Can't connect to POP3 server %s.\n", host);
505     else {
506     sock_getline(server, line);
507     if (!bufleft(line, "+")) {
508     errlog(WARNING, "No POP3 service at %s.\n", host);
509     closesocket(server);
510 rabbi 11 server = INVALID_SOCKET;
511 rabbi 1 }
512     }
513     if (server != INVALID_SOCKET) {
514     errlog(DEBUGINFO, "Opening POP3 connection to %s.\n", host);
515     do
516     c = buf_getc(line);
517     while (c != '<' && c != -1);
518     while (c != '>' && c != -1) {
519     buf_appendc(line, c);
520     c = buf_getc(line);
521     }
522     if (c == '>' && (auth == POP3_ANY || auth == POP3_APOP)) {
523     buf_appendc(line, c);
524     buf_appends(line, pass);
525     digest_md5(line, line);
526     id_encode(line->data, md);
527     buf_setf(line, "APOP %s %s\r\n", user, md);
528     sock_cat(server, line);
529     sock_getline(server, line);
530     if (bufleft(line, "+"))
531     authenticated = 1;
532     else {
533     errlog(auth == POP3_APOP ? ERRORMSG : NOTICE,
534     "POP3 APOP auth at %s failed: %b\n", host, line);
535     buf_sets(line, "QUIT\r\n");
536     sock_cat(server, line);
537     closesocket(server);
538     server = pop3_open(user, host, pass, POP3_PASS);
539     goto end;
540     }
541     }
542     if (!authenticated) {
543     buf_setf(line, "USER %s\r\n", user);
544     sock_cat(server, line);
545     sock_getline(server, line);
546     if (!bufleft(line, "+"))
547     errlog(ERRORMSG, "POP3 USER command at %s failed: %b\n", host, line);
548     else {
549     buf_setf(line, "PASS %s\r\n", pass);
550     sock_cat(server, line);
551     sock_getline(server, line);
552     if (bufleft(line, "+"))
553     authenticated = 1;
554     else
555     errlog(ERRORMSG, "POP3 auth at %s failed: %b\n", host, line);
556     }
557     }
558     if (!authenticated) {
559     pop3_close(server);
560 rabbi 11 closesocket(server);
561 rabbi 1 server = INVALID_SOCKET;
562     }
563     }
564     end:
565     buf_free(line);
566     return (server);
567     }
568    
569     int pop3_close(SOCKET s)
570     {
571     BUFFER *line;
572     int ret = -1;
573    
574     line = buf_new();
575     buf_sets(line, "QUIT\r\n");
576     sock_cat(s, line);
577     sock_getline(s, line);
578     if (bufleft(line, "+")) {
579     ret = 0;
580     errlog(DEBUGINFO, "Closing POP3 connection.\n");
581     } else
582     errlog(ERRORMSG, "POP3 QUIT failed:\n", line->data);
583     buf_free(line);
584     return (ret);
585     }
586    
587     int pop3_stat(SOCKET s)
588     {
589     BUFFER *line;
590     int val = -1;
591    
592     line = buf_new();
593     buf_sets(line, "STAT\r\n");
594     sock_cat(s, line);
595     sock_getline(s, line);
596     if (bufleft(line, "+"))
597     sscanf(line->data, "+%*s %d", &val);
598     buf_free(line);
599     return (val);
600     }
601    
602     int pop3_list(SOCKET s, int n)
603     {
604     BUFFER *line;
605     int val = -1;
606    
607     line = buf_new();
608     buf_setf(line, "LIST %d\r\n", n);
609     sock_cat(s, line);
610     sock_getline(s, line);
611     if (bufleft(line, "+"))
612     sscanf(line->data, "+%*s %d", &val);
613     buf_free(line);
614     return (val);
615     }
616    
617     int pop3_dele(SOCKET s, int n)
618     {
619     BUFFER *line;
620     int ret = 0;
621    
622     line = buf_new();
623     buf_setf(line, "DELE %d\r\n", n);
624     sock_cat(s, line);
625     sock_getline(s, line);
626     if (!bufleft(line, "+"))
627     ret = -1;
628     buf_free(line);
629     return (ret);
630     }
631    
632     int pop3_retr(SOCKET s, int n, BUFFER *msg)
633     {
634     BUFFER *line;
635     int ret = -1;
636    
637     line = buf_new();
638     buf_clear(msg);
639     buf_setf(line, "RETR %d\r\n", n);
640     sock_cat(s, line);
641     sock_getline(s, line);
642     if (bufleft(line, "+")) {
643     for (;;) {
644     if (sock_getline(s, line) == -1)
645     break;
646     if (bufeq(line, ".")) {
647     ret = 0;
648     break;
649     } else if (bufleft(line, ".")) {
650     buf_append(msg, line->data + 1, line->length - 1);
651     } else
652     buf_cat(msg, line);
653     buf_nl(msg);
654     }
655     }
656     buf_free(line);
657     return (ret);
658     }
659    
660     void pop3get(void)
661     {
662     FILE *f;
663     char cfg[LINELEN], user[LINELEN], host[LINELEN], pass[LINELEN], auth[5];
664     SOCKET server;
665     BUFFER *line, *msg;
666     int i = 0, num = 0;
667    
668     line = buf_new();
669     msg = buf_new();
670     f = mix_openfile(POP3CONF, "r");
671     if (f != NULL)
672     while (fgets(cfg, sizeof(cfg), f) != NULL) {
673     if (strchr(cfg, '@'))
674     strchr(cfg, '@')[0] = ' ';
675     if (sscanf(cfg, "%127s %127s %127s %4s", user, host, pass, auth) < 3)
676     continue;
677     i = POP3_ANY;
678     if (strileft(auth, "apop"))
679     i = POP3_APOP;
680     if (strileft(auth, "pass"))
681     i = POP3_PASS;
682     server = pop3_open(user, host, pass, i);
683     if (server != INVALID_SOCKET) {
684     num = pop3_stat(server);
685     if (num < 0)
686     errlog(WARNING, "POP3 protocol error at %s.\n", host);
687     else if (num == 0)
688     errlog(DEBUGINFO, "No mail at %s.\n", host);
689     else
690     for (i = 1; i <= num; i++) {
691     if (POP3SIZELIMIT > 0 &&
692     pop3_list(server, i) > POP3SIZELIMIT * 1024) {
693     errlog(WARNING, "Over size message on %s.", host);
694     if (POP3DEL == 1)
695     pop3_dele(server, i);
696     } else {
697     if (pop3_retr(server, i, msg) == 0 &&
698     pool_add(msg, "inf") == 0)
699     pop3_dele(server, i);
700     else {
701     errlog(WARNING, "POP3 error while getting mail from %s.",
702     host);
703     closesocket(server);
704     goto end;
705     }
706     }
707     }
708     pop3_close(server);
709 rabbi 11 closesocket(server);
710 rabbi 1 }
711     }
712     end:
713 rabbi 11 if (f != NULL)
714     fclose(f);
715 rabbi 1 buf_free(line);
716     buf_free(msg);
717     }
718     #endif

  ViewVC Help
Powered by ViewVC 1.1.5