960a6e0258a7ff8be83deb99daf87041df1093f7
[citadel.git] / citadel / modules / smtp / smtp_clienthandlers.c
1 /*
2  * This module is an SMTP and ESMTP implementation for the Citadel system.
3  * It is compliant with all of the following:
4  *
5  * RFC  821 - Simple Mail Transfer Protocol
6  * RFC  876 - Survey of SMTP Implementations
7  * RFC 1047 - Duplicate messages and SMTP
8  * RFC 1652 - 8 bit MIME
9  * RFC 1869 - Extended Simple Mail Transfer Protocol
10  * RFC 1870 - SMTP Service Extension for Message Size Declaration
11  * RFC 2033 - Local Mail Transfer Protocol
12  * RFC 2197 - SMTP Service Extension for Command Pipelining
13  * RFC 2476 - Message Submission
14  * RFC 2487 - SMTP Service Extension for Secure SMTP over TLS
15  * RFC 2554 - SMTP Service Extension for Authentication
16  * RFC 2821 - Simple Mail Transfer Protocol
17  * RFC 2822 - Internet Message Format
18  * RFC 2920 - SMTP Service Extension for Command Pipelining
19  *
20  * Copyright (c) 1998-2015 by the citadel.org team
21  *
22  * This program is open source software; you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License version 3.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  */
30
31 #include "sysdep.h"
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <termios.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <pwd.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <syslog.h>
42
43 #if TIME_WITH_SYS_TIME
44 # include <sys/time.h>
45 # include <time.h>
46 #else
47 # if HAVE_SYS_TIME_H
48 #  include <sys/time.h>
49 # else
50 #  include <time.h>
51 # endif
52 #endif
53 #include <sys/wait.h>
54 #include <ctype.h>
55 #include <string.h>
56 #include <limits.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <libcitadel.h>
61 #include "citadel.h"
62 #include "server.h"
63 #include "citserver.h"
64 #include "support.h"
65 #include "config.h"
66 #include "control.h"
67 #include "user_ops.h"
68 #include "database.h"
69 #include "msgbase.h"
70 #include "internet_addressing.h"
71 #include "genstamp.h"
72 #include "domain.h"
73 #include "clientsocket.h"
74 #include "locate_host.h"
75 #include "citadel_dirs.h"
76
77 #include "ctdl_module.h"
78
79 #include "smtp_util.h"
80 #include "event_client.h"
81 #include "smtpqueue.h"
82 #include "smtp_clienthandlers.h"
83
84
85 #define SMTP_ERROR(WHICH_ERR, ERRSTR) do {                             \
86                 Msg->MyQEntry->Status = WHICH_ERR;                     \
87                 StrBufAppendBufPlain(Msg->MyQEntry->StatusMessage,     \
88                                      HKEY(ERRSTR), 0);                 \
89                 StrBufTrim(Msg->MyQEntry->StatusMessage);              \
90                 return eAbort; }                                       \
91         while (0)
92
93 #define SMTP_VERROR(WHICH_ERR) do {                            \
94                 Msg->MyQEntry->Status = WHICH_ERR;             \
95                 StrBufPlain(Msg->MyQEntry->StatusMessage,      \
96                             ChrPtr(Msg->IO.IOBuf) + 4,         \
97                             StrLength(Msg->IO.IOBuf) - 4);     \
98                 StrBufTrim(Msg->MyQEntry->StatusMessage);      \
99                 return eAbort; }                               \
100         while (0)
101
102 #define SMTP_IS_STATE(WHICH_STATE) (ChrPtr(Msg->IO.IOBuf)[0] == WHICH_STATE)
103
104 #define SMTP_DBG_SEND() \
105         EVS_syslog(LOG_DEBUG, "> %s\n", ChrPtr(Msg->IO.SendBuf.Buf))
106
107 #define SMTP_DBG_READ() \
108         EVS_syslog(LOG_DEBUG, "< %s\n", ChrPtr(Msg->IO.IOBuf))
109
110 /*
111  * if a Read handler wants to skip to a specific part use this macro.
112  * the -1 is here since the auto-forward following has to be taken into account.
113  */
114 #define READ_NEXT_STATE(state) Msg->State = state - 1
115
116 /*****************************************************************************/
117 /*                     SMTP CLIENT STATE CALLBACKS                           */
118 /*****************************************************************************/
119 eNextState SMTPC_read_greeting(SmtpOutMsg *Msg)
120 {
121         /* Process the SMTP greeting from the server */
122         AsyncIO *IO = &Msg->IO;
123         SMTP_DBG_READ();
124         SetSMTPState(IO, eSTMPsmtp);
125
126         if (!SMTP_IS_STATE('2')) {
127                 if (SMTP_IS_STATE('4'))
128                         SMTP_VERROR(4);
129                 else
130                         SMTP_VERROR(5);
131         }
132         return eSendReply;
133 }
134
135 eNextState SMTPC_send_EHLO(SmtpOutMsg *Msg)
136 {
137         AsyncIO *IO = &Msg->IO;
138         /* At this point we know we are talking to a real SMTP server */
139
140         /* Do a EHLO command.  If it fails, try the HELO command. */
141         StrBufPrintf(Msg->IO.SendBuf.Buf, "EHLO %s\r\n", CtdlGetConfigStr("c_fqdn"));
142
143         SMTP_DBG_SEND();
144         return eReadMessage;
145 }
146
147 eNextState SMTPC_read_EHLO_reply(SmtpOutMsg *Msg)
148 {
149         AsyncIO *IO = &Msg->IO;
150         SMTP_DBG_READ();
151
152         if (SMTP_IS_STATE('2')) {
153                 READ_NEXT_STATE(eSMTPAuth);
154
155                 if ((Msg->pCurrRelay == NULL) ||
156                     (Msg->pCurrRelay->User == NULL))
157                         READ_NEXT_STATE(eFROM); /* Skip auth... */
158                 if (Msg->pCurrRelay != NULL)
159                 {
160                         if (strstr(ChrPtr(Msg->IO.IOBuf), "LOGIN") != NULL)
161                                 Msg->SendLogin = 1;
162                         else if ((Msg->MultiLineBuf != NULL) &&
163                                  strstr(ChrPtr(Msg->MultiLineBuf), "LOGIN") != NULL)
164                         {
165                                 Msg->SendLogin = 1;
166                         }
167                 }
168         }
169         /* else we fall back to 'helo' */
170         return eSendReply;
171 }
172
173 eNextState STMPC_send_HELO(SmtpOutMsg *Msg)
174 {
175         AsyncIO *IO = &Msg->IO;
176         StrBufPrintf(Msg->IO.SendBuf.Buf, "HELO %s\r\n", CtdlGetConfigStr("c_fqdn"));
177
178         SMTP_DBG_SEND();
179         return eReadMessage;
180 }
181
182 eNextState SMTPC_read_HELO_reply(SmtpOutMsg *Msg)
183 {
184         AsyncIO *IO = &Msg->IO;
185         SMTP_DBG_READ();
186
187         if (!SMTP_IS_STATE('2'))
188         {
189                 if (SMTP_IS_STATE('4'))
190                         SMTP_VERROR(4);
191                 else
192                         SMTP_VERROR(5);
193         }
194         if (Msg->pCurrRelay != NULL)
195         {
196                 if (strstr(ChrPtr(Msg->IO.IOBuf), "LOGIN") != NULL)
197                         Msg->SendLogin = 1;
198         }
199         if ((Msg->pCurrRelay == NULL) ||
200             (Msg->pCurrRelay->User == NULL))
201                 READ_NEXT_STATE(eFROM); /* Skip auth... */
202
203         return eSendReply;
204 }
205
206 eNextState SMTPC_send_auth(SmtpOutMsg *Msg)
207 {
208         AsyncIO *IO = &Msg->IO;
209         char buf[SIZ];
210         char encoded[1024];
211
212         if ((Msg->pCurrRelay == NULL) ||
213             (Msg->pCurrRelay->User == NULL))
214                 READ_NEXT_STATE(eFROM); /* Skip auth, shouldn't even come here!... */
215         else {
216                 /* Do an AUTH command if necessary */
217                 if (Msg->SendLogin)
218                 {
219                         StrBufPlain(Msg->IO.SendBuf.Buf,
220                                     HKEY("AUTH LOGIN\r\n"));
221                 }
222                 else
223                 {
224                         sprintf(buf, "%s%c%s%c%s",
225                                 Msg->pCurrRelay->User, '\0',
226                                 Msg->pCurrRelay->User, '\0',
227                                 Msg->pCurrRelay->Pass);
228                         
229                         size_t len = CtdlEncodeBase64(encoded, buf,
230                                                       strlen(Msg->pCurrRelay->User) * 2 +
231                                                       strlen(Msg->pCurrRelay->Pass) + 2, 0);
232
233                         if (buf[len - 1] == '\n') {
234                                 buf[len - 1] = '\0';
235                         }
236
237                         StrBufPrintf(Msg->IO.SendBuf.Buf,
238                                      "AUTH PLAIN %s\r\n",
239                                      encoded);
240                 }
241         }
242         SMTP_DBG_SEND();
243         return eReadMessage;
244 }
245
246
247 eNextState SMTPC_read_auth_reply(SmtpOutMsg *Msg)
248 {
249         AsyncIO *IO = &Msg->IO;
250         /* Do an AUTH command if necessary */
251
252         SMTP_DBG_READ();
253
254         if (Msg->SendLogin)
255         {
256                 if (!SMTP_IS_STATE('3'))
257                         SMTP_VERROR(5);
258         }
259         else
260         {
261                 if (!SMTP_IS_STATE('2')) {
262                         if (SMTP_IS_STATE('4'))
263                                 SMTP_VERROR(4);
264                         else
265                                 SMTP_VERROR(5);
266                 }
267                 READ_NEXT_STATE(eFROM);
268         }
269         return eSendReply;
270 }
271
272
273 eNextState SMTPC_send_authplain_1(SmtpOutMsg *Msg)
274 {
275         AsyncIO *IO = &Msg->IO;
276         char buf[SIZ];
277         char encoded[1024];
278         long encodedlen;
279
280         sprintf(buf, "%s",
281                 Msg->pCurrRelay->User);
282         
283         encodedlen = CtdlEncodeBase64(
284                 encoded,
285                 Msg->pCurrRelay->User,
286                 strlen(Msg->pCurrRelay->User),
287                 0);
288         if (encoded[encodedlen - 1] == '\n') {
289                 encodedlen --;
290                 encoded[encodedlen] = '\0';
291         }
292
293         StrBufPlain(Msg->IO.SendBuf.Buf,
294                     encoded,
295                     encodedlen);
296
297         StrBufAppendBufPlain(Msg->IO.SendBuf.Buf,
298                              HKEY("\r\n"), 0);
299
300         SMTP_DBG_SEND();
301
302         return eReadMessage;
303 }
304 eNextState SMTPC_read_auth_plain_reply_1(SmtpOutMsg *Msg)
305 {
306         AsyncIO *IO = &Msg->IO;
307         /* Do an AUTH command if necessary */
308
309         SMTP_DBG_READ();
310
311         if (!SMTP_IS_STATE('3'))
312                 SMTP_VERROR(5);
313         return eSendReply;
314 }
315
316
317 eNextState SMTPC_send_authplain_2(SmtpOutMsg *Msg)
318 {
319         AsyncIO *IO = &Msg->IO;
320         char buf[SIZ];
321         char encoded[1024];
322         long encodedlen;
323
324         sprintf(buf, "%s",
325                 Msg->pCurrRelay->Pass);
326         
327         encodedlen = CtdlEncodeBase64(
328                 encoded,
329                 Msg->pCurrRelay->Pass,
330                 strlen(Msg->pCurrRelay->Pass),
331                 0);
332
333         if (encoded[encodedlen - 1] == '\n') {
334                 encodedlen --;
335                 encoded[encodedlen] = '\0';
336         }
337
338         StrBufPlain(Msg->IO.SendBuf.Buf,
339                     encoded,
340                     encodedlen);
341
342         StrBufAppendBufPlain(Msg->IO.SendBuf.Buf,
343                              HKEY("\r\n"), 0);
344
345         SMTP_DBG_SEND();
346
347         return eReadMessage;
348 }
349 eNextState SMTPC_read_auth_plain_reply_2(SmtpOutMsg *Msg)
350 {
351         AsyncIO *IO = &Msg->IO;
352         /* Do an AUTH command if necessary */
353
354         SMTP_DBG_READ();
355
356         if (!SMTP_IS_STATE('2')) {
357                 if (SMTP_IS_STATE('4'))
358                         SMTP_VERROR(4);
359                 else
360                         SMTP_VERROR(5);
361         }
362         return eSendReply;
363 }
364
365 eNextState SMTPC_send_FROM(SmtpOutMsg *Msg)
366 {
367         AsyncIO *IO = &Msg->IO;
368         /* previous command succeeded, now try the MAIL FROM: command */
369         StrBufPrintf(Msg->IO.SendBuf.Buf,
370                      "MAIL FROM:<%s>\r\n",
371                      Msg->envelope_from);
372
373         SMTP_DBG_SEND();
374         return eReadMessage;
375 }
376
377 eNextState SMTPC_read_FROM_reply(SmtpOutMsg *Msg)
378 {
379         AsyncIO *IO = &Msg->IO;
380         SMTP_DBG_READ();
381
382         if (!SMTP_IS_STATE('2')) {
383                 if (SMTP_IS_STATE('4'))
384                         SMTP_VERROR(4);
385                 else
386                         SMTP_VERROR(5);
387         }
388         return eSendReply;
389 }
390
391
392 eNextState SMTPC_send_RCPT(SmtpOutMsg *Msg)
393 {
394         AsyncIO *IO = &Msg->IO;
395         /* MAIL succeeded, now try the RCPT To: command */
396         StrBufPrintf(Msg->IO.SendBuf.Buf,
397                      "RCPT TO:<%s@%s>\r\n",
398                      Msg->user,
399                      Msg->node);
400
401         SMTP_DBG_SEND();
402         return eReadMessage;
403 }
404
405 eNextState SMTPC_read_RCPT_reply(SmtpOutMsg *Msg)
406 {
407         AsyncIO *IO = &Msg->IO;
408         SMTP_DBG_READ();
409
410         if (!SMTP_IS_STATE('2')) {
411                 if (SMTP_IS_STATE('4'))
412                         SMTP_VERROR(4);
413                 else
414                         SMTP_VERROR(5);
415         }
416         return eSendReply;
417 }
418
419 eNextState SMTPC_send_DATAcmd(SmtpOutMsg *Msg)
420 {
421         AsyncIO *IO = &Msg->IO;
422         /* RCPT succeeded, now try the DATA command */
423         StrBufPlain(Msg->IO.SendBuf.Buf,
424                     HKEY("DATA\r\n"));
425
426         SMTP_DBG_SEND();
427         return eReadMessage;
428 }
429
430 eNextState SMTPC_read_DATAcmd_reply(SmtpOutMsg *Msg)
431 {
432         AsyncIO *IO = &Msg->IO;
433         SMTP_DBG_READ();
434
435         if (!SMTP_IS_STATE('3')) {
436                 SetSMTPState(IO, eSTMPfailOne);
437                 if (SMTP_IS_STATE('4'))
438                         SMTP_VERROR(3);
439                 else
440                         SMTP_VERROR(5);
441         }
442         SetSMTPState(IO, eSTMPsmtpdata);
443         return eSendReply;
444 }
445
446 eNextState SMTPC_send_data_body(SmtpOutMsg *Msg)
447 {
448         StrBuf *Buf;
449         /* If we reach this point, the server is expecting data.*/
450
451         Buf = Msg->IO.SendBuf.Buf;
452         Msg->IO.SendBuf.Buf = Msg->msgtext;
453         Msg->msgtext = Buf;
454         /* 
455          * sending the message itself doesn't use this state machine.
456          * so we have to operate it here by ourselves.
457          */
458         Msg->State ++;
459
460         return eSendMore;
461 }
462
463 eNextState SMTPC_send_terminate_data_body(SmtpOutMsg *Msg)
464 {
465         StrBuf *Buf;
466
467         Buf = Msg->IO.SendBuf.Buf;
468         Msg->IO.SendBuf.Buf = Msg->msgtext;
469         Msg->msgtext = Buf;
470
471         StrBufPlain(Msg->IO.SendBuf.Buf,
472                     HKEY(".\r\n"));
473
474         return eReadMessage;
475
476 }
477
478 eNextState SMTPC_read_data_body_reply(SmtpOutMsg *Msg)
479 {
480         AsyncIO *IO = &Msg->IO;
481         SMTP_DBG_READ();
482
483         if (!SMTP_IS_STATE('2')) {
484                 if (SMTP_IS_STATE('4'))
485                         SMTP_VERROR(4);
486                 else
487                         SMTP_VERROR(5);
488         }
489
490         SetSMTPState(IO, eSTMPsmtpdone);
491         /* We did it! */
492         StrBufPlain(Msg->MyQEntry->StatusMessage,
493                     &ChrPtr(Msg->IO.RecvBuf.Buf)[4],
494                     StrLength(Msg->IO.RecvBuf.Buf) - 4);
495         StrBufTrim(Msg->MyQEntry->StatusMessage);
496         Msg->MyQEntry->Status = 2;
497         return eSendReply;
498 }
499
500 eNextState SMTPC_send_QUIT(SmtpOutMsg *Msg)
501 {
502         AsyncIO *IO = &Msg->IO;
503         StrBufPlain(Msg->IO.SendBuf.Buf,
504                     HKEY("QUIT\r\n"));
505
506         SMTP_DBG_SEND();
507         return eReadMessage;
508 }
509
510 eNextState SMTPC_read_QUIT_reply(SmtpOutMsg *Msg)
511 {
512         AsyncIO *IO = &Msg->IO;
513         SMTP_DBG_READ();
514
515         EVS_syslog(LOG_DEBUG,
516                    "delivery to <%s> @ <%s> (%s) succeeded\n",
517                    Msg->user,
518                    Msg->node,
519                    Msg->name);
520
521         return eTerminateConnection;
522 }
523
524 eNextState SMTPC_read_dummy(SmtpOutMsg *Msg)
525 {
526         return eSendReply;
527 }
528
529 eNextState SMTPC_send_dummy(SmtpOutMsg *Msg)
530 {
531         return eReadMessage;
532 }
533
534 /*****************************************************************************/
535 /*                     SMTP CLIENT DISPATCHER                                */
536 /*****************************************************************************/
537 SMTPReadHandler ReadHandlers[eMaxSMTPC] = {
538         SMTPC_read_greeting,
539         SMTPC_read_EHLO_reply,
540         SMTPC_read_HELO_reply,
541         SMTPC_read_auth_reply,
542         SMTPC_read_auth_plain_reply_1,
543         SMTPC_read_auth_plain_reply_2,
544         SMTPC_read_FROM_reply,
545         SMTPC_read_RCPT_reply,
546         SMTPC_read_DATAcmd_reply,
547         SMTPC_read_dummy,
548         SMTPC_read_data_body_reply,
549         SMTPC_read_QUIT_reply
550 };
551 SMTPSendHandler SendHandlers[eMaxSMTPC] = {
552         SMTPC_send_dummy, /* we don't send a greeting, the server does... */
553         SMTPC_send_EHLO,
554         STMPC_send_HELO,
555         SMTPC_send_auth,
556         SMTPC_send_authplain_1,
557         SMTPC_send_authplain_2,
558         SMTPC_send_FROM,
559         SMTPC_send_RCPT,
560         SMTPC_send_DATAcmd,
561         SMTPC_send_data_body,
562         SMTPC_send_terminate_data_body,
563         SMTPC_send_QUIT
564 };
565
566 const double SMTP_C_ConnTimeout = 300.; /* wail 1 minute for connections... */
567
568 const double SMTP_C_ReadTimeouts[eMaxSMTPC] = {
569         300., /* Greeting... */
570         30., /* EHLO */
571         30., /* HELO */
572         30., /* Auth */
573         30., /* Auth */
574         30., /* Auth */
575         30., /* From */
576         90., /* RCPT */
577         30., /* DATA */
578         90., /* DATABody */
579         90., /* end of body... */
580         30.  /* QUIT */
581 };
582 const double SMTP_C_SendTimeouts[eMaxSMTPC] = {
583         90., /* Greeting... */
584         30., /* EHLO */
585         30., /* HELO */
586         30., /* Auth */
587         30., /* Auth */
588         30., /* Auth */
589         30., /* From */
590         30., /* RCPT */
591         30., /* DATA */
592         90., /* DATABody */
593         900., /* end of body... */
594         30.  /* QUIT */
595 };
596
597 const ConstStr ReadErrors[eMaxSMTPC + 1] = {
598         {HKEY("Connection broken during SMTP conversation")},
599         {HKEY("Connection broken during SMTP EHLO")},
600         {HKEY("Connection broken during SMTP HELO")},
601         {HKEY("Connection broken during SMTP AUTH")},
602         {HKEY("Connection broken during SMTP AUTH PLAIN I")},
603         {HKEY("Connection broken during SMTP AUTH PLAIN II")},
604         {HKEY("Connection broken during SMTP MAIL FROM")},
605         {HKEY("Connection broken during SMTP RCPT")},
606         {HKEY("Connection broken during SMTP DATA")},
607         {HKEY("Connection broken during SMTP message transmit")},
608         {HKEY("Connection broken during SMTP message transmit")},/* quit reply, don't care. */
609         {HKEY("Connection broken during SMTP message transmit")},/* quit reply, don't care. */
610         {HKEY("")}/* quit reply, don't care. */
611 };
612
613
614
615
616
617 int smtp_resolve_recipients(SmtpOutMsg *Msg)
618 {
619         AsyncIO *IO = &Msg->IO;
620         const char *ptr;
621         char buf[1024];
622         int scan_done;
623         int lp, rp;
624         int i;
625
626         EVNCS_syslog(LOG_DEBUG, "%s\n", __FUNCTION__);
627
628         if ((Msg==NULL) ||
629             (Msg->MyQEntry == NULL) ||
630             (StrLength(Msg->MyQEntry->Recipient) == 0)) {
631                 return 0;
632         }
633
634         /* Parse out the host portion of the recipient address */
635         process_rfc822_addr(ChrPtr(Msg->MyQEntry->Recipient),
636                             Msg->user,
637                             Msg->node,
638                             Msg->name);
639
640         EVNCS_syslog(LOG_DEBUG,
641                      "Attempting delivery to <%s> @ <%s> (%s)\n",
642                      Msg->user,
643                      Msg->node,
644                      Msg->name);
645
646         /* If no envelope_from is supplied, extract one from the message */
647         Msg->envelope_from = ChrPtr(Msg->MyQItem->EnvelopeFrom);
648         if ( (Msg->envelope_from == NULL) ||
649              (IsEmptyStr(Msg->envelope_from)) ) {
650                 Msg->mailfrom[0] = '\0';
651                 scan_done = 0;
652                 ptr = ChrPtr(Msg->msgtext);
653                 do {
654                         if (ptr = cmemreadline(ptr, buf, sizeof buf), *ptr == 0)
655                         {
656                                 scan_done = 1;
657                         }
658                         if (!strncasecmp(buf, "From:", 5))
659                         {
660                                 safestrncpy(Msg->mailfrom,
661                                             &buf[5],
662                                             sizeof Msg->mailfrom);
663
664                                 striplt(Msg->mailfrom);
665                                 for (i=0; Msg->mailfrom[i]; ++i) {
666                                         if (!isprint(Msg->mailfrom[i]))
667                                         {
668                                                 strcpy(&Msg->mailfrom[i],
669                                                        &Msg->mailfrom[i+1]);
670                                                 i=0;
671                                         }
672                                 }
673
674                                 /* Strip out parenthesized names */
675                                 lp = (-1);
676                                 rp = (-1);
677                                 for (i=0;
678                                      !IsEmptyStr(Msg->mailfrom + i);
679                                      ++i)
680                                 {
681                                         if (Msg->mailfrom[i] == '(') lp = i;
682                                         if (Msg->mailfrom[i] == ')') rp = i;
683                                 }
684                                 if ((lp>0)&&(rp>lp))
685                                 {
686                                         strcpy(&Msg->mailfrom[lp-1],
687                                                &Msg->mailfrom[rp+1]);
688                                 }
689
690                                 /* Prefer brokketized names */
691                                 lp = (-1);
692                                 rp = (-1);
693                                 for (i=0;
694                                      !IsEmptyStr(Msg->mailfrom + i);
695                                      ++i)
696                                 {
697                                         if (Msg->mailfrom[i] == '<') lp = i;
698                                         if (Msg->mailfrom[i] == '>') rp = i;
699                                 }
700                                 if ( (lp>=0) && (rp>lp) ) {
701                                         Msg->mailfrom[rp] = 0;
702                                         memmove(Msg->mailfrom,
703                                                 &Msg->mailfrom[lp + 1],
704                                                 rp - lp);
705                                 }
706
707                                 scan_done = 1;
708                         }
709                 } while (scan_done == 0);
710                 if (IsEmptyStr(Msg->mailfrom))
711                         strcpy(Msg->mailfrom, "someone@somewhere.org");
712
713                 stripallbut(Msg->mailfrom, '<', '>');
714                 Msg->envelope_from = Msg->mailfrom;
715         }
716
717         return 1;
718 }