Fossil SCM

Improve the conformance to rfc2822 for generated email messages.

drh 2018-06-30 15:37 trunk
Commit 429ae9b73674f796ffe840df1841fa6be3f207e52d88eefa239c6ec88ea61169
1 file changed +27 -12
+27 -12
--- src/email.c
+++ src/email.c
@@ -322,11 +322,11 @@
322322
|| (c==' ' && zIn[0]!='\r' && zIn[0]!='\n')
323323
){
324324
blob_append_char(pOut, c);
325325
iCol++;
326326
if( iCol>=70 ){
327
- blob_append(pOut, "=\n", 2);
327
+ blob_append(pOut, "=\r\n", 3);
328328
iCol = 0;
329329
}
330330
}else if( c=='\r' && zIn[0]=='\n' ){
331331
zIn++;
332332
blob_append(pOut, "\r\n", 2);
@@ -513,19 +513,23 @@
513513
** "In-Reply-To:".
514514
**
515515
** This routine will add fields to the header as follows:
516516
**
517517
** From:
518
+** Date:
519
+** Message-Id:
518520
** Content-Type:
519521
** Content-Transfer-Encoding:
520522
**
521523
** The caller maintains ownership of the input Blobs. This routine will
522524
** read the Blobs and send them onward to the email system, but it will
523525
** not free them.
524526
*/
525527
void email_send(EmailSender *p, Blob *pHdr, Blob *pBody){
526528
Blob all, *pOut;
529
+ char *zDate;
530
+ u64 r1, r2;
527531
if( fossil_strcmp(p->zDest, "off")==0 ){
528532
return;
529533
}
530534
if( fossil_strcmp(p->zDest, "blob")==0 ){
531535
pOut = &p->out;
@@ -535,11 +539,18 @@
535539
}else{
536540
blob_init(&all, 0, 0);
537541
pOut = &all;
538542
}
539543
blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
540
- blob_appendf(pOut, "From: %s\r\n", p->zFrom);
544
+ blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
545
+ blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
546
+ /* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is
547
+ ** the current unix-time in hex, $(random) is a 64-bit random number,
548
+ ** and $(from) is the sender. */
549
+ sqlite3_randomness(sizeof(r1), &r1);
550
+ r2 = time(0);
551
+ blob_appendf(pOut, "Message-Id: <%llxx%016llx.%s>\r\n", r2, r1, p->zFrom);
541552
blob_add_final_newline(pBody);
542553
blob_appendf(pOut,"Content-Type: text/plain\r\n");
543554
#if 0
544555
blob_appendf(pOut, "Content-Transfer-Encoding: base64\r\n\r\n");
545556
append_base64(pOut, pBody);
@@ -569,11 +580,12 @@
569580
}else if( p->zDir ){
570581
char *zFile = emailTempFilename(p->zDir);
571582
blob_write_to_file(&all, zFile);
572583
fossil_free(zFile);
573584
}else if( strcmp(p->zDest, "stdout")==0 ){
574
- fossil_print("%s\n", blob_str(&all));
585
+ blob_add_final_newline(&all);
586
+ fossil_print("%s", blob_str(&all));
575587
}
576588
blob_zero(&all);
577589
}
578590
579591
/*
@@ -741,15 +753,18 @@
741753
EmailSender *pSender;
742754
verify_all_options();
743755
blob_init(&prompt, 0, 0);
744756
blob_init(&body, 0, 0);
745757
blob_init(&hdr, 0, 0);
758
+ blob_appendf(&hdr,"To: ");
746759
for(i=3; i<g.argc; i++){
747
- blob_appendf(&hdr, "To: %s\n", g.argv[i]);
760
+ if( i>3 ) blob_append(&hdr, ", ", 2);
761
+ blob_appendf(&hdr, "<%s>", g.argv[i]);
748762
}
763
+ blob_append(&hdr,"\r\n",2);
749764
if( zSubject ){
750
- blob_appendf(&hdr, "Subject: %s\n", zSubject);
765
+ blob_appendf(&hdr, "Subject: %s\r\n", zSubject);
751766
}
752767
if( zSource ){
753768
blob_read_from_file(&body, zSource, ExtFILE);
754769
}else{
755770
prompt_for_user_comment(&body, &prompt);
@@ -1416,12 +1431,12 @@
14161431
** been submitted. Send the appropriate email. */
14171432
Blob hdr, body;
14181433
EmailSender *pSender = email_sender_new(0,0);
14191434
blob_init(&hdr,0,0);
14201435
blob_init(&body,0,0);
1421
- blob_appendf(&hdr, "To: %s\n", zEAddr);
1422
- blob_appendf(&hdr, "Subject: Unsubscribe Instructions\n");
1436
+ blob_appendf(&hdr, "To: <%s>\r\n", zEAddr);
1437
+ blob_appendf(&hdr, "Subject: Unsubscribe Instructions\r\n");
14231438
blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/,
14241439
g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode);
14251440
email_send(pSender, &hdr, &body);
14261441
style_header("Unsubscribe Instructions Sent");
14271442
if( pSender->zErr ){
@@ -1803,12 +1818,12 @@
18031818
const char *zEmail = db_column_text(&q, 1);
18041819
int nHit = 0;
18051820
for(p=pEvents; p; p=p->pNext){
18061821
if( strchr(zSub,p->type)==0 ) continue;
18071822
if( nHit==0 ){
1808
- blob_appendf(&hdr,"To: %s\n", zEmail);
1809
- blob_appendf(&hdr,"Subject: %s activity alert\n", zRepoName);
1823
+ blob_appendf(&hdr,"To: <%s>\r\n", zEmail);
1824
+ blob_appendf(&hdr,"Subject: %s activity alert\r\n", zRepoName);
18101825
blob_appendf(&body,
18111826
"This is an automated email sent by the Fossil repository "
18121827
"at %s to report changes.\n",
18131828
zUrl
18141829
);
@@ -1900,11 +1915,11 @@
19001915
&& captcha_is_correct(0)
19011916
){
19021917
Blob hdr, body;
19031918
EmailSender *pSender = email_sender_new(0,0);
19041919
blob_init(&hdr, 0, 0);
1905
- blob_appendf(&hdr, "To: %s\nSubject: %s administrator message\n",
1920
+ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s administrator message\r\n",
19061921
zAdminEmail, db_get("email-subname","Fossil Repo"));
19071922
blob_init(&body, 0, 0);
19081923
blob_appendf(&body, "Message from [%s]\n", PT("from")/*safe-for-%s*/);
19091924
blob_appendf(&body, "Subject: [%s]\n\n", PT("subject")/*safe-for-%s*/);
19101925
blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
@@ -1987,11 +2002,11 @@
19872002
blob_init(&body, 0, 0);
19882003
blob_init(&hdr, 0, 0);
19892004
blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
19902005
pSender = email_sender_new(bTest2 ? "blob" : 0, 0);
19912006
if( zTo[0] ){
1992
- blob_appendf(&hdr, "To: %s\nSubject: %s %s\n", zTo, zSub, zSubject);
2007
+ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
19932008
email_send(pSender, &hdr, &body);
19942009
}
19952010
if( bAll || bAA ){
19962011
Stmt q;
19972012
int nUsed = blob_size(&body);
@@ -2001,11 +2016,11 @@
20012016
bAll ? "" : " AND ssub LIKE '%a%'");
20022017
while( db_step(&q)==SQLITE_ROW ){
20032018
const char *zCode = db_column_text(&q, 1);
20042019
zTo = db_column_text(&q, 0);
20052020
blob_truncate(&hdr, 0);
2006
- blob_appendf(&hdr, "To: %s\nSubject: %s %s\n", zTo, zSub, zSubject);
2021
+ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
20072022
if( zURL ){
20082023
blob_truncate(&body, nUsed);
20092024
blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
20102025
zURL, zCode);
20112026
}
20122027
--- src/email.c
+++ src/email.c
@@ -322,11 +322,11 @@
322 || (c==' ' && zIn[0]!='\r' && zIn[0]!='\n')
323 ){
324 blob_append_char(pOut, c);
325 iCol++;
326 if( iCol>=70 ){
327 blob_append(pOut, "=\n", 2);
328 iCol = 0;
329 }
330 }else if( c=='\r' && zIn[0]=='\n' ){
331 zIn++;
332 blob_append(pOut, "\r\n", 2);
@@ -513,19 +513,23 @@
513 ** "In-Reply-To:".
514 **
515 ** This routine will add fields to the header as follows:
516 **
517 ** From:
 
 
518 ** Content-Type:
519 ** Content-Transfer-Encoding:
520 **
521 ** The caller maintains ownership of the input Blobs. This routine will
522 ** read the Blobs and send them onward to the email system, but it will
523 ** not free them.
524 */
525 void email_send(EmailSender *p, Blob *pHdr, Blob *pBody){
526 Blob all, *pOut;
 
 
527 if( fossil_strcmp(p->zDest, "off")==0 ){
528 return;
529 }
530 if( fossil_strcmp(p->zDest, "blob")==0 ){
531 pOut = &p->out;
@@ -535,11 +539,18 @@
535 }else{
536 blob_init(&all, 0, 0);
537 pOut = &all;
538 }
539 blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
540 blob_appendf(pOut, "From: %s\r\n", p->zFrom);
 
 
 
 
 
 
 
541 blob_add_final_newline(pBody);
542 blob_appendf(pOut,"Content-Type: text/plain\r\n");
543 #if 0
544 blob_appendf(pOut, "Content-Transfer-Encoding: base64\r\n\r\n");
545 append_base64(pOut, pBody);
@@ -569,11 +580,12 @@
569 }else if( p->zDir ){
570 char *zFile = emailTempFilename(p->zDir);
571 blob_write_to_file(&all, zFile);
572 fossil_free(zFile);
573 }else if( strcmp(p->zDest, "stdout")==0 ){
574 fossil_print("%s\n", blob_str(&all));
 
575 }
576 blob_zero(&all);
577 }
578
579 /*
@@ -741,15 +753,18 @@
741 EmailSender *pSender;
742 verify_all_options();
743 blob_init(&prompt, 0, 0);
744 blob_init(&body, 0, 0);
745 blob_init(&hdr, 0, 0);
 
746 for(i=3; i<g.argc; i++){
747 blob_appendf(&hdr, "To: %s\n", g.argv[i]);
 
748 }
 
749 if( zSubject ){
750 blob_appendf(&hdr, "Subject: %s\n", zSubject);
751 }
752 if( zSource ){
753 blob_read_from_file(&body, zSource, ExtFILE);
754 }else{
755 prompt_for_user_comment(&body, &prompt);
@@ -1416,12 +1431,12 @@
1416 ** been submitted. Send the appropriate email. */
1417 Blob hdr, body;
1418 EmailSender *pSender = email_sender_new(0,0);
1419 blob_init(&hdr,0,0);
1420 blob_init(&body,0,0);
1421 blob_appendf(&hdr, "To: %s\n", zEAddr);
1422 blob_appendf(&hdr, "Subject: Unsubscribe Instructions\n");
1423 blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/,
1424 g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode);
1425 email_send(pSender, &hdr, &body);
1426 style_header("Unsubscribe Instructions Sent");
1427 if( pSender->zErr ){
@@ -1803,12 +1818,12 @@
1803 const char *zEmail = db_column_text(&q, 1);
1804 int nHit = 0;
1805 for(p=pEvents; p; p=p->pNext){
1806 if( strchr(zSub,p->type)==0 ) continue;
1807 if( nHit==0 ){
1808 blob_appendf(&hdr,"To: %s\n", zEmail);
1809 blob_appendf(&hdr,"Subject: %s activity alert\n", zRepoName);
1810 blob_appendf(&body,
1811 "This is an automated email sent by the Fossil repository "
1812 "at %s to report changes.\n",
1813 zUrl
1814 );
@@ -1900,11 +1915,11 @@
1900 && captcha_is_correct(0)
1901 ){
1902 Blob hdr, body;
1903 EmailSender *pSender = email_sender_new(0,0);
1904 blob_init(&hdr, 0, 0);
1905 blob_appendf(&hdr, "To: %s\nSubject: %s administrator message\n",
1906 zAdminEmail, db_get("email-subname","Fossil Repo"));
1907 blob_init(&body, 0, 0);
1908 blob_appendf(&body, "Message from [%s]\n", PT("from")/*safe-for-%s*/);
1909 blob_appendf(&body, "Subject: [%s]\n\n", PT("subject")/*safe-for-%s*/);
1910 blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
@@ -1987,11 +2002,11 @@
1987 blob_init(&body, 0, 0);
1988 blob_init(&hdr, 0, 0);
1989 blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
1990 pSender = email_sender_new(bTest2 ? "blob" : 0, 0);
1991 if( zTo[0] ){
1992 blob_appendf(&hdr, "To: %s\nSubject: %s %s\n", zTo, zSub, zSubject);
1993 email_send(pSender, &hdr, &body);
1994 }
1995 if( bAll || bAA ){
1996 Stmt q;
1997 int nUsed = blob_size(&body);
@@ -2001,11 +2016,11 @@
2001 bAll ? "" : " AND ssub LIKE '%a%'");
2002 while( db_step(&q)==SQLITE_ROW ){
2003 const char *zCode = db_column_text(&q, 1);
2004 zTo = db_column_text(&q, 0);
2005 blob_truncate(&hdr, 0);
2006 blob_appendf(&hdr, "To: %s\nSubject: %s %s\n", zTo, zSub, zSubject);
2007 if( zURL ){
2008 blob_truncate(&body, nUsed);
2009 blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
2010 zURL, zCode);
2011 }
2012
--- src/email.c
+++ src/email.c
@@ -322,11 +322,11 @@
322 || (c==' ' && zIn[0]!='\r' && zIn[0]!='\n')
323 ){
324 blob_append_char(pOut, c);
325 iCol++;
326 if( iCol>=70 ){
327 blob_append(pOut, "=\r\n", 3);
328 iCol = 0;
329 }
330 }else if( c=='\r' && zIn[0]=='\n' ){
331 zIn++;
332 blob_append(pOut, "\r\n", 2);
@@ -513,19 +513,23 @@
513 ** "In-Reply-To:".
514 **
515 ** This routine will add fields to the header as follows:
516 **
517 ** From:
518 ** Date:
519 ** Message-Id:
520 ** Content-Type:
521 ** Content-Transfer-Encoding:
522 **
523 ** The caller maintains ownership of the input Blobs. This routine will
524 ** read the Blobs and send them onward to the email system, but it will
525 ** not free them.
526 */
527 void email_send(EmailSender *p, Blob *pHdr, Blob *pBody){
528 Blob all, *pOut;
529 char *zDate;
530 u64 r1, r2;
531 if( fossil_strcmp(p->zDest, "off")==0 ){
532 return;
533 }
534 if( fossil_strcmp(p->zDest, "blob")==0 ){
535 pOut = &p->out;
@@ -535,11 +539,18 @@
539 }else{
540 blob_init(&all, 0, 0);
541 pOut = &all;
542 }
543 blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr));
544 blob_appendf(pOut, "From: <%s>\r\n", p->zFrom);
545 blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0)));
546 /* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is
547 ** the current unix-time in hex, $(random) is a 64-bit random number,
548 ** and $(from) is the sender. */
549 sqlite3_randomness(sizeof(r1), &r1);
550 r2 = time(0);
551 blob_appendf(pOut, "Message-Id: <%llxx%016llx.%s>\r\n", r2, r1, p->zFrom);
552 blob_add_final_newline(pBody);
553 blob_appendf(pOut,"Content-Type: text/plain\r\n");
554 #if 0
555 blob_appendf(pOut, "Content-Transfer-Encoding: base64\r\n\r\n");
556 append_base64(pOut, pBody);
@@ -569,11 +580,12 @@
580 }else if( p->zDir ){
581 char *zFile = emailTempFilename(p->zDir);
582 blob_write_to_file(&all, zFile);
583 fossil_free(zFile);
584 }else if( strcmp(p->zDest, "stdout")==0 ){
585 blob_add_final_newline(&all);
586 fossil_print("%s", blob_str(&all));
587 }
588 blob_zero(&all);
589 }
590
591 /*
@@ -741,15 +753,18 @@
753 EmailSender *pSender;
754 verify_all_options();
755 blob_init(&prompt, 0, 0);
756 blob_init(&body, 0, 0);
757 blob_init(&hdr, 0, 0);
758 blob_appendf(&hdr,"To: ");
759 for(i=3; i<g.argc; i++){
760 if( i>3 ) blob_append(&hdr, ", ", 2);
761 blob_appendf(&hdr, "<%s>", g.argv[i]);
762 }
763 blob_append(&hdr,"\r\n",2);
764 if( zSubject ){
765 blob_appendf(&hdr, "Subject: %s\r\n", zSubject);
766 }
767 if( zSource ){
768 blob_read_from_file(&body, zSource, ExtFILE);
769 }else{
770 prompt_for_user_comment(&body, &prompt);
@@ -1416,12 +1431,12 @@
1431 ** been submitted. Send the appropriate email. */
1432 Blob hdr, body;
1433 EmailSender *pSender = email_sender_new(0,0);
1434 blob_init(&hdr,0,0);
1435 blob_init(&body,0,0);
1436 blob_appendf(&hdr, "To: <%s>\r\n", zEAddr);
1437 blob_appendf(&hdr, "Subject: Unsubscribe Instructions\r\n");
1438 blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/,
1439 g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode);
1440 email_send(pSender, &hdr, &body);
1441 style_header("Unsubscribe Instructions Sent");
1442 if( pSender->zErr ){
@@ -1803,12 +1818,12 @@
1818 const char *zEmail = db_column_text(&q, 1);
1819 int nHit = 0;
1820 for(p=pEvents; p; p=p->pNext){
1821 if( strchr(zSub,p->type)==0 ) continue;
1822 if( nHit==0 ){
1823 blob_appendf(&hdr,"To: <%s>\r\n", zEmail);
1824 blob_appendf(&hdr,"Subject: %s activity alert\r\n", zRepoName);
1825 blob_appendf(&body,
1826 "This is an automated email sent by the Fossil repository "
1827 "at %s to report changes.\n",
1828 zUrl
1829 );
@@ -1900,11 +1915,11 @@
1915 && captcha_is_correct(0)
1916 ){
1917 Blob hdr, body;
1918 EmailSender *pSender = email_sender_new(0,0);
1919 blob_init(&hdr, 0, 0);
1920 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s administrator message\r\n",
1921 zAdminEmail, db_get("email-subname","Fossil Repo"));
1922 blob_init(&body, 0, 0);
1923 blob_appendf(&body, "Message from [%s]\n", PT("from")/*safe-for-%s*/);
1924 blob_appendf(&body, "Subject: [%s]\n\n", PT("subject")/*safe-for-%s*/);
1925 blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
@@ -1987,11 +2002,11 @@
2002 blob_init(&body, 0, 0);
2003 blob_init(&hdr, 0, 0);
2004 blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/);
2005 pSender = email_sender_new(bTest2 ? "blob" : 0, 0);
2006 if( zTo[0] ){
2007 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
2008 email_send(pSender, &hdr, &body);
2009 }
2010 if( bAll || bAA ){
2011 Stmt q;
2012 int nUsed = blob_size(&body);
@@ -2001,11 +2016,11 @@
2016 bAll ? "" : " AND ssub LIKE '%a%'");
2017 while( db_step(&q)==SQLITE_ROW ){
2018 const char *zCode = db_column_text(&q, 1);
2019 zTo = db_column_text(&q, 0);
2020 blob_truncate(&hdr, 0);
2021 blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject);
2022 if( zURL ){
2023 blob_truncate(&body, nUsed);
2024 blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
2025 zURL, zCode);
2026 }
2027

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button