3333 * SUCH DAMAGE.
3434 */
3535
36+ #include "dfcompat.h"
37+
38+ #include <ctype.h>
3639#include <errno.h>
3740#include <inttypes.h>
3841#include <signal.h>
@@ -341,19 +344,43 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
341344 goto again ;
342345}
343346
347+ static int
348+ writeline (struct queue * queue , const char * line , ssize_t linelen )
349+ {
350+ ssize_t len ;
351+
352+ while (linelen > 0 ) {
353+ len = linelen ;
354+ if (linelen > 1000 ) {
355+ len = 990 ;
356+ }
357+ if (fwrite (line , len , 1 , queue -> mailf ) != 1 )
358+ return (-1 );
359+ if (linelen <= 1000 )
360+ break ;
361+ if (fwrite ("\n" , 1 , 1 , queue -> mailf ) != 1 )
362+ return (-1 );
363+ line += 990 ;
364+ linelen = strlen (line );
365+ }
366+ return (0 );
367+ }
368+
344369int
345370readmail (struct queue * queue , int nodot , int recp_from_header )
346371{
347372 struct parse_state parse_state ;
348- char line [1000 ]; /* by RFC2822 */
349- size_t linelen ;
373+ char * line = NULL ;
374+ ssize_t linelen ;
375+ size_t linecap = 0 ;
376+ char newline [1000 ];
350377 size_t error ;
351378 int had_headers = 0 ;
352379 int had_from = 0 ;
353380 int had_messagid = 0 ;
354381 int had_date = 0 ;
355- int had_last_line = 0 ;
356382 int nocopy = 0 ;
383+ int ret = -1 ;
357384
358385 parse_state .state = NONE ;
359386
@@ -372,24 +399,15 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
372399 return (-1 );
373400
374401 while (!feof (stdin )) {
375- if (fgets (line , sizeof (line ) - 1 , stdin ) == NULL )
402+ newline [0 ] = '\0' ;
403+ if ((linelen = getline (& line , & linecap , stdin )) <= 0 )
376404 break ;
377- if (had_last_line )
378- errlogx (EX_DATAERR , "bad mail input format:"
379- " from %s (uid %d) (envelope-from %s)" ,
380- username , useruid , queue -> sender );
381- linelen = strlen (line );
382- if (linelen == 0 || line [linelen - 1 ] != '\n' ) {
383- /*
384- * This line did not end with a newline character.
385- * If we fix it, it better be the last line of
386- * the file.
387- */
388- line [linelen ] = '\n' ;
389- line [linelen + 1 ] = 0 ;
390- had_last_line = 1 ;
391- }
392405 if (!had_headers ) {
406+ if (linelen > 1000 )
407+ errlogx (EX_DATAERR , "bad mail input format:"
408+ " from %s (uid %d) (envelope-from %s)" ,
409+ username , useruid , queue -> sender );
410+
393411 /*
394412 * Unless this is a continuation, switch of
395413 * the Bcc: nocopy flag.
@@ -430,31 +448,39 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
430448 while (!had_date || !had_messagid || !had_from ) {
431449 if (!had_date ) {
432450 had_date = 1 ;
433- snprintf (line , sizeof (line ), "Date: %s\n" , rfc822date ());
451+ snprintf (newline , sizeof (newline ), "Date: %s\n" , rfc822date ());
434452 } else if (!had_messagid ) {
435453 /* XXX msgid, assign earlier and log? */
436454 had_messagid = 1 ;
437- snprintf (line , sizeof (line ), "Message-Id: <%" PRIxMAX ".%s.%" PRIxMAX "@%s>\n" ,
455+ snprintf (newline , sizeof (newline ), "Message-Id: <%" PRIxMAX ".%s.%" PRIxMAX "@%s>\n" ,
438456 (uintmax_t )time (NULL ),
439457 queue -> id ,
440458 (uintmax_t )random (),
441459 hostname ());
442460 } else if (!had_from ) {
443461 had_from = 1 ;
444- snprintf (line , sizeof (line ), "From: <%s>\n" , queue -> sender );
462+ snprintf (newline , sizeof (newline ), "From: <%s>\n" , queue -> sender );
445463 }
446- if (fwrite (line , strlen (line ), 1 , queue -> mailf ) != 1 )
447- return ( -1 ) ;
464+ if (fwrite (newline , strlen (newline ), 1 , queue -> mailf ) != 1 )
465+ goto fail ;
448466 }
449- strcpy ( line , "\n" );
467+ strlcpy ( newline , "\n" , sizeof ( newline ) );
450468 }
451469 if (!nodot && linelen == 2 && line [0 ] == '.' )
452470 break ;
453471 if (!nocopy ) {
454- if (fwrite (line , strlen (line ), 1 , queue -> mailf ) != 1 )
455- return (-1 );
472+ if (newline [0 ]) {
473+ if (fwrite (newline , strlen (newline ), 1 , queue -> mailf ) != 1 )
474+ goto fail ;
475+ } else {
476+ if (writeline (queue , line , linelen ) != 0 )
477+ goto fail ;
478+ }
456479 }
457480 }
458481
459- return (0 );
482+ ret = 0
483+ fail :
484+ free (line );
485+ return (ret );
460486}
0 commit comments