Fossil SCM
Improved support for one-click unsubscribe for notifications.
Commit
bca95cbf9c2bf230efe14793f0389db34c6636d3b44b0863161a6997a6d84dcb
Parent
55151f0024d3852…
1 file changed
+48
-26
+48
-26
| --- src/alerts.c | ||
| +++ src/alerts.c | ||
| @@ -47,10 +47,11 @@ | ||
| 47 | 47 | @ -- The ssub field is a string where each character indicates a particular |
| 48 | 48 | @ -- type of event to subscribe to. Choices: |
| 49 | 49 | @ -- a - Announcements |
| 50 | 50 | @ -- c - Check-ins |
| 51 | 51 | @ -- f - Forum posts |
| 52 | +@ -- k - ** Special: Unsubscribed using /oneclickunsub | |
| 52 | 53 | @ -- n - New forum threads |
| 53 | 54 | @ -- r - Replies to my own forum posts |
| 54 | 55 | @ -- t - Ticket changes |
| 55 | 56 | @ -- w - Wiki changes |
| 56 | 57 | @ -- x - Edits to forum posts |
| @@ -86,11 +87,11 @@ | ||
| 86 | 87 | @ eventid TEXT PRIMARY KEY, -- Object that changed |
| 87 | 88 | @ sentSep BOOLEAN DEFAULT false, -- individual alert sent |
| 88 | 89 | @ sentDigest BOOLEAN DEFAULT false, -- digest alert sent |
| 89 | 90 | @ sentMod BOOLEAN DEFAULT false -- pending moderation alert sent |
| 90 | 91 | @ ) WITHOUT ROWID; |
| 91 | -@ | |
| 92 | +@ | |
| 92 | 93 | @ -- Obsolete table. No longer used. |
| 93 | 94 | @ DROP TABLE IF EXISTS repository.alert_bounce; |
| 94 | 95 | ; |
| 95 | 96 | |
| 96 | 97 | /* |
| @@ -875,11 +876,11 @@ | ||
| 875 | 876 | int nTo = 0; |
| 876 | 877 | char **azTo = 0; |
| 877 | 878 | Blob v; |
| 878 | 879 | char *z, *zAddr; |
| 879 | 880 | int i; |
| 880 | - | |
| 881 | + | |
| 881 | 882 | email_header_value(pMsg, "to", &v); |
| 882 | 883 | z = blob_str(&v); |
| 883 | 884 | for(i=0; z[i]; i++){ |
| 884 | 885 | if( z[i]=='<' && (zAddr = email_copy_addr(&z[i+1],'>'))!=0 ){ |
| 885 | 886 | azTo = fossil_realloc(azTo, sizeof(azTo[0])*(nTo+1) ); |
| @@ -889,11 +890,11 @@ | ||
| 889 | 890 | *pnTo = nTo; |
| 890 | 891 | *pazTo = azTo; |
| 891 | 892 | } |
| 892 | 893 | |
| 893 | 894 | /* |
| 894 | -** Free a list of To addresses obtained from a prior call to | |
| 895 | +** Free a list of To addresses obtained from a prior call to | |
| 895 | 896 | ** email_header_to() |
| 896 | 897 | */ |
| 897 | 898 | void email_header_to_free(int nTo, char **azTo){ |
| 898 | 899 | int i; |
| 899 | 900 | for(i=0; i<nTo; i++) fossil_free(azTo[i]); |
| @@ -915,11 +916,11 @@ | ||
| 915 | 916 | ** Message-Id: |
| 916 | 917 | ** Content-Type: |
| 917 | 918 | ** Content-Transfer-Encoding: |
| 918 | 919 | ** MIME-Version: |
| 919 | 920 | ** Sender: |
| 920 | -** | |
| 921 | +** | |
| 921 | 922 | ** The caller maintains ownership of the input Blobs. This routine will |
| 922 | 923 | ** read the Blobs and send them onward to the email system, but it will |
| 923 | 924 | ** not free them. |
| 924 | 925 | ** |
| 925 | 926 | ** The Message-Id: field is added if there is not already a Message-Id |
| @@ -928,11 +929,11 @@ | ||
| 928 | 929 | ** If the zFromName argument is not NULL, then it should be a human-readable |
| 929 | 930 | ** name or handle for the sender. In that case, "From:" becomes a made-up |
| 930 | 931 | ** email address based on a hash of zFromName and the domain of email-self, |
| 931 | 932 | ** and an additional "Sender:" field is inserted with the email-self |
| 932 | 933 | ** address. Downstream software might use the Sender header to set |
| 933 | -** the envelope-from address of the email. If zFromName is a NULL pointer, | |
| 934 | +** the envelope-from address of the email. If zFromName is a NULL pointer, | |
| 934 | 935 | ** then the "From:" is set to the email-self value and Sender is |
| 935 | 936 | ** omitted. |
| 936 | 937 | */ |
| 937 | 938 | void alert_send( |
| 938 | 939 | AlertSender *p, /* Emailer context */ |
| @@ -1045,11 +1046,11 @@ | ||
| 1045 | 1046 | ** a long-running server and will not be sending email notifications, |
| 1046 | 1047 | ** then leave this setting blank. |
| 1047 | 1048 | */ |
| 1048 | 1049 | /* |
| 1049 | 1050 | ** SETTING: email-admin width=40 |
| 1050 | -** This is the email address for the human administrator for the system. | |
| 1051 | +** This is the email address for the human administrator for the system. | |
| 1051 | 1052 | ** Abuse and trouble reports and password reset requests are send here. |
| 1052 | 1053 | */ |
| 1053 | 1054 | /* |
| 1054 | 1055 | ** SETTING: email-subname width=16 |
| 1055 | 1056 | ** This is a short name used to identifies the repository in the Subject: |
| @@ -1080,19 +1081,19 @@ | ||
| 1080 | 1081 | ** |
| 1081 | 1082 | ** email-renew-warning is the time (in days since 1970-01-01) when the |
| 1082 | 1083 | ** last batch of "your subscription is about to expire" emails were |
| 1083 | 1084 | ** sent out. |
| 1084 | 1085 | ** |
| 1085 | -** email-renew-cutoff is normally 7 days behind email-renew-warning. | |
| 1086 | +** email-renew-cutoff is normally 7 days behind email-renew-warning. | |
| 1086 | 1087 | */ |
| 1087 | 1088 | /* |
| 1088 | 1089 | ** SETTING: email-send-method width=5 default=off sensitive |
| 1089 | 1090 | ** Determine the method used to send email. Allowed values are |
| 1090 | 1091 | ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value |
| 1091 | 1092 | ** means no email is ever sent. The "relay" value means emails are sent |
| 1092 | 1093 | ** to an Mail Sending Agent using SMTP located at email-send-relayhost. |
| 1093 | -** The "pipe" value means email messages are piped into a command | |
| 1094 | +** The "pipe" value means email messages are piped into a command | |
| 1094 | 1095 | ** determined by the email-send-command setting. The "dir" value means |
| 1095 | 1096 | ** emails are written to individual files in a directory determined |
| 1096 | 1097 | ** by the email-send-dir setting. The "db" value means that emails |
| 1097 | 1098 | ** are added to an SQLite database named by the* email-send-db setting. |
| 1098 | 1099 | ** The "stdout" value writes email text to standard output, for debugging. |
| @@ -1133,11 +1134,11 @@ | ||
| 1133 | 1134 | */ |
| 1134 | 1135 | |
| 1135 | 1136 | |
| 1136 | 1137 | /* |
| 1137 | 1138 | ** COMMAND: alerts* |
| 1138 | -** | |
| 1139 | +** | |
| 1139 | 1140 | ** Usage: %fossil alerts SUBCOMMAND ARGS... |
| 1140 | 1141 | ** |
| 1141 | 1142 | ** Subcommands: |
| 1142 | 1143 | ** |
| 1143 | 1144 | ** pending Show all pending alerts. Useful for debugging. |
| @@ -1742,11 +1743,11 @@ | ||
| 1742 | 1743 | /* |
| 1743 | 1744 | ** Either shutdown or completely delete a subscription entry given |
| 1744 | 1745 | ** by the hex value zName. Then paint a webpage that explains that |
| 1745 | 1746 | ** the entry has been removed. |
| 1746 | 1747 | */ |
| 1747 | -static void alert_unsubscribe(int sid){ | |
| 1748 | +static void alert_unsubscribe(int sid, int bTotal){ | |
| 1748 | 1749 | const char *zEmail = 0; |
| 1749 | 1750 | const char *zLogin = 0; |
| 1750 | 1751 | int uid = 0; |
| 1751 | 1752 | Stmt q; |
| 1752 | 1753 | db_prepare(&q, "SELECT semail, suname FROM subscriber" |
| @@ -1759,13 +1760,24 @@ | ||
| 1759 | 1760 | style_set_current_feature("alerts"); |
| 1760 | 1761 | if( zEmail==0 ){ |
| 1761 | 1762 | style_header("Unsubscribe Fail"); |
| 1762 | 1763 | @ <p>Unable to locate a subscriber with the requested key</p> |
| 1763 | 1764 | }else{ |
| 1764 | - db_multi_exec( | |
| 1765 | - "DELETE FROM subscriber WHERE subscriberId=%d", sid | |
| 1766 | - ); | |
| 1765 | + db_unprotect(PROTECT_READONLY); | |
| 1766 | + if( bTotal ){ | |
| 1767 | + /* Completely delete the subscriber */ | |
| 1768 | + db_multi_exec( | |
| 1769 | + "DELETE FROM subscriber WHERE subscriberId=%d", sid | |
| 1770 | + ); | |
| 1771 | + }else{ | |
| 1772 | + /* Keep the subscriber, but turn off all notifications */ | |
| 1773 | + db_multi_exec( | |
| 1774 | + "UPDATE subscriber SET ssub='k', mtime=now() WHERE subscriberId=%d", | |
| 1775 | + sid | |
| 1776 | + ); | |
| 1777 | + } | |
| 1778 | + db_protect_pop(); | |
| 1767 | 1779 | style_header("Unsubscribed"); |
| 1768 | 1780 | @ <p>The "%h(zEmail)" email address has been unsubscribed from all |
| 1769 | 1781 | @ notifications. All subscription records for "%h(zEmail)" have |
| 1770 | 1782 | @ been purged. No further emails will be sent to "%h(zEmail)".</p> |
| 1771 | 1783 | if( uid && g.perm.Admin ){ |
| @@ -1793,11 +1805,11 @@ | ||
| 1793 | 1805 | ** that constitutes verification of the email address. |
| 1794 | 1806 | ** |
| 1795 | 1807 | ** * The sid= query parameter contains an integer subscriberId. |
| 1796 | 1808 | ** This only works for the administrator. It allows the |
| 1797 | 1809 | ** administrator to edit any subscription. |
| 1798 | -** | |
| 1810 | +** | |
| 1799 | 1811 | ** * The user is logged into an account other than "nobody" or |
| 1800 | 1812 | ** "anonymous". In that case the notification settings |
| 1801 | 1813 | ** associated with that account can be edited without needing |
| 1802 | 1814 | ** to know the subscriber code. |
| 1803 | 1815 | ** |
| @@ -1923,13 +1935,13 @@ | ||
| 1923 | 1935 | if( !PB("dodelete") ){ |
| 1924 | 1936 | eErr = 9; |
| 1925 | 1937 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to" |
| 1926 | 1938 | " unsubscribe"); |
| 1927 | 1939 | }else{ |
| 1928 | - alert_unsubscribe(sid); | |
| 1940 | + alert_unsubscribe(sid, 1); | |
| 1929 | 1941 | db_commit_transaction(); |
| 1930 | - return; | |
| 1942 | + return; | |
| 1931 | 1943 | } |
| 1932 | 1944 | } |
| 1933 | 1945 | style_set_current_feature("alerts"); |
| 1934 | 1946 | style_header("Update Subscription"); |
| 1935 | 1947 | db_prepare(&q, |
| @@ -2088,10 +2100,14 @@ | ||
| 2088 | 2100 | if( g.perm.RdWiki ){ |
| 2089 | 2101 | @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\ |
| 2090 | 2102 | @ Wiki</label> |
| 2091 | 2103 | } |
| 2092 | 2104 | @ </td></tr> |
| 2105 | + if( strchr(ssub,'k')!=0 ){ | |
| 2106 | + @ <tr><td></td><td> ↑ | |
| 2107 | + @ Note: User did a one-click unsubscribe</td></tr> | |
| 2108 | + } | |
| 2093 | 2109 | @ <tr> |
| 2094 | 2110 | @ <td class="form_label">Delivery:</td> |
| 2095 | 2111 | @ <td><select size="1" name="sdigest"> |
| 2096 | 2112 | @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option> |
| 2097 | 2113 | @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option> |
| @@ -2182,11 +2198,11 @@ | ||
| 2182 | 2198 | |
| 2183 | 2199 | |
| 2184 | 2200 | /* This is the message that gets sent to describe how to change |
| 2185 | 2201 | ** or modify a subscription |
| 2186 | 2202 | */ |
| 2187 | -static const char zUnsubMsg[] = | |
| 2203 | +static const char zUnsubMsg[] = | |
| 2188 | 2204 | @ To changes your subscription settings at %s visit this link: |
| 2189 | 2205 | @ |
| 2190 | 2206 | @ %s/alerts/%s |
| 2191 | 2207 | @ |
| 2192 | 2208 | @ To completely unsubscribe from %s, visit the following link: |
| @@ -2194,10 +2210,11 @@ | ||
| 2194 | 2210 | @ %s/unsubscribe/%s |
| 2195 | 2211 | ; |
| 2196 | 2212 | |
| 2197 | 2213 | /* |
| 2198 | 2214 | ** WEBPAGE: unsubscribe |
| 2215 | +** WEBPAGE: oneclickunsub | |
| 2199 | 2216 | ** |
| 2200 | 2217 | ** Users visit this page to be delisted from email alerts. |
| 2201 | 2218 | ** |
| 2202 | 2219 | ** If a valid subscriber code is supplied in the name= query parameter, |
| 2203 | 2220 | ** then that subscriber is delisted. |
| @@ -2206,10 +2223,13 @@ | ||
| 2206 | 2223 | ** to the /alerts page where they have an unsubscribe button. |
| 2207 | 2224 | ** |
| 2208 | 2225 | ** Non-logged-in users with no name= query parameter are invited to enter |
| 2209 | 2226 | ** an email address to which will be sent the unsubscribe link that |
| 2210 | 2227 | ** contains the correct subscriber code. |
| 2228 | +** | |
| 2229 | +** The /unsubscribe page requires comfirmation. The /oneclickunsub | |
| 2230 | +** page unsubscribes immediately without any need to confirm. | |
| 2211 | 2231 | */ |
| 2212 | 2232 | void unsubscribe_page(void){ |
| 2213 | 2233 | const char *zName = P("name"); |
| 2214 | 2234 | char *zErr = 0; |
| 2215 | 2235 | int eErr = 0; |
| @@ -2223,19 +2243,21 @@ | ||
| 2223 | 2243 | int sid = 0; |
| 2224 | 2244 | |
| 2225 | 2245 | if( zName==0 ) zName = P("scode"); |
| 2226 | 2246 | |
| 2227 | 2247 | /* If a valid subscriber code is supplied, then either present the user |
| 2228 | - ** with a confirmation, or if already confirmed, unsubscribe immediately. | |
| 2248 | + ** with a comformation, or if already confirmed, unsubscribe immediately. | |
| 2229 | 2249 | */ |
| 2230 | - if( zName | |
| 2250 | + if( zName | |
| 2231 | 2251 | && (sid = db_int(0, "SELECT subscriberId FROM subscriber" |
| 2232 | 2252 | " WHERE subscriberCode=hextoblob(%Q)", zName))!=0 |
| 2233 | 2253 | ){ |
| 2234 | 2254 | char *zUnsubName = mprintf("confirm%04x", sid); |
| 2235 | 2255 | if( P(zUnsubName)!=0 ){ |
| 2236 | - alert_unsubscribe(sid); | |
| 2256 | + alert_unsubscribe(sid, 1); | |
| 2257 | + }else if( sqlite3_strglob("*oneclick*",g.zPath)==0 ){ | |
| 2258 | + alert_unsubscribe(sid, 0); | |
| 2237 | 2259 | }else if( P("manage")!=0 ){ |
| 2238 | 2260 | cgi_redirectf("%R/alerts/%s", zName); |
| 2239 | 2261 | }else{ |
| 2240 | 2262 | style_header("Unsubscribe"); |
| 2241 | 2263 | form_begin(0, "%R/unsubscribe"); |
| @@ -2312,11 +2334,11 @@ | ||
| 2312 | 2334 | @ unsubscribe and/or modify your subscription settings</p> |
| 2313 | 2335 | } |
| 2314 | 2336 | alert_sender_free(pSender); |
| 2315 | 2337 | style_finish_page(); |
| 2316 | 2338 | return; |
| 2317 | - } | |
| 2339 | + } | |
| 2318 | 2340 | |
| 2319 | 2341 | /* Non-logged-in users have to enter an email address to which is |
| 2320 | 2342 | ** sent a message containing the unsubscribe link. |
| 2321 | 2343 | */ |
| 2322 | 2344 | style_header("Unsubscribe Request"); |
| @@ -2721,11 +2743,11 @@ | ||
| 2721 | 2743 | if( p->needMod ){ |
| 2722 | 2744 | blob_appendf(&p->hdr, "Subject: %s Pending Moderation: %s\r\n", |
| 2723 | 2745 | zSub, zTitle); |
| 2724 | 2746 | }else{ |
| 2725 | 2747 | blob_appendf(&p->hdr, "Subject: %s %s\r\n", zSub, zTitle); |
| 2726 | - blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n", | |
| 2748 | + blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n", | |
| 2727 | 2749 | zUuid, alert_hostname(zFrom)); |
| 2728 | 2750 | zIrt = db_column_text(&q, 4); |
| 2729 | 2751 | if( zIrt && zIrt[0] ){ |
| 2730 | 2752 | blob_appendf(&p->hdr, "In-Reply-To: <%.32s@%s>\r\n", |
| 2731 | 2753 | zIrt, alert_hostname(zFrom)); |
| @@ -3148,11 +3170,11 @@ | ||
| 3148 | 3170 | Blob fhdr, fbody; |
| 3149 | 3171 | blob_init(&fhdr, 0, 0); |
| 3150 | 3172 | blob_appendf(&fhdr, "To: <%s>\r\n", zEmail); |
| 3151 | 3173 | blob_append(&fhdr, blob_buffer(&p->hdr), blob_size(&p->hdr)); |
| 3152 | 3174 | blob_init(&fbody, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3153 | - blob_appendf(&fhdr, "List-Unsubscribe: <%s/unsubscribe/%s>\r\n", | |
| 3175 | + blob_appendf(&fhdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n", | |
| 3154 | 3176 | zUrl, zCode); |
| 3155 | 3177 | blob_appendf(&fhdr, |
| 3156 | 3178 | "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3157 | 3179 | blob_appendf(&fbody, "\n-- \nUnsubscribe: %s/unsubscribe/%s\n", |
| 3158 | 3180 | zUrl, zCode); |
| @@ -3178,11 +3200,11 @@ | ||
| 3178 | 3200 | blob_append(&body, "\n", 1); |
| 3179 | 3201 | blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3180 | 3202 | } |
| 3181 | 3203 | } |
| 3182 | 3204 | if( nHit==0 ) continue; |
| 3183 | - blob_appendf(&hdr, "List-Unsubscribe: <%s/unsubscribe/%s>\r\n", | |
| 3205 | + blob_appendf(&hdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n", | |
| 3184 | 3206 | zUrl, zCode); |
| 3185 | 3207 | blob_appendf(&hdr, "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3186 | 3208 | blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n", |
| 3187 | 3209 | zUrl, zCode); |
| 3188 | 3210 | alert_send(pSender,&hdr,&body,0); |
| @@ -3230,11 +3252,11 @@ | ||
| 3230 | 3252 | ); |
| 3231 | 3253 | while( db_step(&q)==SQLITE_ROW ){ |
| 3232 | 3254 | Blob hdr, body; |
| 3233 | 3255 | blob_init(&hdr, 0, 0); |
| 3234 | 3256 | blob_init(&body, 0, 0); |
| 3235 | - alert_renewal_msg(&hdr, &body, | |
| 3257 | + alert_renewal_msg(&hdr, &body, | |
| 3236 | 3258 | db_column_text(&q,0), |
| 3237 | 3259 | db_column_int(&q,1), |
| 3238 | 3260 | db_column_text(&q,2), |
| 3239 | 3261 | db_column_text(&q,3), |
| 3240 | 3262 | zRepoName, zUrl); |
| @@ -3300,11 +3322,11 @@ | ||
| 3300 | 3322 | style_header("Outbound Email Disabled"); |
| 3301 | 3323 | @ <p>Outbound email is disabled on this repository |
| 3302 | 3324 | style_finish_page(); |
| 3303 | 3325 | return; |
| 3304 | 3326 | } |
| 3305 | - if( P("submit")!=0 | |
| 3327 | + if( P("submit")!=0 | |
| 3306 | 3328 | && P("subject")!=0 |
| 3307 | 3329 | && P("msg")!=0 |
| 3308 | 3330 | && P("from")!=0 |
| 3309 | 3331 | && cgi_csrf_safe(2) |
| 3310 | 3332 | && captcha_is_correct(0) |
| 3311 | 3333 |
| --- src/alerts.c | |
| +++ src/alerts.c | |
| @@ -47,10 +47,11 @@ | |
| 47 | @ -- The ssub field is a string where each character indicates a particular |
| 48 | @ -- type of event to subscribe to. Choices: |
| 49 | @ -- a - Announcements |
| 50 | @ -- c - Check-ins |
| 51 | @ -- f - Forum posts |
| 52 | @ -- n - New forum threads |
| 53 | @ -- r - Replies to my own forum posts |
| 54 | @ -- t - Ticket changes |
| 55 | @ -- w - Wiki changes |
| 56 | @ -- x - Edits to forum posts |
| @@ -86,11 +87,11 @@ | |
| 86 | @ eventid TEXT PRIMARY KEY, -- Object that changed |
| 87 | @ sentSep BOOLEAN DEFAULT false, -- individual alert sent |
| 88 | @ sentDigest BOOLEAN DEFAULT false, -- digest alert sent |
| 89 | @ sentMod BOOLEAN DEFAULT false -- pending moderation alert sent |
| 90 | @ ) WITHOUT ROWID; |
| 91 | @ |
| 92 | @ -- Obsolete table. No longer used. |
| 93 | @ DROP TABLE IF EXISTS repository.alert_bounce; |
| 94 | ; |
| 95 | |
| 96 | /* |
| @@ -875,11 +876,11 @@ | |
| 875 | int nTo = 0; |
| 876 | char **azTo = 0; |
| 877 | Blob v; |
| 878 | char *z, *zAddr; |
| 879 | int i; |
| 880 | |
| 881 | email_header_value(pMsg, "to", &v); |
| 882 | z = blob_str(&v); |
| 883 | for(i=0; z[i]; i++){ |
| 884 | if( z[i]=='<' && (zAddr = email_copy_addr(&z[i+1],'>'))!=0 ){ |
| 885 | azTo = fossil_realloc(azTo, sizeof(azTo[0])*(nTo+1) ); |
| @@ -889,11 +890,11 @@ | |
| 889 | *pnTo = nTo; |
| 890 | *pazTo = azTo; |
| 891 | } |
| 892 | |
| 893 | /* |
| 894 | ** Free a list of To addresses obtained from a prior call to |
| 895 | ** email_header_to() |
| 896 | */ |
| 897 | void email_header_to_free(int nTo, char **azTo){ |
| 898 | int i; |
| 899 | for(i=0; i<nTo; i++) fossil_free(azTo[i]); |
| @@ -915,11 +916,11 @@ | |
| 915 | ** Message-Id: |
| 916 | ** Content-Type: |
| 917 | ** Content-Transfer-Encoding: |
| 918 | ** MIME-Version: |
| 919 | ** Sender: |
| 920 | ** |
| 921 | ** The caller maintains ownership of the input Blobs. This routine will |
| 922 | ** read the Blobs and send them onward to the email system, but it will |
| 923 | ** not free them. |
| 924 | ** |
| 925 | ** The Message-Id: field is added if there is not already a Message-Id |
| @@ -928,11 +929,11 @@ | |
| 928 | ** If the zFromName argument is not NULL, then it should be a human-readable |
| 929 | ** name or handle for the sender. In that case, "From:" becomes a made-up |
| 930 | ** email address based on a hash of zFromName and the domain of email-self, |
| 931 | ** and an additional "Sender:" field is inserted with the email-self |
| 932 | ** address. Downstream software might use the Sender header to set |
| 933 | ** the envelope-from address of the email. If zFromName is a NULL pointer, |
| 934 | ** then the "From:" is set to the email-self value and Sender is |
| 935 | ** omitted. |
| 936 | */ |
| 937 | void alert_send( |
| 938 | AlertSender *p, /* Emailer context */ |
| @@ -1045,11 +1046,11 @@ | |
| 1045 | ** a long-running server and will not be sending email notifications, |
| 1046 | ** then leave this setting blank. |
| 1047 | */ |
| 1048 | /* |
| 1049 | ** SETTING: email-admin width=40 |
| 1050 | ** This is the email address for the human administrator for the system. |
| 1051 | ** Abuse and trouble reports and password reset requests are send here. |
| 1052 | */ |
| 1053 | /* |
| 1054 | ** SETTING: email-subname width=16 |
| 1055 | ** This is a short name used to identifies the repository in the Subject: |
| @@ -1080,19 +1081,19 @@ | |
| 1080 | ** |
| 1081 | ** email-renew-warning is the time (in days since 1970-01-01) when the |
| 1082 | ** last batch of "your subscription is about to expire" emails were |
| 1083 | ** sent out. |
| 1084 | ** |
| 1085 | ** email-renew-cutoff is normally 7 days behind email-renew-warning. |
| 1086 | */ |
| 1087 | /* |
| 1088 | ** SETTING: email-send-method width=5 default=off sensitive |
| 1089 | ** Determine the method used to send email. Allowed values are |
| 1090 | ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value |
| 1091 | ** means no email is ever sent. The "relay" value means emails are sent |
| 1092 | ** to an Mail Sending Agent using SMTP located at email-send-relayhost. |
| 1093 | ** The "pipe" value means email messages are piped into a command |
| 1094 | ** determined by the email-send-command setting. The "dir" value means |
| 1095 | ** emails are written to individual files in a directory determined |
| 1096 | ** by the email-send-dir setting. The "db" value means that emails |
| 1097 | ** are added to an SQLite database named by the* email-send-db setting. |
| 1098 | ** The "stdout" value writes email text to standard output, for debugging. |
| @@ -1133,11 +1134,11 @@ | |
| 1133 | */ |
| 1134 | |
| 1135 | |
| 1136 | /* |
| 1137 | ** COMMAND: alerts* |
| 1138 | ** |
| 1139 | ** Usage: %fossil alerts SUBCOMMAND ARGS... |
| 1140 | ** |
| 1141 | ** Subcommands: |
| 1142 | ** |
| 1143 | ** pending Show all pending alerts. Useful for debugging. |
| @@ -1742,11 +1743,11 @@ | |
| 1742 | /* |
| 1743 | ** Either shutdown or completely delete a subscription entry given |
| 1744 | ** by the hex value zName. Then paint a webpage that explains that |
| 1745 | ** the entry has been removed. |
| 1746 | */ |
| 1747 | static void alert_unsubscribe(int sid){ |
| 1748 | const char *zEmail = 0; |
| 1749 | const char *zLogin = 0; |
| 1750 | int uid = 0; |
| 1751 | Stmt q; |
| 1752 | db_prepare(&q, "SELECT semail, suname FROM subscriber" |
| @@ -1759,13 +1760,24 @@ | |
| 1759 | style_set_current_feature("alerts"); |
| 1760 | if( zEmail==0 ){ |
| 1761 | style_header("Unsubscribe Fail"); |
| 1762 | @ <p>Unable to locate a subscriber with the requested key</p> |
| 1763 | }else{ |
| 1764 | db_multi_exec( |
| 1765 | "DELETE FROM subscriber WHERE subscriberId=%d", sid |
| 1766 | ); |
| 1767 | style_header("Unsubscribed"); |
| 1768 | @ <p>The "%h(zEmail)" email address has been unsubscribed from all |
| 1769 | @ notifications. All subscription records for "%h(zEmail)" have |
| 1770 | @ been purged. No further emails will be sent to "%h(zEmail)".</p> |
| 1771 | if( uid && g.perm.Admin ){ |
| @@ -1793,11 +1805,11 @@ | |
| 1793 | ** that constitutes verification of the email address. |
| 1794 | ** |
| 1795 | ** * The sid= query parameter contains an integer subscriberId. |
| 1796 | ** This only works for the administrator. It allows the |
| 1797 | ** administrator to edit any subscription. |
| 1798 | ** |
| 1799 | ** * The user is logged into an account other than "nobody" or |
| 1800 | ** "anonymous". In that case the notification settings |
| 1801 | ** associated with that account can be edited without needing |
| 1802 | ** to know the subscriber code. |
| 1803 | ** |
| @@ -1923,13 +1935,13 @@ | |
| 1923 | if( !PB("dodelete") ){ |
| 1924 | eErr = 9; |
| 1925 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to" |
| 1926 | " unsubscribe"); |
| 1927 | }else{ |
| 1928 | alert_unsubscribe(sid); |
| 1929 | db_commit_transaction(); |
| 1930 | return; |
| 1931 | } |
| 1932 | } |
| 1933 | style_set_current_feature("alerts"); |
| 1934 | style_header("Update Subscription"); |
| 1935 | db_prepare(&q, |
| @@ -2088,10 +2100,14 @@ | |
| 2088 | if( g.perm.RdWiki ){ |
| 2089 | @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\ |
| 2090 | @ Wiki</label> |
| 2091 | } |
| 2092 | @ </td></tr> |
| 2093 | @ <tr> |
| 2094 | @ <td class="form_label">Delivery:</td> |
| 2095 | @ <td><select size="1" name="sdigest"> |
| 2096 | @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option> |
| 2097 | @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option> |
| @@ -2182,11 +2198,11 @@ | |
| 2182 | |
| 2183 | |
| 2184 | /* This is the message that gets sent to describe how to change |
| 2185 | ** or modify a subscription |
| 2186 | */ |
| 2187 | static const char zUnsubMsg[] = |
| 2188 | @ To changes your subscription settings at %s visit this link: |
| 2189 | @ |
| 2190 | @ %s/alerts/%s |
| 2191 | @ |
| 2192 | @ To completely unsubscribe from %s, visit the following link: |
| @@ -2194,10 +2210,11 @@ | |
| 2194 | @ %s/unsubscribe/%s |
| 2195 | ; |
| 2196 | |
| 2197 | /* |
| 2198 | ** WEBPAGE: unsubscribe |
| 2199 | ** |
| 2200 | ** Users visit this page to be delisted from email alerts. |
| 2201 | ** |
| 2202 | ** If a valid subscriber code is supplied in the name= query parameter, |
| 2203 | ** then that subscriber is delisted. |
| @@ -2206,10 +2223,13 @@ | |
| 2206 | ** to the /alerts page where they have an unsubscribe button. |
| 2207 | ** |
| 2208 | ** Non-logged-in users with no name= query parameter are invited to enter |
| 2209 | ** an email address to which will be sent the unsubscribe link that |
| 2210 | ** contains the correct subscriber code. |
| 2211 | */ |
| 2212 | void unsubscribe_page(void){ |
| 2213 | const char *zName = P("name"); |
| 2214 | char *zErr = 0; |
| 2215 | int eErr = 0; |
| @@ -2223,19 +2243,21 @@ | |
| 2223 | int sid = 0; |
| 2224 | |
| 2225 | if( zName==0 ) zName = P("scode"); |
| 2226 | |
| 2227 | /* If a valid subscriber code is supplied, then either present the user |
| 2228 | ** with a confirmation, or if already confirmed, unsubscribe immediately. |
| 2229 | */ |
| 2230 | if( zName |
| 2231 | && (sid = db_int(0, "SELECT subscriberId FROM subscriber" |
| 2232 | " WHERE subscriberCode=hextoblob(%Q)", zName))!=0 |
| 2233 | ){ |
| 2234 | char *zUnsubName = mprintf("confirm%04x", sid); |
| 2235 | if( P(zUnsubName)!=0 ){ |
| 2236 | alert_unsubscribe(sid); |
| 2237 | }else if( P("manage")!=0 ){ |
| 2238 | cgi_redirectf("%R/alerts/%s", zName); |
| 2239 | }else{ |
| 2240 | style_header("Unsubscribe"); |
| 2241 | form_begin(0, "%R/unsubscribe"); |
| @@ -2312,11 +2334,11 @@ | |
| 2312 | @ unsubscribe and/or modify your subscription settings</p> |
| 2313 | } |
| 2314 | alert_sender_free(pSender); |
| 2315 | style_finish_page(); |
| 2316 | return; |
| 2317 | } |
| 2318 | |
| 2319 | /* Non-logged-in users have to enter an email address to which is |
| 2320 | ** sent a message containing the unsubscribe link. |
| 2321 | */ |
| 2322 | style_header("Unsubscribe Request"); |
| @@ -2721,11 +2743,11 @@ | |
| 2721 | if( p->needMod ){ |
| 2722 | blob_appendf(&p->hdr, "Subject: %s Pending Moderation: %s\r\n", |
| 2723 | zSub, zTitle); |
| 2724 | }else{ |
| 2725 | blob_appendf(&p->hdr, "Subject: %s %s\r\n", zSub, zTitle); |
| 2726 | blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n", |
| 2727 | zUuid, alert_hostname(zFrom)); |
| 2728 | zIrt = db_column_text(&q, 4); |
| 2729 | if( zIrt && zIrt[0] ){ |
| 2730 | blob_appendf(&p->hdr, "In-Reply-To: <%.32s@%s>\r\n", |
| 2731 | zIrt, alert_hostname(zFrom)); |
| @@ -3148,11 +3170,11 @@ | |
| 3148 | Blob fhdr, fbody; |
| 3149 | blob_init(&fhdr, 0, 0); |
| 3150 | blob_appendf(&fhdr, "To: <%s>\r\n", zEmail); |
| 3151 | blob_append(&fhdr, blob_buffer(&p->hdr), blob_size(&p->hdr)); |
| 3152 | blob_init(&fbody, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3153 | blob_appendf(&fhdr, "List-Unsubscribe: <%s/unsubscribe/%s>\r\n", |
| 3154 | zUrl, zCode); |
| 3155 | blob_appendf(&fhdr, |
| 3156 | "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3157 | blob_appendf(&fbody, "\n-- \nUnsubscribe: %s/unsubscribe/%s\n", |
| 3158 | zUrl, zCode); |
| @@ -3178,11 +3200,11 @@ | |
| 3178 | blob_append(&body, "\n", 1); |
| 3179 | blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3180 | } |
| 3181 | } |
| 3182 | if( nHit==0 ) continue; |
| 3183 | blob_appendf(&hdr, "List-Unsubscribe: <%s/unsubscribe/%s>\r\n", |
| 3184 | zUrl, zCode); |
| 3185 | blob_appendf(&hdr, "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3186 | blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n", |
| 3187 | zUrl, zCode); |
| 3188 | alert_send(pSender,&hdr,&body,0); |
| @@ -3230,11 +3252,11 @@ | |
| 3230 | ); |
| 3231 | while( db_step(&q)==SQLITE_ROW ){ |
| 3232 | Blob hdr, body; |
| 3233 | blob_init(&hdr, 0, 0); |
| 3234 | blob_init(&body, 0, 0); |
| 3235 | alert_renewal_msg(&hdr, &body, |
| 3236 | db_column_text(&q,0), |
| 3237 | db_column_int(&q,1), |
| 3238 | db_column_text(&q,2), |
| 3239 | db_column_text(&q,3), |
| 3240 | zRepoName, zUrl); |
| @@ -3300,11 +3322,11 @@ | |
| 3300 | style_header("Outbound Email Disabled"); |
| 3301 | @ <p>Outbound email is disabled on this repository |
| 3302 | style_finish_page(); |
| 3303 | return; |
| 3304 | } |
| 3305 | if( P("submit")!=0 |
| 3306 | && P("subject")!=0 |
| 3307 | && P("msg")!=0 |
| 3308 | && P("from")!=0 |
| 3309 | && cgi_csrf_safe(2) |
| 3310 | && captcha_is_correct(0) |
| 3311 |
| --- src/alerts.c | |
| +++ src/alerts.c | |
| @@ -47,10 +47,11 @@ | |
| 47 | @ -- The ssub field is a string where each character indicates a particular |
| 48 | @ -- type of event to subscribe to. Choices: |
| 49 | @ -- a - Announcements |
| 50 | @ -- c - Check-ins |
| 51 | @ -- f - Forum posts |
| 52 | @ -- k - ** Special: Unsubscribed using /oneclickunsub |
| 53 | @ -- n - New forum threads |
| 54 | @ -- r - Replies to my own forum posts |
| 55 | @ -- t - Ticket changes |
| 56 | @ -- w - Wiki changes |
| 57 | @ -- x - Edits to forum posts |
| @@ -86,11 +87,11 @@ | |
| 87 | @ eventid TEXT PRIMARY KEY, -- Object that changed |
| 88 | @ sentSep BOOLEAN DEFAULT false, -- individual alert sent |
| 89 | @ sentDigest BOOLEAN DEFAULT false, -- digest alert sent |
| 90 | @ sentMod BOOLEAN DEFAULT false -- pending moderation alert sent |
| 91 | @ ) WITHOUT ROWID; |
| 92 | @ |
| 93 | @ -- Obsolete table. No longer used. |
| 94 | @ DROP TABLE IF EXISTS repository.alert_bounce; |
| 95 | ; |
| 96 | |
| 97 | /* |
| @@ -875,11 +876,11 @@ | |
| 876 | int nTo = 0; |
| 877 | char **azTo = 0; |
| 878 | Blob v; |
| 879 | char *z, *zAddr; |
| 880 | int i; |
| 881 | |
| 882 | email_header_value(pMsg, "to", &v); |
| 883 | z = blob_str(&v); |
| 884 | for(i=0; z[i]; i++){ |
| 885 | if( z[i]=='<' && (zAddr = email_copy_addr(&z[i+1],'>'))!=0 ){ |
| 886 | azTo = fossil_realloc(azTo, sizeof(azTo[0])*(nTo+1) ); |
| @@ -889,11 +890,11 @@ | |
| 890 | *pnTo = nTo; |
| 891 | *pazTo = azTo; |
| 892 | } |
| 893 | |
| 894 | /* |
| 895 | ** Free a list of To addresses obtained from a prior call to |
| 896 | ** email_header_to() |
| 897 | */ |
| 898 | void email_header_to_free(int nTo, char **azTo){ |
| 899 | int i; |
| 900 | for(i=0; i<nTo; i++) fossil_free(azTo[i]); |
| @@ -915,11 +916,11 @@ | |
| 916 | ** Message-Id: |
| 917 | ** Content-Type: |
| 918 | ** Content-Transfer-Encoding: |
| 919 | ** MIME-Version: |
| 920 | ** Sender: |
| 921 | ** |
| 922 | ** The caller maintains ownership of the input Blobs. This routine will |
| 923 | ** read the Blobs and send them onward to the email system, but it will |
| 924 | ** not free them. |
| 925 | ** |
| 926 | ** The Message-Id: field is added if there is not already a Message-Id |
| @@ -928,11 +929,11 @@ | |
| 929 | ** If the zFromName argument is not NULL, then it should be a human-readable |
| 930 | ** name or handle for the sender. In that case, "From:" becomes a made-up |
| 931 | ** email address based on a hash of zFromName and the domain of email-self, |
| 932 | ** and an additional "Sender:" field is inserted with the email-self |
| 933 | ** address. Downstream software might use the Sender header to set |
| 934 | ** the envelope-from address of the email. If zFromName is a NULL pointer, |
| 935 | ** then the "From:" is set to the email-self value and Sender is |
| 936 | ** omitted. |
| 937 | */ |
| 938 | void alert_send( |
| 939 | AlertSender *p, /* Emailer context */ |
| @@ -1045,11 +1046,11 @@ | |
| 1046 | ** a long-running server and will not be sending email notifications, |
| 1047 | ** then leave this setting blank. |
| 1048 | */ |
| 1049 | /* |
| 1050 | ** SETTING: email-admin width=40 |
| 1051 | ** This is the email address for the human administrator for the system. |
| 1052 | ** Abuse and trouble reports and password reset requests are send here. |
| 1053 | */ |
| 1054 | /* |
| 1055 | ** SETTING: email-subname width=16 |
| 1056 | ** This is a short name used to identifies the repository in the Subject: |
| @@ -1080,19 +1081,19 @@ | |
| 1081 | ** |
| 1082 | ** email-renew-warning is the time (in days since 1970-01-01) when the |
| 1083 | ** last batch of "your subscription is about to expire" emails were |
| 1084 | ** sent out. |
| 1085 | ** |
| 1086 | ** email-renew-cutoff is normally 7 days behind email-renew-warning. |
| 1087 | */ |
| 1088 | /* |
| 1089 | ** SETTING: email-send-method width=5 default=off sensitive |
| 1090 | ** Determine the method used to send email. Allowed values are |
| 1091 | ** "off", "relay", "pipe", "dir", "db", and "stdout". The "off" value |
| 1092 | ** means no email is ever sent. The "relay" value means emails are sent |
| 1093 | ** to an Mail Sending Agent using SMTP located at email-send-relayhost. |
| 1094 | ** The "pipe" value means email messages are piped into a command |
| 1095 | ** determined by the email-send-command setting. The "dir" value means |
| 1096 | ** emails are written to individual files in a directory determined |
| 1097 | ** by the email-send-dir setting. The "db" value means that emails |
| 1098 | ** are added to an SQLite database named by the* email-send-db setting. |
| 1099 | ** The "stdout" value writes email text to standard output, for debugging. |
| @@ -1133,11 +1134,11 @@ | |
| 1134 | */ |
| 1135 | |
| 1136 | |
| 1137 | /* |
| 1138 | ** COMMAND: alerts* |
| 1139 | ** |
| 1140 | ** Usage: %fossil alerts SUBCOMMAND ARGS... |
| 1141 | ** |
| 1142 | ** Subcommands: |
| 1143 | ** |
| 1144 | ** pending Show all pending alerts. Useful for debugging. |
| @@ -1742,11 +1743,11 @@ | |
| 1743 | /* |
| 1744 | ** Either shutdown or completely delete a subscription entry given |
| 1745 | ** by the hex value zName. Then paint a webpage that explains that |
| 1746 | ** the entry has been removed. |
| 1747 | */ |
| 1748 | static void alert_unsubscribe(int sid, int bTotal){ |
| 1749 | const char *zEmail = 0; |
| 1750 | const char *zLogin = 0; |
| 1751 | int uid = 0; |
| 1752 | Stmt q; |
| 1753 | db_prepare(&q, "SELECT semail, suname FROM subscriber" |
| @@ -1759,13 +1760,24 @@ | |
| 1760 | style_set_current_feature("alerts"); |
| 1761 | if( zEmail==0 ){ |
| 1762 | style_header("Unsubscribe Fail"); |
| 1763 | @ <p>Unable to locate a subscriber with the requested key</p> |
| 1764 | }else{ |
| 1765 | db_unprotect(PROTECT_READONLY); |
| 1766 | if( bTotal ){ |
| 1767 | /* Completely delete the subscriber */ |
| 1768 | db_multi_exec( |
| 1769 | "DELETE FROM subscriber WHERE subscriberId=%d", sid |
| 1770 | ); |
| 1771 | }else{ |
| 1772 | /* Keep the subscriber, but turn off all notifications */ |
| 1773 | db_multi_exec( |
| 1774 | "UPDATE subscriber SET ssub='k', mtime=now() WHERE subscriberId=%d", |
| 1775 | sid |
| 1776 | ); |
| 1777 | } |
| 1778 | db_protect_pop(); |
| 1779 | style_header("Unsubscribed"); |
| 1780 | @ <p>The "%h(zEmail)" email address has been unsubscribed from all |
| 1781 | @ notifications. All subscription records for "%h(zEmail)" have |
| 1782 | @ been purged. No further emails will be sent to "%h(zEmail)".</p> |
| 1783 | if( uid && g.perm.Admin ){ |
| @@ -1793,11 +1805,11 @@ | |
| 1805 | ** that constitutes verification of the email address. |
| 1806 | ** |
| 1807 | ** * The sid= query parameter contains an integer subscriberId. |
| 1808 | ** This only works for the administrator. It allows the |
| 1809 | ** administrator to edit any subscription. |
| 1810 | ** |
| 1811 | ** * The user is logged into an account other than "nobody" or |
| 1812 | ** "anonymous". In that case the notification settings |
| 1813 | ** associated with that account can be edited without needing |
| 1814 | ** to know the subscriber code. |
| 1815 | ** |
| @@ -1923,13 +1935,13 @@ | |
| 1935 | if( !PB("dodelete") ){ |
| 1936 | eErr = 9; |
| 1937 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" again to" |
| 1938 | " unsubscribe"); |
| 1939 | }else{ |
| 1940 | alert_unsubscribe(sid, 1); |
| 1941 | db_commit_transaction(); |
| 1942 | return; |
| 1943 | } |
| 1944 | } |
| 1945 | style_set_current_feature("alerts"); |
| 1946 | style_header("Update Subscription"); |
| 1947 | db_prepare(&q, |
| @@ -2088,10 +2100,14 @@ | |
| 2100 | if( g.perm.RdWiki ){ |
| 2101 | @ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\ |
| 2102 | @ Wiki</label> |
| 2103 | } |
| 2104 | @ </td></tr> |
| 2105 | if( strchr(ssub,'k')!=0 ){ |
| 2106 | @ <tr><td></td><td> ↑ |
| 2107 | @ Note: User did a one-click unsubscribe</td></tr> |
| 2108 | } |
| 2109 | @ <tr> |
| 2110 | @ <td class="form_label">Delivery:</td> |
| 2111 | @ <td><select size="1" name="sdigest"> |
| 2112 | @ <option value="0" %s(sdigest?"":"selected")>Individual Emails</option> |
| 2113 | @ <option value="1" %s(sdigest?"selected":"")>Daily Digest</option> |
| @@ -2182,11 +2198,11 @@ | |
| 2198 | |
| 2199 | |
| 2200 | /* This is the message that gets sent to describe how to change |
| 2201 | ** or modify a subscription |
| 2202 | */ |
| 2203 | static const char zUnsubMsg[] = |
| 2204 | @ To changes your subscription settings at %s visit this link: |
| 2205 | @ |
| 2206 | @ %s/alerts/%s |
| 2207 | @ |
| 2208 | @ To completely unsubscribe from %s, visit the following link: |
| @@ -2194,10 +2210,11 @@ | |
| 2210 | @ %s/unsubscribe/%s |
| 2211 | ; |
| 2212 | |
| 2213 | /* |
| 2214 | ** WEBPAGE: unsubscribe |
| 2215 | ** WEBPAGE: oneclickunsub |
| 2216 | ** |
| 2217 | ** Users visit this page to be delisted from email alerts. |
| 2218 | ** |
| 2219 | ** If a valid subscriber code is supplied in the name= query parameter, |
| 2220 | ** then that subscriber is delisted. |
| @@ -2206,10 +2223,13 @@ | |
| 2223 | ** to the /alerts page where they have an unsubscribe button. |
| 2224 | ** |
| 2225 | ** Non-logged-in users with no name= query parameter are invited to enter |
| 2226 | ** an email address to which will be sent the unsubscribe link that |
| 2227 | ** contains the correct subscriber code. |
| 2228 | ** |
| 2229 | ** The /unsubscribe page requires comfirmation. The /oneclickunsub |
| 2230 | ** page unsubscribes immediately without any need to confirm. |
| 2231 | */ |
| 2232 | void unsubscribe_page(void){ |
| 2233 | const char *zName = P("name"); |
| 2234 | char *zErr = 0; |
| 2235 | int eErr = 0; |
| @@ -2223,19 +2243,21 @@ | |
| 2243 | int sid = 0; |
| 2244 | |
| 2245 | if( zName==0 ) zName = P("scode"); |
| 2246 | |
| 2247 | /* If a valid subscriber code is supplied, then either present the user |
| 2248 | ** with a comformation, or if already confirmed, unsubscribe immediately. |
| 2249 | */ |
| 2250 | if( zName |
| 2251 | && (sid = db_int(0, "SELECT subscriberId FROM subscriber" |
| 2252 | " WHERE subscriberCode=hextoblob(%Q)", zName))!=0 |
| 2253 | ){ |
| 2254 | char *zUnsubName = mprintf("confirm%04x", sid); |
| 2255 | if( P(zUnsubName)!=0 ){ |
| 2256 | alert_unsubscribe(sid, 1); |
| 2257 | }else if( sqlite3_strglob("*oneclick*",g.zPath)==0 ){ |
| 2258 | alert_unsubscribe(sid, 0); |
| 2259 | }else if( P("manage")!=0 ){ |
| 2260 | cgi_redirectf("%R/alerts/%s", zName); |
| 2261 | }else{ |
| 2262 | style_header("Unsubscribe"); |
| 2263 | form_begin(0, "%R/unsubscribe"); |
| @@ -2312,11 +2334,11 @@ | |
| 2334 | @ unsubscribe and/or modify your subscription settings</p> |
| 2335 | } |
| 2336 | alert_sender_free(pSender); |
| 2337 | style_finish_page(); |
| 2338 | return; |
| 2339 | } |
| 2340 | |
| 2341 | /* Non-logged-in users have to enter an email address to which is |
| 2342 | ** sent a message containing the unsubscribe link. |
| 2343 | */ |
| 2344 | style_header("Unsubscribe Request"); |
| @@ -2721,11 +2743,11 @@ | |
| 2743 | if( p->needMod ){ |
| 2744 | blob_appendf(&p->hdr, "Subject: %s Pending Moderation: %s\r\n", |
| 2745 | zSub, zTitle); |
| 2746 | }else{ |
| 2747 | blob_appendf(&p->hdr, "Subject: %s %s\r\n", zSub, zTitle); |
| 2748 | blob_appendf(&p->hdr, "Message-Id: <%.32s@%s>\r\n", |
| 2749 | zUuid, alert_hostname(zFrom)); |
| 2750 | zIrt = db_column_text(&q, 4); |
| 2751 | if( zIrt && zIrt[0] ){ |
| 2752 | blob_appendf(&p->hdr, "In-Reply-To: <%.32s@%s>\r\n", |
| 2753 | zIrt, alert_hostname(zFrom)); |
| @@ -3148,11 +3170,11 @@ | |
| 3170 | Blob fhdr, fbody; |
| 3171 | blob_init(&fhdr, 0, 0); |
| 3172 | blob_appendf(&fhdr, "To: <%s>\r\n", zEmail); |
| 3173 | blob_append(&fhdr, blob_buffer(&p->hdr), blob_size(&p->hdr)); |
| 3174 | blob_init(&fbody, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3175 | blob_appendf(&fhdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n", |
| 3176 | zUrl, zCode); |
| 3177 | blob_appendf(&fhdr, |
| 3178 | "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3179 | blob_appendf(&fbody, "\n-- \nUnsubscribe: %s/unsubscribe/%s\n", |
| 3180 | zUrl, zCode); |
| @@ -3178,11 +3200,11 @@ | |
| 3200 | blob_append(&body, "\n", 1); |
| 3201 | blob_append(&body, blob_buffer(&p->txt), blob_size(&p->txt)); |
| 3202 | } |
| 3203 | } |
| 3204 | if( nHit==0 ) continue; |
| 3205 | blob_appendf(&hdr, "List-Unsubscribe: <%s/oneclickunsub/%s>\r\n", |
| 3206 | zUrl, zCode); |
| 3207 | blob_appendf(&hdr, "List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n"); |
| 3208 | blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n", |
| 3209 | zUrl, zCode); |
| 3210 | alert_send(pSender,&hdr,&body,0); |
| @@ -3230,11 +3252,11 @@ | |
| 3252 | ); |
| 3253 | while( db_step(&q)==SQLITE_ROW ){ |
| 3254 | Blob hdr, body; |
| 3255 | blob_init(&hdr, 0, 0); |
| 3256 | blob_init(&body, 0, 0); |
| 3257 | alert_renewal_msg(&hdr, &body, |
| 3258 | db_column_text(&q,0), |
| 3259 | db_column_int(&q,1), |
| 3260 | db_column_text(&q,2), |
| 3261 | db_column_text(&q,3), |
| 3262 | zRepoName, zUrl); |
| @@ -3300,11 +3322,11 @@ | |
| 3322 | style_header("Outbound Email Disabled"); |
| 3323 | @ <p>Outbound email is disabled on this repository |
| 3324 | style_finish_page(); |
| 3325 | return; |
| 3326 | } |
| 3327 | if( P("submit")!=0 |
| 3328 | && P("subject")!=0 |
| 3329 | && P("msg")!=0 |
| 3330 | && P("from")!=0 |
| 3331 | && cgi_csrf_safe(2) |
| 3332 | && captcha_is_correct(0) |
| 3333 |