Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge fixes and improvements from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | smtp |
Files: | files | file ages | folders |
SHA3-256: |
4f30802a88425497819bf859a6c46e07 |
User & Date: | drh 2018-06-30 16:06:22.801 |
Context
2018-06-30
| ||
17:27 | Add "SMTP relay" as a new method for sending alert emails. ... (check-in: b96415f0 user: drh tags: smtp) | |
16:06 | Merge fixes and improvements from trunk. ... (check-in: 4f30802a user: drh tags: smtp) | |
15:40 | Fix harmless compiler warnings. ... (check-in: 50daa540 user: drh tags: trunk) | |
2018-06-29
| ||
22:54 | Populate the esubject column of the emailbox table based on the subject in the email header. ... (check-in: dbb1ce5f user: drh tags: smtp) | |
Changes
Changes to src/cgi.c.
︙ | ︙ | |||
1927 1928 1929 1930 1931 1932 1933 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; /* ** Returns an RFC822-formatted time string suitable for HTTP headers. ** The timezone is always GMT. The value returned is always a | | | | | 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; /* ** Returns an RFC822-formatted time string suitable for HTTP headers. ** The timezone is always GMT. The value returned is always a ** string obtained from mprintf() and must be freed using fossil_free() ** to avoid a memory leak. ** ** See http://www.faqs.org/rfcs/rfc822.html, section 5 ** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3. */ char *cgi_rfc822_datestamp(time_t now){ struct tm *pTm; pTm = gmtime(&now); if( pTm==0 ){ return mprintf(""); }else{ return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); } } /* ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return |
︙ | ︙ |
Changes to src/email.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ******************************************************************************* ** ** Logic for email notification, also known as "alerts". */ #include "config.h" #include "email.h" #include <assert.h> /* ** Maximum size of the subscriberCode blob, in bytes */ #define SUBSCRIBER_CODE_SZ 32 /* | > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ******************************************************************************* ** ** Logic for email notification, also known as "alerts". */ #include "config.h" #include "email.h" #include <assert.h> #include <time.h> /* ** Maximum size of the subscriberCode blob, in bytes */ #define SUBSCRIBER_CODE_SZ 32 /* |
︙ | ︙ | |||
320 321 322 323 324 325 326 | while( (c = *(zIn++))!=0 ){ if( (c>='!' && c<='~' && c!='=' && c!=':') || (c==' ' && zIn[0]!='\r' && zIn[0]!='\n') ){ blob_append_char(pOut, c); iCol++; if( iCol>=70 ){ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | while( (c = *(zIn++))!=0 ){ if( (c>='!' && c<='~' && c!='=' && c!=':') || (c==' ' && zIn[0]!='\r' && zIn[0]!='\n') ){ blob_append_char(pOut, c); iCol++; if( iCol>=70 ){ blob_append(pOut, "=\r\n", 3); iCol = 0; } }else if( c=='\r' && zIn[0]=='\n' ){ zIn++; blob_append(pOut, "\r\n", 2); iCol = 0; }else if( c=='\n' ){ |
︙ | ︙ | |||
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | ** in the header. Likewise, the header must contains a "Subject:" line. ** The header might also include fields like "Message-Id:" or ** "In-Reply-To:". ** ** This routine will add fields to the header as follows: ** ** From: ** Content-Type: ** Content-Transfer-Encoding: ** ** The caller maintains ownership of the input Blobs. This routine will ** read the Blobs and send them onward to the email system, but it will ** not free them. */ void email_send(EmailSender *p, Blob *pHdr, Blob *pBody){ Blob all, *pOut; if( fossil_strcmp(p->zDest, "off")==0 ){ return; } if( fossil_strcmp(p->zDest, "blob")==0 ){ pOut = &p->out; if( blob_size(pOut) ){ blob_appendf(pOut, "%.72c\n", '='); } }else{ blob_init(&all, 0, 0); pOut = &all; } blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr)); | > > > | > > > > > > > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | ** in the header. Likewise, the header must contains a "Subject:" line. ** The header might also include fields like "Message-Id:" or ** "In-Reply-To:". ** ** This routine will add fields to the header as follows: ** ** From: ** Date: ** Message-Id: ** Content-Type: ** Content-Transfer-Encoding: ** ** The caller maintains ownership of the input Blobs. This routine will ** read the Blobs and send them onward to the email system, but it will ** not free them. */ void email_send(EmailSender *p, Blob *pHdr, Blob *pBody){ Blob all, *pOut; u64 r1, r2; if( fossil_strcmp(p->zDest, "off")==0 ){ return; } if( fossil_strcmp(p->zDest, "blob")==0 ){ pOut = &p->out; if( blob_size(pOut) ){ blob_appendf(pOut, "%.72c\n", '='); } }else{ blob_init(&all, 0, 0); pOut = &all; } blob_append(pOut, blob_buffer(pHdr), blob_size(pHdr)); blob_appendf(pOut, "From: <%s>\r\n", p->zFrom); blob_appendf(pOut, "Date: %z\r\n", cgi_rfc822_datestamp(time(0))); /* Message-id format: "<$(date)x$(random).$(from)>" where $(date) is ** the current unix-time in hex, $(random) is a 64-bit random number, ** and $(from) is the sender. */ sqlite3_randomness(sizeof(r1), &r1); r2 = time(0); blob_appendf(pOut, "Message-Id: <%llxx%016llx.%s>\r\n", r2, r1, p->zFrom); blob_add_final_newline(pBody); blob_appendf(pOut,"Content-Type: text/plain\r\n"); #if 0 blob_appendf(pOut, "Content-Transfer-Encoding: base64\r\n\r\n"); append_base64(pOut, pBody); #else blob_appendf(pOut, "Content-Transfer-Encoding: quoted-printable\r\n\r\n"); |
︙ | ︙ | |||
567 568 569 570 571 572 573 | emailerError(p, "Could not open output pipe \"%s\"", p->zCmd); } }else if( p->zDir ){ char *zFile = emailTempFilename(p->zDir); blob_write_to_file(&all, zFile); fossil_free(zFile); }else if( strcmp(p->zDest, "stdout")==0 ){ | > | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | emailerError(p, "Could not open output pipe \"%s\"", p->zCmd); } }else if( p->zDir ){ char *zFile = emailTempFilename(p->zDir); blob_write_to_file(&all, zFile); fossil_free(zFile); }else if( strcmp(p->zDest, "stdout")==0 ){ blob_add_final_newline(&all); fossil_print("%s", blob_str(&all)); } blob_reset(&all); } /* ** Analyze and act on a received email. ** |
︙ | ︙ | |||
739 740 741 742 743 744 745 746 | const char *zSubject = find_option("subject", "S", 1); const char *zSource = find_option("body", 0, 1); EmailSender *pSender; verify_all_options(); blob_init(&prompt, 0, 0); blob_init(&body, 0, 0); blob_init(&hdr, 0, 0); for(i=3; i<g.argc; i++){ | > > | > | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 | const char *zSubject = find_option("subject", "S", 1); const char *zSource = find_option("body", 0, 1); EmailSender *pSender; verify_all_options(); blob_init(&prompt, 0, 0); blob_init(&body, 0, 0); blob_init(&hdr, 0, 0); blob_appendf(&hdr,"To: "); for(i=3; i<g.argc; i++){ if( i>3 ) blob_append(&hdr, ", ", 2); blob_appendf(&hdr, "<%s>", g.argv[i]); } blob_append(&hdr,"\r\n",2); if( zSubject ){ blob_appendf(&hdr, "Subject: %s\r\n", zSubject); } if( zSource ){ blob_read_from_file(&body, zSource, ExtFILE); }else{ prompt_for_user_comment(&body, &prompt); } blob_add_final_newline(&body); |
︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 | if( bSubmit ){ /* If we get this far, it means that a valid unsubscribe request has ** been submitted. Send the appropriate email. */ Blob hdr, body; EmailSender *pSender = email_sender_new(0,0); blob_init(&hdr,0,0); blob_init(&body,0,0); | | | | 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 | if( bSubmit ){ /* If we get this far, it means that a valid unsubscribe request has ** been submitted. Send the appropriate email. */ Blob hdr, body; EmailSender *pSender = email_sender_new(0,0); blob_init(&hdr,0,0); blob_init(&body,0,0); blob_appendf(&hdr, "To: <%s>\r\n", zEAddr); blob_appendf(&hdr, "Subject: Unsubscribe Instructions\r\n"); blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/, g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode); email_send(pSender, &hdr, &body); style_header("Unsubscribe Instructions Sent"); if( pSender->zErr ){ @ <h1>Internal Error</h1> @ <p>The following error was encountered while trying to send an |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 | const char *zCode = db_column_text(&q, 0); const char *zSub = db_column_text(&q, 2); const char *zEmail = db_column_text(&q, 1); int nHit = 0; for(p=pEvents; p; p=p->pNext){ if( strchr(zSub,p->type)==0 ) continue; if( nHit==0 ){ | | | | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 | const char *zCode = db_column_text(&q, 0); const char *zSub = db_column_text(&q, 2); const char *zEmail = db_column_text(&q, 1); int nHit = 0; for(p=pEvents; p; p=p->pNext){ if( strchr(zSub,p->type)==0 ) continue; if( nHit==0 ){ blob_appendf(&hdr,"To: <%s>\r\n", zEmail); blob_appendf(&hdr,"Subject: %s activity alert\r\n", zRepoName); blob_appendf(&body, "This is an automated email sent by the Fossil repository " "at %s to report changes.\n", zUrl ); } nHit++; |
︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 | && P("from")!=0 && cgi_csrf_safe(1) && captcha_is_correct(0) ){ Blob hdr, body; EmailSender *pSender = email_sender_new(0,0); blob_init(&hdr, 0, 0); | | | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | && P("from")!=0 && cgi_csrf_safe(1) && captcha_is_correct(0) ){ Blob hdr, body; EmailSender *pSender = email_sender_new(0,0); blob_init(&hdr, 0, 0); blob_appendf(&hdr, "To: <%s>\r\nSubject: %s administrator message\r\n", zAdminEmail, db_get("email-subname","Fossil Repo")); blob_init(&body, 0, 0); blob_appendf(&body, "Message from [%s]\n", PT("from")/*safe-for-%s*/); blob_appendf(&body, "Subject: [%s]\n\n", PT("subject")/*safe-for-%s*/); blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/); email_send(pSender, &hdr, &body); style_header("Message Sent"); |
︙ | ︙ | |||
1985 1986 1987 1988 1989 1990 1991 | int bTest2 = fossil_strcmp(P("name"),"test2")==0; Blob hdr, body; blob_init(&body, 0, 0); blob_init(&hdr, 0, 0); blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/); pSender = email_sender_new(bTest2 ? "blob" : 0, 0); if( zTo[0] ){ | | | | 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 | int bTest2 = fossil_strcmp(P("name"),"test2")==0; Blob hdr, body; blob_init(&body, 0, 0); blob_init(&hdr, 0, 0); blob_appendf(&body, "%s", PT("msg")/*safe-for-%s*/); pSender = email_sender_new(bTest2 ? "blob" : 0, 0); if( zTo[0] ){ blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject); email_send(pSender, &hdr, &body); } if( bAll || bAA ){ Stmt q; int nUsed = blob_size(&body); const char *zURL = db_get("email-url",0); db_prepare(&q, "SELECT semail, hex(subscriberCode) FROM subscriber " " WHERE sverified AND NOT sdonotcall %s", bAll ? "" : " AND ssub LIKE '%a%'"); while( db_step(&q)==SQLITE_ROW ){ const char *zCode = db_column_text(&q, 1); zTo = db_column_text(&q, 0); blob_truncate(&hdr, 0); blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n", zTo, zSub, zSubject); if( zURL ){ blob_truncate(&body, nUsed); blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n", zURL, zCode); } email_send(pSender, &hdr, &body); } |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 | if( g.isHTTP ){ rc = 0 /* avoid HTTP 500 */; } } else #endif { | | | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | if( g.isHTTP ){ rc = 0 /* avoid HTTP 500 */; } } else #endif { if( g.cgiOutput==1 && g.db ){ g.cgiOutput = 2; cgi_reset_content(); style_header("Bad Request"); @ <p class="generalError">%h(z)</p> cgi_set_status(400, "Bad Request"); style_footer(); cgi_reply(); |
︙ | ︙ |