Fossil SCM
Add the /unsubscribe page.
Commit
f9116088243353b0f072c81061cb80a8cbd123a27633872d879d5ec7413bfac7
Parent
5fde17bbbc2cba6…
1 file changed
+172
-11
+172
-11
| --- src/email.c | ||
| +++ src/email.c | ||
| @@ -152,11 +152,11 @@ | ||
| 152 | 152 | void setup_email(void){ |
| 153 | 153 | static const char *const azSendMethods[] = { |
| 154 | 154 | "off", "Disabled", |
| 155 | 155 | "pipe", "Pipe to a command", |
| 156 | 156 | "db", "Store in a database", |
| 157 | - "file", "Store in a directory" | |
| 157 | + "dir", "Store in a directory" | |
| 158 | 158 | }; |
| 159 | 159 | login_check_credentials(); |
| 160 | 160 | if( !g.perm.Setup ){ |
| 161 | 161 | login_needed(0); |
| 162 | 162 | return; |
| @@ -571,13 +571,13 @@ | ||
| 571 | 571 | /* |
| 572 | 572 | ** Do error checking on a submitted subscription form. Return TRUE |
| 573 | 573 | ** if the submission is valid. Return false if any problems are seen. |
| 574 | 574 | */ |
| 575 | 575 | static int subscribe_error_check( |
| 576 | - int *peErr, /* Type of error */ | |
| 577 | - char **pzErr, /* Error message text */ | |
| 578 | - int needCaptcha /* True if captcha check needed */ | |
| 576 | + int *peErr, /* Type of error */ | |
| 577 | + char **pzErr, /* Error message text */ | |
| 578 | + int needCaptcha /* True if captcha check needed */ | |
| 579 | 579 | ){ |
| 580 | 580 | const char *zEAddr; |
| 581 | 581 | int i, j, n; |
| 582 | 582 | char c; |
| 583 | 583 | |
| @@ -817,10 +817,35 @@ | ||
| 817 | 817 | } |
| 818 | 818 | @ </form> |
| 819 | 819 | fossil_free(zErr); |
| 820 | 820 | style_footer(); |
| 821 | 821 | } |
| 822 | + | |
| 823 | +/* | |
| 824 | +** Either shutdown or completely delete a subscription entry given | |
| 825 | +** by the hex value zName. Then paint a webpage that explains that | |
| 826 | +** the entry has been removed. | |
| 827 | +*/ | |
| 828 | +static void email_unsubscribe(const char *zName){ | |
| 829 | + char *zEmail; | |
| 830 | + zEmail = db_text(0, "SELECT semail FROM subscriber" | |
| 831 | + " WHERE subscriberCode=hextoblob(%Q)", zName); | |
| 832 | + if( zEmail==0 ){ | |
| 833 | + style_header("Unsubscribe Fail"); | |
| 834 | + @ <p>Unable to locate a subscriber with the requested key</p> | |
| 835 | + }else{ | |
| 836 | + db_multi_exec( | |
| 837 | + "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)", | |
| 838 | + zName | |
| 839 | + ); | |
| 840 | + style_header("Unsubscribed"); | |
| 841 | + @ <p>The "%h(zEmail)" email address has been delisted. | |
| 842 | + @ All traces of that email address have been removed</p> | |
| 843 | + } | |
| 844 | + style_footer(); | |
| 845 | + return; | |
| 846 | +} | |
| 822 | 847 | |
| 823 | 848 | /* |
| 824 | 849 | ** WEBPAGE: alerts |
| 825 | 850 | ** |
| 826 | 851 | ** Edit email alert and notification settings. |
| @@ -896,17 +921,11 @@ | ||
| 896 | 921 | if( !PB("dodelete") ){ |
| 897 | 922 | eErr = 9; |
| 898 | 923 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" to" |
| 899 | 924 | " unsubscribe"); |
| 900 | 925 | }else{ |
| 901 | - db_multi_exec( | |
| 902 | - "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)", | |
| 903 | - zName | |
| 904 | - ); | |
| 905 | - style_header("Email Subscription Deleted"); | |
| 906 | - @ <p>The email subscription has been deleted</p> | |
| 907 | - style_footer(); | |
| 926 | + email_unsubscribe(zName); | |
| 908 | 927 | return; |
| 909 | 928 | } |
| 910 | 929 | } |
| 911 | 930 | db_prepare(&q, |
| 912 | 931 | "SELECT" |
| @@ -999,10 +1018,152 @@ | ||
| 999 | 1018 | @ </form> |
| 1000 | 1019 | fossil_free(zErr); |
| 1001 | 1020 | db_finalize(&q); |
| 1002 | 1021 | style_footer(); |
| 1003 | 1022 | } |
| 1023 | + | |
| 1024 | +/* This is the message that gets sent to describe how to change | |
| 1025 | +** or modify a subscription | |
| 1026 | +*/ | |
| 1027 | +static const char zUnsubMsg[] = | |
| 1028 | +@ To changes your subscription settings at %s visit this link: | |
| 1029 | +@ | |
| 1030 | +@ %s/alerts/%s | |
| 1031 | +@ | |
| 1032 | +@ To completely unsubscribe from %s, visit the following link: | |
| 1033 | +@ | |
| 1034 | +@ %s/unsubscribe/%s | |
| 1035 | +; | |
| 1036 | + | |
| 1037 | +/* | |
| 1038 | +** WEBPAGE: unsubscribe | |
| 1039 | +** | |
| 1040 | +** Users visit this page to be delisted from email alerts. | |
| 1041 | +** | |
| 1042 | +** If a valid subscriber code is supplied in the name= query parameter, | |
| 1043 | +** then that subscriber is delisted. | |
| 1044 | +** | |
| 1045 | +** Otherwise, If the users is logged in, then they are redirected | |
| 1046 | +** to the /alerts page where they have an unsubscribe button. | |
| 1047 | +** | |
| 1048 | +** Non-logged-in users with no name= query parameter are invited to enter | |
| 1049 | +** an email address to which will be sent the unsubscribe link that | |
| 1050 | +** contains the correct subscriber code. | |
| 1051 | +*/ | |
| 1052 | +void unsubscribe_page(void){ | |
| 1053 | + const char *zName = P("name"); | |
| 1054 | + char *zErr = 0; | |
| 1055 | + int eErr = 0; | |
| 1056 | + unsigned int uSeed; | |
| 1057 | + const char *zDecoded; | |
| 1058 | + char *zCaptcha = 0; | |
| 1059 | + int dx; | |
| 1060 | + int bSubmit; | |
| 1061 | + const char *zEAddr; | |
| 1062 | + char *zCode = 0; | |
| 1063 | + | |
| 1064 | + /* If a valid subscriber code is supplied, then unsubscribe immediately. | |
| 1065 | + */ | |
| 1066 | + if( zName | |
| 1067 | + && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)", | |
| 1068 | + zName) | |
| 1069 | + ){ | |
| 1070 | + email_unsubscribe(zName); | |
| 1071 | + return; | |
| 1072 | + } | |
| 1073 | + | |
| 1074 | + /* Logged in users are redirected to the /alerts page */ | |
| 1075 | + login_check_credentials(); | |
| 1076 | + if( login_is_individual() ){ | |
| 1077 | + cgi_redirectf("%R/alerts"); | |
| 1078 | + return; | |
| 1079 | + } | |
| 1080 | + | |
| 1081 | + zEAddr = PD("e",""); | |
| 1082 | + dx = atoi(PD("dx","0")); | |
| 1083 | + bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(1); | |
| 1084 | + if( bSubmit ){ | |
| 1085 | + if( !captcha_is_correct(1) ){ | |
| 1086 | + eErr = 2; | |
| 1087 | + zErr = mprintf("enter the security code shown below"); | |
| 1088 | + bSubmit = 0; | |
| 1089 | + } | |
| 1090 | + } | |
| 1091 | + if( bSubmit ){ | |
| 1092 | + zCode = db_text(0,"SELECT hex(subscriberCode) FROM subscriber" | |
| 1093 | + " WHERE semail=%Q", zEAddr); | |
| 1094 | + if( zCode==0 ){ | |
| 1095 | + eErr = 1; | |
| 1096 | + zErr = mprintf("not a valid email address"); | |
| 1097 | + bSubmit = 0; | |
| 1098 | + } | |
| 1099 | + } | |
| 1100 | + if( bSubmit ){ | |
| 1101 | + /* If we get this far, it means that a valid unsubscribe request has | |
| 1102 | + ** been submitted. Send the appropriate email. */ | |
| 1103 | + Blob hdr, body; | |
| 1104 | + blob_init(&hdr,0,0); | |
| 1105 | + blob_init(&body,0,0); | |
| 1106 | + blob_appendf(&hdr, "To: %s\n", zEAddr); | |
| 1107 | + blob_appendf(&hdr, "Subject: Unsubscribe Instructions\n"); | |
| 1108 | + blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/, | |
| 1109 | + g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode); | |
| 1110 | + email_send(&hdr, &body, 0, 0); | |
| 1111 | + style_header("Unsubscribe Instructions Sent"); | |
| 1112 | + @ <p>An email has been sent to "%h(zEAddr)" that explains how to | |
| 1113 | + @ unsubscribe and/or modify your subscription settings</p> | |
| 1114 | + style_footer(); | |
| 1115 | + return; | |
| 1116 | + } | |
| 1117 | + | |
| 1118 | + /* Non-logged-in users have to enter an email address to which is | |
| 1119 | + ** sent a message containing the unsubscribe link. | |
| 1120 | + */ | |
| 1121 | + style_header("Unsubscribe Request"); | |
| 1122 | + @ <p>Fill out the form below to request an email message that will | |
| 1123 | + @ explain how to unsubscribe and/or change your subscription settings.</p> | |
| 1124 | + @ | |
| 1125 | + form_begin(0, "%R/unsubscribe"); | |
| 1126 | + @ <table class="subscribe"> | |
| 1127 | + @ <tr> | |
| 1128 | + @ <td class="form_label">Email Address:</td> | |
| 1129 | + @ <td><input type="text" name="e" value="%h(zEAddr)" size="30"></td> | |
| 1130 | + if( eErr==1 ){ | |
| 1131 | + @ <td><span class="loginError">← %h(zErr)</span></td> | |
| 1132 | + } | |
| 1133 | + @ </tr> | |
| 1134 | + uSeed = captcha_seed(); | |
| 1135 | + zDecoded = captcha_decode(uSeed); | |
| 1136 | + zCaptcha = captcha_render(zDecoded); | |
| 1137 | + @ <tr> | |
| 1138 | + @ <td class="form_label">Security Code:</td> | |
| 1139 | + @ <td><input type="text" name="captcha" value="" size="30"> | |
| 1140 | + @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> | |
| 1141 | + if( eErr==2 ){ | |
| 1142 | + @ <td><span class="loginError">← %h(zErr)</span></td> | |
| 1143 | + } | |
| 1144 | + @ </tr> | |
| 1145 | + @ <tr> | |
| 1146 | + @ <td class="form_label">Options:</td> | |
| 1147 | + @ <td><label><input type="radio" name="dx" value="0" %s(dx?"":"checked")>\ | |
| 1148 | + @ Modify subscription</label><br> | |
| 1149 | + @ <label><input type="radio" name="dx" value="1" %s(dx?"checked":"")>\ | |
| 1150 | + @ Completely unsubscribe</label><br> | |
| 1151 | + @ <tr> | |
| 1152 | + @ <td></td> | |
| 1153 | + @ <td><input type="submit" name="submit" value="Submit"></td> | |
| 1154 | + @ </tr> | |
| 1155 | + @ </table> | |
| 1156 | + @ <div class="captcha"><table class="captcha"><tr><td><pre> | |
| 1157 | + @ %h(zCaptcha) | |
| 1158 | + @ </pre> | |
| 1159 | + @ Enter the 8 characters above in the "Security Code" box | |
| 1160 | + @ </td></tr></table></div> | |
| 1161 | + @ </form> | |
| 1162 | + fossil_free(zErr); | |
| 1163 | + style_footer(); | |
| 1164 | +} | |
| 1004 | 1165 | |
| 1005 | 1166 | /* |
| 1006 | 1167 | ** WEBPAGE: subscribers |
| 1007 | 1168 | ** |
| 1008 | 1169 | ** This page, accessible to administrators only, |
| 1009 | 1170 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -152,11 +152,11 @@ | |
| 152 | void setup_email(void){ |
| 153 | static const char *const azSendMethods[] = { |
| 154 | "off", "Disabled", |
| 155 | "pipe", "Pipe to a command", |
| 156 | "db", "Store in a database", |
| 157 | "file", "Store in a directory" |
| 158 | }; |
| 159 | login_check_credentials(); |
| 160 | if( !g.perm.Setup ){ |
| 161 | login_needed(0); |
| 162 | return; |
| @@ -571,13 +571,13 @@ | |
| 571 | /* |
| 572 | ** Do error checking on a submitted subscription form. Return TRUE |
| 573 | ** if the submission is valid. Return false if any problems are seen. |
| 574 | */ |
| 575 | static int subscribe_error_check( |
| 576 | int *peErr, /* Type of error */ |
| 577 | char **pzErr, /* Error message text */ |
| 578 | int needCaptcha /* True if captcha check needed */ |
| 579 | ){ |
| 580 | const char *zEAddr; |
| 581 | int i, j, n; |
| 582 | char c; |
| 583 | |
| @@ -817,10 +817,35 @@ | |
| 817 | } |
| 818 | @ </form> |
| 819 | fossil_free(zErr); |
| 820 | style_footer(); |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | ** WEBPAGE: alerts |
| 825 | ** |
| 826 | ** Edit email alert and notification settings. |
| @@ -896,17 +921,11 @@ | |
| 896 | if( !PB("dodelete") ){ |
| 897 | eErr = 9; |
| 898 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" to" |
| 899 | " unsubscribe"); |
| 900 | }else{ |
| 901 | db_multi_exec( |
| 902 | "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)", |
| 903 | zName |
| 904 | ); |
| 905 | style_header("Email Subscription Deleted"); |
| 906 | @ <p>The email subscription has been deleted</p> |
| 907 | style_footer(); |
| 908 | return; |
| 909 | } |
| 910 | } |
| 911 | db_prepare(&q, |
| 912 | "SELECT" |
| @@ -999,10 +1018,152 @@ | |
| 999 | @ </form> |
| 1000 | fossil_free(zErr); |
| 1001 | db_finalize(&q); |
| 1002 | style_footer(); |
| 1003 | } |
| 1004 | |
| 1005 | /* |
| 1006 | ** WEBPAGE: subscribers |
| 1007 | ** |
| 1008 | ** This page, accessible to administrators only, |
| 1009 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -152,11 +152,11 @@ | |
| 152 | void setup_email(void){ |
| 153 | static const char *const azSendMethods[] = { |
| 154 | "off", "Disabled", |
| 155 | "pipe", "Pipe to a command", |
| 156 | "db", "Store in a database", |
| 157 | "dir", "Store in a directory" |
| 158 | }; |
| 159 | login_check_credentials(); |
| 160 | if( !g.perm.Setup ){ |
| 161 | login_needed(0); |
| 162 | return; |
| @@ -571,13 +571,13 @@ | |
| 571 | /* |
| 572 | ** Do error checking on a submitted subscription form. Return TRUE |
| 573 | ** if the submission is valid. Return false if any problems are seen. |
| 574 | */ |
| 575 | static int subscribe_error_check( |
| 576 | int *peErr, /* Type of error */ |
| 577 | char **pzErr, /* Error message text */ |
| 578 | int needCaptcha /* True if captcha check needed */ |
| 579 | ){ |
| 580 | const char *zEAddr; |
| 581 | int i, j, n; |
| 582 | char c; |
| 583 | |
| @@ -817,10 +817,35 @@ | |
| 817 | } |
| 818 | @ </form> |
| 819 | fossil_free(zErr); |
| 820 | style_footer(); |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | ** Either shutdown or completely delete a subscription entry given |
| 825 | ** by the hex value zName. Then paint a webpage that explains that |
| 826 | ** the entry has been removed. |
| 827 | */ |
| 828 | static void email_unsubscribe(const char *zName){ |
| 829 | char *zEmail; |
| 830 | zEmail = db_text(0, "SELECT semail FROM subscriber" |
| 831 | " WHERE subscriberCode=hextoblob(%Q)", zName); |
| 832 | if( zEmail==0 ){ |
| 833 | style_header("Unsubscribe Fail"); |
| 834 | @ <p>Unable to locate a subscriber with the requested key</p> |
| 835 | }else{ |
| 836 | db_multi_exec( |
| 837 | "DELETE FROM subscriber WHERE subscriberCode=hextoblob(%Q)", |
| 838 | zName |
| 839 | ); |
| 840 | style_header("Unsubscribed"); |
| 841 | @ <p>The "%h(zEmail)" email address has been delisted. |
| 842 | @ All traces of that email address have been removed</p> |
| 843 | } |
| 844 | style_footer(); |
| 845 | return; |
| 846 | } |
| 847 | |
| 848 | /* |
| 849 | ** WEBPAGE: alerts |
| 850 | ** |
| 851 | ** Edit email alert and notification settings. |
| @@ -896,17 +921,11 @@ | |
| 921 | if( !PB("dodelete") ){ |
| 922 | eErr = 9; |
| 923 | zErr = mprintf("Select this checkbox and press \"Unsubscribe\" to" |
| 924 | " unsubscribe"); |
| 925 | }else{ |
| 926 | email_unsubscribe(zName); |
| 927 | return; |
| 928 | } |
| 929 | } |
| 930 | db_prepare(&q, |
| 931 | "SELECT" |
| @@ -999,10 +1018,152 @@ | |
| 1018 | @ </form> |
| 1019 | fossil_free(zErr); |
| 1020 | db_finalize(&q); |
| 1021 | style_footer(); |
| 1022 | } |
| 1023 | |
| 1024 | /* This is the message that gets sent to describe how to change |
| 1025 | ** or modify a subscription |
| 1026 | */ |
| 1027 | static const char zUnsubMsg[] = |
| 1028 | @ To changes your subscription settings at %s visit this link: |
| 1029 | @ |
| 1030 | @ %s/alerts/%s |
| 1031 | @ |
| 1032 | @ To completely unsubscribe from %s, visit the following link: |
| 1033 | @ |
| 1034 | @ %s/unsubscribe/%s |
| 1035 | ; |
| 1036 | |
| 1037 | /* |
| 1038 | ** WEBPAGE: unsubscribe |
| 1039 | ** |
| 1040 | ** Users visit this page to be delisted from email alerts. |
| 1041 | ** |
| 1042 | ** If a valid subscriber code is supplied in the name= query parameter, |
| 1043 | ** then that subscriber is delisted. |
| 1044 | ** |
| 1045 | ** Otherwise, If the users is logged in, then they are redirected |
| 1046 | ** to the /alerts page where they have an unsubscribe button. |
| 1047 | ** |
| 1048 | ** Non-logged-in users with no name= query parameter are invited to enter |
| 1049 | ** an email address to which will be sent the unsubscribe link that |
| 1050 | ** contains the correct subscriber code. |
| 1051 | */ |
| 1052 | void unsubscribe_page(void){ |
| 1053 | const char *zName = P("name"); |
| 1054 | char *zErr = 0; |
| 1055 | int eErr = 0; |
| 1056 | unsigned int uSeed; |
| 1057 | const char *zDecoded; |
| 1058 | char *zCaptcha = 0; |
| 1059 | int dx; |
| 1060 | int bSubmit; |
| 1061 | const char *zEAddr; |
| 1062 | char *zCode = 0; |
| 1063 | |
| 1064 | /* If a valid subscriber code is supplied, then unsubscribe immediately. |
| 1065 | */ |
| 1066 | if( zName |
| 1067 | && db_exists("SELECT 1 FROM subscriber WHERE subscriberCode=hextoblob(%Q)", |
| 1068 | zName) |
| 1069 | ){ |
| 1070 | email_unsubscribe(zName); |
| 1071 | return; |
| 1072 | } |
| 1073 | |
| 1074 | /* Logged in users are redirected to the /alerts page */ |
| 1075 | login_check_credentials(); |
| 1076 | if( login_is_individual() ){ |
| 1077 | cgi_redirectf("%R/alerts"); |
| 1078 | return; |
| 1079 | } |
| 1080 | |
| 1081 | zEAddr = PD("e",""); |
| 1082 | dx = atoi(PD("dx","0")); |
| 1083 | bSubmit = P("submit")!=0 && P("e")!=0 && cgi_csrf_safe(1); |
| 1084 | if( bSubmit ){ |
| 1085 | if( !captcha_is_correct(1) ){ |
| 1086 | eErr = 2; |
| 1087 | zErr = mprintf("enter the security code shown below"); |
| 1088 | bSubmit = 0; |
| 1089 | } |
| 1090 | } |
| 1091 | if( bSubmit ){ |
| 1092 | zCode = db_text(0,"SELECT hex(subscriberCode) FROM subscriber" |
| 1093 | " WHERE semail=%Q", zEAddr); |
| 1094 | if( zCode==0 ){ |
| 1095 | eErr = 1; |
| 1096 | zErr = mprintf("not a valid email address"); |
| 1097 | bSubmit = 0; |
| 1098 | } |
| 1099 | } |
| 1100 | if( bSubmit ){ |
| 1101 | /* If we get this far, it means that a valid unsubscribe request has |
| 1102 | ** been submitted. Send the appropriate email. */ |
| 1103 | Blob hdr, body; |
| 1104 | blob_init(&hdr,0,0); |
| 1105 | blob_init(&body,0,0); |
| 1106 | blob_appendf(&hdr, "To: %s\n", zEAddr); |
| 1107 | blob_appendf(&hdr, "Subject: Unsubscribe Instructions\n"); |
| 1108 | blob_appendf(&body, zUnsubMsg/*works-like:"%s%s%s%s%s%s"*/, |
| 1109 | g.zBaseURL, g.zBaseURL, zCode, g.zBaseURL, g.zBaseURL, zCode); |
| 1110 | email_send(&hdr, &body, 0, 0); |
| 1111 | style_header("Unsubscribe Instructions Sent"); |
| 1112 | @ <p>An email has been sent to "%h(zEAddr)" that explains how to |
| 1113 | @ unsubscribe and/or modify your subscription settings</p> |
| 1114 | style_footer(); |
| 1115 | return; |
| 1116 | } |
| 1117 | |
| 1118 | /* Non-logged-in users have to enter an email address to which is |
| 1119 | ** sent a message containing the unsubscribe link. |
| 1120 | */ |
| 1121 | style_header("Unsubscribe Request"); |
| 1122 | @ <p>Fill out the form below to request an email message that will |
| 1123 | @ explain how to unsubscribe and/or change your subscription settings.</p> |
| 1124 | @ |
| 1125 | form_begin(0, "%R/unsubscribe"); |
| 1126 | @ <table class="subscribe"> |
| 1127 | @ <tr> |
| 1128 | @ <td class="form_label">Email Address:</td> |
| 1129 | @ <td><input type="text" name="e" value="%h(zEAddr)" size="30"></td> |
| 1130 | if( eErr==1 ){ |
| 1131 | @ <td><span class="loginError">← %h(zErr)</span></td> |
| 1132 | } |
| 1133 | @ </tr> |
| 1134 | uSeed = captcha_seed(); |
| 1135 | zDecoded = captcha_decode(uSeed); |
| 1136 | zCaptcha = captcha_render(zDecoded); |
| 1137 | @ <tr> |
| 1138 | @ <td class="form_label">Security Code:</td> |
| 1139 | @ <td><input type="text" name="captcha" value="" size="30"> |
| 1140 | @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> |
| 1141 | if( eErr==2 ){ |
| 1142 | @ <td><span class="loginError">← %h(zErr)</span></td> |
| 1143 | } |
| 1144 | @ </tr> |
| 1145 | @ <tr> |
| 1146 | @ <td class="form_label">Options:</td> |
| 1147 | @ <td><label><input type="radio" name="dx" value="0" %s(dx?"":"checked")>\ |
| 1148 | @ Modify subscription</label><br> |
| 1149 | @ <label><input type="radio" name="dx" value="1" %s(dx?"checked":"")>\ |
| 1150 | @ Completely unsubscribe</label><br> |
| 1151 | @ <tr> |
| 1152 | @ <td></td> |
| 1153 | @ <td><input type="submit" name="submit" value="Submit"></td> |
| 1154 | @ </tr> |
| 1155 | @ </table> |
| 1156 | @ <div class="captcha"><table class="captcha"><tr><td><pre> |
| 1157 | @ %h(zCaptcha) |
| 1158 | @ </pre> |
| 1159 | @ Enter the 8 characters above in the "Security Code" box |
| 1160 | @ </td></tr></table></div> |
| 1161 | @ </form> |
| 1162 | fossil_free(zErr); |
| 1163 | style_footer(); |
| 1164 | } |
| 1165 | |
| 1166 | /* |
| 1167 | ** WEBPAGE: subscribers |
| 1168 | ** |
| 1169 | ** This page, accessible to administrators only, |
| 1170 |