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>
@@ -333,26 +336,49 @@ parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
333336 ps -> pos = 0 ;
334337 addr = strdup (ps -> addr );
335338 if (addr == NULL )
336- errlog (EX_SOFTWARE , NULL );
339+ errlog (EX_SOFTWARE , "strdup" );
337340
338341 if (add_recp (queue , addr , EXPAND_WILDCARD ) != 0 )
339342 errlogx (EX_DATAERR , "invalid recipient `%s'" , addr );
340343
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 ;
357383
358384 parse_state .state = NONE ;
@@ -372,24 +398,15 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
372398 return (-1 );
373399
374400 while (!feof (stdin )) {
375- if (fgets (line , sizeof (line ) - 1 , stdin ) == NULL )
401+ newline [0 ] = '\0' ;
402+ if ((linelen = getline (& line , & linecap , stdin )) <= 0 )
376403 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- }
392404 if (!had_headers ) {
405+ if (linelen > 1000 )
406+ errlogx (EX_DATAERR , "bad mail input format:"
407+ " from %s (uid %d) (envelope-from %s)" ,
408+ username , useruid , queue -> sender );
409+
393410 /*
394411 * Unless this is a continuation, switch of
395412 * the Bcc: nocopy flag.
@@ -425,36 +442,44 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
425442 }
426443 }
427444
428- if (strcmp ( line , "\n" ) == 0 && !had_headers ) {
445+ if (line [ 0 ] == '\n' && !had_headers ) {
429446 had_headers = 1 ;
430447 while (!had_date || !had_messagid || !had_from ) {
431448 if (!had_date ) {
432449 had_date = 1 ;
433- snprintf (line , sizeof (line ), "Date: %s\n" , rfc822date ());
450+ snprintf (newline , sizeof (newline ), "Date: %s\n" , rfc822date ());
434451 } else if (!had_messagid ) {
435452 /* XXX msgid, assign earlier and log? */
436453 had_messagid = 1 ;
437- snprintf (line , sizeof (line ), "Message-Id: <%" PRIxMAX ".%s.%" PRIxMAX "@%s>\n" ,
454+ snprintf (newline , sizeof (newline ), "Message-Id: <%" PRIxMAX ".%s.%" PRIxMAX "@%s>\n" ,
438455 (uintmax_t )time (NULL ),
439456 queue -> id ,
440457 (uintmax_t )random (),
441458 hostname ());
442459 } else if (!had_from ) {
443460 had_from = 1 ;
444- snprintf (line , sizeof (line ), "From: <%s>\n" , queue -> sender );
461+ snprintf (newline , sizeof (newline ), "From: <%s>\n" , queue -> sender );
445462 }
446- if (fwrite (line , strlen (line ), 1 , queue -> mailf ) != 1 )
447- return ( -1 ) ;
463+ if (fwrite (newline , strlen (newline ), 1 , queue -> mailf ) != 1 )
464+ goto fail ;
448465 }
449- strcpy ( line , "\n" );
466+ strlcpy ( newline , "\n" , sizeof ( newline ) );
450467 }
451468 if (!nodot && linelen == 2 && line [0 ] == '.' )
452469 break ;
453470 if (!nocopy ) {
454- if (fwrite (line , strlen (line ), 1 , queue -> mailf ) != 1 )
455- return (-1 );
471+ if (newline [0 ] != '\0' ) {
472+ if (fwrite (newline , strlen (newline ), 1 , queue -> mailf ) != 1 )
473+ goto fail ;
474+ } else {
475+ if (writeline (queue , line , linelen ) != 0 )
476+ goto fail ;
477+ }
456478 }
457479 }
458480
459481 return (0 );
482+ fail :
483+ free (line );
484+ return (-1 );
460485}
0 commit comments