Fossil SCM
First attempt at a /subscribe page. Non-functional display only.
Commit
fb3934ec53e86be5d2694cdcd0577fc542eb18fcb4ff07111b412087be96fa9f
Parent
fa83e4b3e1eb55c…
2 files changed
+4
+89
-50
+4
| --- src/default_css.txt | ||
| +++ src/default_css.txt | ||
| @@ -668,5 +668,9 @@ | ||
| 668 | 668 | padding: 1px; |
| 669 | 669 | } |
| 670 | 670 | div.forum_body p { |
| 671 | 671 | margin-top: 0; |
| 672 | 672 | } |
| 673 | +td.form_label { | |
| 674 | + vertical-align: top; | |
| 675 | + text-align: right; | |
| 676 | +} | |
| 673 | 677 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -668,5 +668,9 @@ | |
| 668 | padding: 1px; |
| 669 | } |
| 670 | div.forum_body p { |
| 671 | margin-top: 0; |
| 672 | } |
| 673 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -668,5 +668,9 @@ | |
| 668 | padding: 1px; |
| 669 | } |
| 670 | div.forum_body p { |
| 671 | margin-top: 0; |
| 672 | } |
| 673 | td.form_label { |
| 674 | vertical-align: top; |
| 675 | text-align: right; |
| 676 | } |
| 677 |
+89
-50
| --- src/email.c | ||
| +++ src/email.c | ||
| @@ -30,10 +30,20 @@ | ||
| 30 | 30 | @ -- the USER table without being a subscriber. Or a person can be a |
| 31 | 31 | @ -- subscriber without having a USER table entry. Or they can have both. |
| 32 | 32 | @ -- In the last case the suname column points from the subscriber entry |
| 33 | 33 | @ -- to the USER entry. |
| 34 | 34 | @ -- |
| 35 | +@ -- The ssub field is a string where each character indicates a particular | |
| 36 | +@ -- type of event to subscribe to. Choices: | |
| 37 | +@ -- a - Announcements | |
| 38 | +@ -- c - Check-ins | |
| 39 | +@ -- t - Ticket changes | |
| 40 | +@ -- w - Wiki changes | |
| 41 | +@ -- Probably different codes will be added in the future. In the future | |
| 42 | +@ -- we might also add a separate table that allows subscribing to email | |
| 43 | +@ -- notifications for specific branches or tags or tickets. | |
| 44 | +@ -- | |
| 35 | 45 | @ CREATE TABLE repository.subscriber( |
| 36 | 46 | @ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use |
| 37 | 47 | @ subscriberCode TEXT UNIQUE, -- UUID for subscriber. External use |
| 38 | 48 | @ sname TEXT, -- Human readable name |
| 39 | 49 | @ suname TEXT, -- Corresponding USER or NULL |
| @@ -46,48 +56,10 @@ | ||
| 46 | 56 | @ smtime DATE, -- Last change. JulianDay |
| 47 | 57 | @ sipaddr TEXT, -- IP address for last change |
| 48 | 58 | @ spswdHash TEXT -- SHA3 hash of password |
| 49 | 59 | @ ); |
| 50 | 60 | @ |
| 51 | -@ -- Each subscriber is associated with zero or more subscriptions. Each | |
| 52 | -@ -- subscription identifies events for which the subscriber desires | |
| 53 | -@ -- email notification. | |
| 54 | -@ -- | |
| 55 | -@ -- The stype field can be: | |
| 56 | -@ -- | |
| 57 | -@ -- 'c' Check-ins | |
| 58 | -@ -- 'w' Wiki pages | |
| 59 | -@ -- 't' Tickets | |
| 60 | -@ -- 'e' Tech-notes | |
| 61 | -@ -- 'g' Tags | |
| 62 | -@ -- 'f' Forum posts | |
| 63 | -@ -- 'm' Any item in need of moderation | |
| 64 | -@ -- | |
| 65 | -@ -- stype values are restricted to items that suname is allowed to see. | |
| 66 | -@ -- If suname is NULL, then stype values are restricted to things that | |
| 67 | -@ -- user "nobody" is allowed to see. | |
| 68 | -@ -- | |
| 69 | -@ -- The sarg field provides additional restrictions. Since it is | |
| 70 | -@ -- part of the primary key, sarg cannot be NULL. Use an empty string | |
| 71 | -@ -- instead. | |
| 72 | -@ -- | |
| 73 | -@ -- For check-ins, sargs can be a tag that is on the check-in. Examples: | |
| 74 | -@ -- 'trunk', or 'release'. Notifications are only sent if that tag is | |
| 75 | -@ -- present. For wiki, the sarg is a glob pattern matching the page name. | |
| 76 | -@ -- For tickets, sarg is the UUID of the ticket. And so forth. | |
| 77 | -@ -- | |
| 78 | -@ -- For the 'x' subscription, email is sent for any timeline event whose | |
| 79 | -@ -- text matches the GLOB pattern defined by sarg. | |
| 80 | -@ -- | |
| 81 | -@ CREATE TABLE repository.subscription( | |
| 82 | -@ subscriberId INTEGER, -- Which user has subscribed | |
| 83 | -@ stype TEXT, -- event type | |
| 84 | -@ sarg TEXT, -- additional event restriction | |
| 85 | -@ PRIMARY KEY(stype,sarg,subscriberId) | |
| 86 | -@ ) WITHOUT ROWID; | |
| 87 | -@ CREATE INDEX repository.subscription_x1 ON subscription(subscriberId); | |
| 88 | -@ | |
| 89 | 61 | @ -- Email notifications that need to be sent. |
| 90 | 62 | @ -- |
| 91 | 63 | @ -- If the eventid key is an integer, then it corresponds to the |
| 92 | 64 | @ -- EVENT.OBJID table. Other kinds of eventids are reserved for |
| 93 | 65 | @ -- future expansion. |
| @@ -355,10 +327,14 @@ | ||
| 355 | 327 | ** COMMAND: email |
| 356 | 328 | ** |
| 357 | 329 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 358 | 330 | ** |
| 359 | 331 | ** Subcommands: |
| 332 | +** | |
| 333 | +** reset Hard reset of all email notification tables | |
| 334 | +** in the repository. This erases all subscription | |
| 335 | +** information. Use with extreme care. | |
| 360 | 336 | ** |
| 361 | 337 | ** send TO [OPTIONS] Send a single email message using whatever |
| 362 | 338 | ** email sending mechanism is currently configured. |
| 363 | 339 | ** Use this for testing the email configuration. |
| 364 | 340 | ** Options: |
| @@ -376,10 +352,30 @@ | ||
| 376 | 352 | int nCmd; |
| 377 | 353 | db_find_and_open_repository(0, 0); |
| 378 | 354 | email_schema(); |
| 379 | 355 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 380 | 356 | nCmd = (int)strlen(zCmd); |
| 357 | + if( strncmp(zCmd, "reset", nCmd)==0 ){ | |
| 358 | + Blob yn; | |
| 359 | + int c; | |
| 360 | + fossil_print( | |
| 361 | + "This will erase all content in the repository tables, thus\n" | |
| 362 | + "deleting all subscriber information. The information will be\n" | |
| 363 | + "unrecoverable.\n"); | |
| 364 | + prompt_user("Continue? (y/N) ", &yn); | |
| 365 | + c = blob_str(&yn)[0]; | |
| 366 | + if( c=='y' ){ | |
| 367 | + db_multi_exec( | |
| 368 | + "DROP TABLE IF EXISTS subscriber;\n" | |
| 369 | + "DROP TABLE IF EXISTS subscription;\n" | |
| 370 | + "DROP TABLE IF EXISTS email_pending;\n" | |
| 371 | + "DROP TABLE IF EXISTS email_bounce;\n" | |
| 372 | + ); | |
| 373 | + email_schema(); | |
| 374 | + } | |
| 375 | + blob_zero(&yn); | |
| 376 | + }else | |
| 381 | 377 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 382 | 378 | Blob prompt, body, hdr; |
| 383 | 379 | int sendAsBoth = find_option("both",0,0)!=0; |
| 384 | 380 | int sendAsHtml = find_option("html",0,0)!=0; |
| 385 | 381 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| @@ -438,11 +434,11 @@ | ||
| 438 | 434 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 439 | 435 | print_setting(pSetting); |
| 440 | 436 | } |
| 441 | 437 | } |
| 442 | 438 | else{ |
| 443 | - usage("send|setting"); | |
| 439 | + usage("reset|send|setting"); | |
| 444 | 440 | } |
| 445 | 441 | } |
| 446 | 442 | |
| 447 | 443 | /* |
| 448 | 444 | ** WEBPAGE: subscribe |
| @@ -449,32 +445,75 @@ | ||
| 449 | 445 | ** |
| 450 | 446 | ** Allow users to subscribe to email notifications, or to change or |
| 451 | 447 | ** verify their subscription. |
| 452 | 448 | */ |
| 453 | 449 | void subscribe_page(void){ |
| 450 | + int needCaptcha; | |
| 451 | + unsigned int uSeed; | |
| 452 | + const char *zDecoded; | |
| 453 | + char *zCaptcha; | |
| 454 | + | |
| 454 | 455 | login_check_credentials(); |
| 455 | 456 | if( !g.perm.EmailAlert ){ |
| 456 | 457 | login_needed(g.anon.EmailAlert); |
| 457 | 458 | return; |
| 458 | 459 | } |
| 459 | 460 | style_header("Email Subscription"); |
| 461 | + needCaptcha = P("usecaptcha")!=0 || login_is_nobody() | |
| 462 | + || login_is_special(g.zLogin); | |
| 460 | 463 | form_begin(0, "%R/subscribe"); |
| 461 | 464 | @ <table class="subscribe"> |
| 462 | 465 | @ <tr> |
| 463 | - @ <td class="subscribe_label">Nickname:</td> | |
| 464 | - @ <td><input type="text" id="nn" value="" size="30"></td> | |
| 466 | + @ <td class="form_label">Email Address:</td> | |
| 467 | + @ <td><input type="text" name="e" value="" size="30"></td> | |
| 468 | + @ <td></td> | |
| 469 | + @ </tr> | |
| 470 | + if( needCaptcha ){ | |
| 471 | + uSeed = captcha_seed(); | |
| 472 | + zDecoded = captcha_decode(uSeed); | |
| 473 | + zCaptcha = captcha_render(zDecoded); | |
| 474 | + @ <tr> | |
| 475 | + @ <td class="form_label">Security Code:</td> | |
| 476 | + @ <td><input type="text" name="captcha" value="" size="30"> | |
| 477 | + @ <input type="hidden" name="usecaptcha" value="1"></td> | |
| 478 | + @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> | |
| 479 | + @ <td><span class="optionalTag">(copy from below)</span></td> | |
| 480 | + @ </tr> | |
| 481 | + } | |
| 482 | + @ <tr> | |
| 483 | + @ <td class="form_label">Nickname:</td> | |
| 484 | + @ <td><input type="text" name="nn" value="" size="30"></td> | |
| 485 | + @ <td><span class="optionalTag">(optional)</span></td> | |
| 486 | + @ </tr> | |
| 487 | + @ <tr> | |
| 488 | + @ <td class="form_label">Password:</td> | |
| 489 | + @ <td><input type="password" name="pw" value="" size="30"></td> | |
| 465 | 490 | @ <td><span class="optionalTag">(optional)</span></td> |
| 466 | 491 | @ </tr> |
| 467 | 492 | @ <tr> |
| 468 | - @ <td class="subscribe_label">Email Address:</td> | |
| 469 | - @ <td><input type="text" id="e" value="" size="30"></td> | |
| 470 | - @ <td></td> | |
| 493 | + @ <td class="form_label">Options:</td> | |
| 494 | + @ <td><label><input type="checkbox" name="sa" value="0">\ | |
| 495 | + @ Announcements</label><br> | |
| 496 | + @ <label><input type="checkbox" name="sc" value="0">\ | |
| 497 | + @ Check-ins</label><br> | |
| 498 | + @ <label><input type="checkbox" name="st" value="0">\ | |
| 499 | + @ Ticket changes</label><br> | |
| 500 | + @ <label><input type="checkbox" name="sw" value="0">\ | |
| 501 | + @ Wiki</label><br> | |
| 502 | + @ <label><input type="checkbox" name="di" value="0">\ | |
| 503 | + @ Daily digest only</label><br></td> | |
| 471 | 504 | @ </tr> |
| 472 | 505 | @ <tr> |
| 473 | - @ <td class="subscribe_label">Password:</td> | |
| 474 | - @ <td><input type="password" id="p1" value="" size="30"></td> | |
| 475 | - @ <td><span class="optionalTag">(optional)</span></td> | |
| 506 | + @ <td></td> | |
| 507 | + @ <td><input type="submit" value="Submit"></td> | |
| 476 | 508 | @ </tr> |
| 477 | - | |
| 478 | - | |
| 479 | - | |
| 509 | + @ </table> | |
| 510 | + if( needCaptcha ){ | |
| 511 | + @ <div class="captcha"><table class="captcha"><tr><td><pre> | |
| 512 | + @ %h(zCaptcha) | |
| 513 | + @ </pre> | |
| 514 | + @ Enter the 8 characters above in the "Security Code" box | |
| 515 | + @ </td></tr></table></div> | |
| 516 | + } | |
| 517 | + @ </form> | |
| 518 | + style_footer(); | |
| 480 | 519 | } |
| 481 | 520 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -30,10 +30,20 @@ | |
| 30 | @ -- the USER table without being a subscriber. Or a person can be a |
| 31 | @ -- subscriber without having a USER table entry. Or they can have both. |
| 32 | @ -- In the last case the suname column points from the subscriber entry |
| 33 | @ -- to the USER entry. |
| 34 | @ -- |
| 35 | @ CREATE TABLE repository.subscriber( |
| 36 | @ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use |
| 37 | @ subscriberCode TEXT UNIQUE, -- UUID for subscriber. External use |
| 38 | @ sname TEXT, -- Human readable name |
| 39 | @ suname TEXT, -- Corresponding USER or NULL |
| @@ -46,48 +56,10 @@ | |
| 46 | @ smtime DATE, -- Last change. JulianDay |
| 47 | @ sipaddr TEXT, -- IP address for last change |
| 48 | @ spswdHash TEXT -- SHA3 hash of password |
| 49 | @ ); |
| 50 | @ |
| 51 | @ -- Each subscriber is associated with zero or more subscriptions. Each |
| 52 | @ -- subscription identifies events for which the subscriber desires |
| 53 | @ -- email notification. |
| 54 | @ -- |
| 55 | @ -- The stype field can be: |
| 56 | @ -- |
| 57 | @ -- 'c' Check-ins |
| 58 | @ -- 'w' Wiki pages |
| 59 | @ -- 't' Tickets |
| 60 | @ -- 'e' Tech-notes |
| 61 | @ -- 'g' Tags |
| 62 | @ -- 'f' Forum posts |
| 63 | @ -- 'm' Any item in need of moderation |
| 64 | @ -- |
| 65 | @ -- stype values are restricted to items that suname is allowed to see. |
| 66 | @ -- If suname is NULL, then stype values are restricted to things that |
| 67 | @ -- user "nobody" is allowed to see. |
| 68 | @ -- |
| 69 | @ -- The sarg field provides additional restrictions. Since it is |
| 70 | @ -- part of the primary key, sarg cannot be NULL. Use an empty string |
| 71 | @ -- instead. |
| 72 | @ -- |
| 73 | @ -- For check-ins, sargs can be a tag that is on the check-in. Examples: |
| 74 | @ -- 'trunk', or 'release'. Notifications are only sent if that tag is |
| 75 | @ -- present. For wiki, the sarg is a glob pattern matching the page name. |
| 76 | @ -- For tickets, sarg is the UUID of the ticket. And so forth. |
| 77 | @ -- |
| 78 | @ -- For the 'x' subscription, email is sent for any timeline event whose |
| 79 | @ -- text matches the GLOB pattern defined by sarg. |
| 80 | @ -- |
| 81 | @ CREATE TABLE repository.subscription( |
| 82 | @ subscriberId INTEGER, -- Which user has subscribed |
| 83 | @ stype TEXT, -- event type |
| 84 | @ sarg TEXT, -- additional event restriction |
| 85 | @ PRIMARY KEY(stype,sarg,subscriberId) |
| 86 | @ ) WITHOUT ROWID; |
| 87 | @ CREATE INDEX repository.subscription_x1 ON subscription(subscriberId); |
| 88 | @ |
| 89 | @ -- Email notifications that need to be sent. |
| 90 | @ -- |
| 91 | @ -- If the eventid key is an integer, then it corresponds to the |
| 92 | @ -- EVENT.OBJID table. Other kinds of eventids are reserved for |
| 93 | @ -- future expansion. |
| @@ -355,10 +327,14 @@ | |
| 355 | ** COMMAND: email |
| 356 | ** |
| 357 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 358 | ** |
| 359 | ** Subcommands: |
| 360 | ** |
| 361 | ** send TO [OPTIONS] Send a single email message using whatever |
| 362 | ** email sending mechanism is currently configured. |
| 363 | ** Use this for testing the email configuration. |
| 364 | ** Options: |
| @@ -376,10 +352,30 @@ | |
| 376 | int nCmd; |
| 377 | db_find_and_open_repository(0, 0); |
| 378 | email_schema(); |
| 379 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 380 | nCmd = (int)strlen(zCmd); |
| 381 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 382 | Blob prompt, body, hdr; |
| 383 | int sendAsBoth = find_option("both",0,0)!=0; |
| 384 | int sendAsHtml = find_option("html",0,0)!=0; |
| 385 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| @@ -438,11 +434,11 @@ | |
| 438 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 439 | print_setting(pSetting); |
| 440 | } |
| 441 | } |
| 442 | else{ |
| 443 | usage("send|setting"); |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | /* |
| 448 | ** WEBPAGE: subscribe |
| @@ -449,32 +445,75 @@ | |
| 449 | ** |
| 450 | ** Allow users to subscribe to email notifications, or to change or |
| 451 | ** verify their subscription. |
| 452 | */ |
| 453 | void subscribe_page(void){ |
| 454 | login_check_credentials(); |
| 455 | if( !g.perm.EmailAlert ){ |
| 456 | login_needed(g.anon.EmailAlert); |
| 457 | return; |
| 458 | } |
| 459 | style_header("Email Subscription"); |
| 460 | form_begin(0, "%R/subscribe"); |
| 461 | @ <table class="subscribe"> |
| 462 | @ <tr> |
| 463 | @ <td class="subscribe_label">Nickname:</td> |
| 464 | @ <td><input type="text" id="nn" value="" size="30"></td> |
| 465 | @ <td><span class="optionalTag">(optional)</span></td> |
| 466 | @ </tr> |
| 467 | @ <tr> |
| 468 | @ <td class="subscribe_label">Email Address:</td> |
| 469 | @ <td><input type="text" id="e" value="" size="30"></td> |
| 470 | @ <td></td> |
| 471 | @ </tr> |
| 472 | @ <tr> |
| 473 | @ <td class="subscribe_label">Password:</td> |
| 474 | @ <td><input type="password" id="p1" value="" size="30"></td> |
| 475 | @ <td><span class="optionalTag">(optional)</span></td> |
| 476 | @ </tr> |
| 477 | |
| 478 | |
| 479 | |
| 480 | } |
| 481 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -30,10 +30,20 @@ | |
| 30 | @ -- the USER table without being a subscriber. Or a person can be a |
| 31 | @ -- subscriber without having a USER table entry. Or they can have both. |
| 32 | @ -- In the last case the suname column points from the subscriber entry |
| 33 | @ -- to the USER entry. |
| 34 | @ -- |
| 35 | @ -- The ssub field is a string where each character indicates a particular |
| 36 | @ -- type of event to subscribe to. Choices: |
| 37 | @ -- a - Announcements |
| 38 | @ -- c - Check-ins |
| 39 | @ -- t - Ticket changes |
| 40 | @ -- w - Wiki changes |
| 41 | @ -- Probably different codes will be added in the future. In the future |
| 42 | @ -- we might also add a separate table that allows subscribing to email |
| 43 | @ -- notifications for specific branches or tags or tickets. |
| 44 | @ -- |
| 45 | @ CREATE TABLE repository.subscriber( |
| 46 | @ subscriberId INTEGER PRIMARY KEY, -- numeric subscriber ID. Internal use |
| 47 | @ subscriberCode TEXT UNIQUE, -- UUID for subscriber. External use |
| 48 | @ sname TEXT, -- Human readable name |
| 49 | @ suname TEXT, -- Corresponding USER or NULL |
| @@ -46,48 +56,10 @@ | |
| 56 | @ smtime DATE, -- Last change. JulianDay |
| 57 | @ sipaddr TEXT, -- IP address for last change |
| 58 | @ spswdHash TEXT -- SHA3 hash of password |
| 59 | @ ); |
| 60 | @ |
| 61 | @ -- Email notifications that need to be sent. |
| 62 | @ -- |
| 63 | @ -- If the eventid key is an integer, then it corresponds to the |
| 64 | @ -- EVENT.OBJID table. Other kinds of eventids are reserved for |
| 65 | @ -- future expansion. |
| @@ -355,10 +327,14 @@ | |
| 327 | ** COMMAND: email |
| 328 | ** |
| 329 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 330 | ** |
| 331 | ** Subcommands: |
| 332 | ** |
| 333 | ** reset Hard reset of all email notification tables |
| 334 | ** in the repository. This erases all subscription |
| 335 | ** information. Use with extreme care. |
| 336 | ** |
| 337 | ** send TO [OPTIONS] Send a single email message using whatever |
| 338 | ** email sending mechanism is currently configured. |
| 339 | ** Use this for testing the email configuration. |
| 340 | ** Options: |
| @@ -376,10 +352,30 @@ | |
| 352 | int nCmd; |
| 353 | db_find_and_open_repository(0, 0); |
| 354 | email_schema(); |
| 355 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 356 | nCmd = (int)strlen(zCmd); |
| 357 | if( strncmp(zCmd, "reset", nCmd)==0 ){ |
| 358 | Blob yn; |
| 359 | int c; |
| 360 | fossil_print( |
| 361 | "This will erase all content in the repository tables, thus\n" |
| 362 | "deleting all subscriber information. The information will be\n" |
| 363 | "unrecoverable.\n"); |
| 364 | prompt_user("Continue? (y/N) ", &yn); |
| 365 | c = blob_str(&yn)[0]; |
| 366 | if( c=='y' ){ |
| 367 | db_multi_exec( |
| 368 | "DROP TABLE IF EXISTS subscriber;\n" |
| 369 | "DROP TABLE IF EXISTS subscription;\n" |
| 370 | "DROP TABLE IF EXISTS email_pending;\n" |
| 371 | "DROP TABLE IF EXISTS email_bounce;\n" |
| 372 | ); |
| 373 | email_schema(); |
| 374 | } |
| 375 | blob_zero(&yn); |
| 376 | }else |
| 377 | if( strncmp(zCmd, "send", nCmd)==0 ){ |
| 378 | Blob prompt, body, hdr; |
| 379 | int sendAsBoth = find_option("both",0,0)!=0; |
| 380 | int sendAsHtml = find_option("html",0,0)!=0; |
| 381 | const char *zDest = find_option("stdout",0,0)!=0 ? "stdout" : 0; |
| @@ -438,11 +434,11 @@ | |
| 434 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 435 | print_setting(pSetting); |
| 436 | } |
| 437 | } |
| 438 | else{ |
| 439 | usage("reset|send|setting"); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | /* |
| 444 | ** WEBPAGE: subscribe |
| @@ -449,32 +445,75 @@ | |
| 445 | ** |
| 446 | ** Allow users to subscribe to email notifications, or to change or |
| 447 | ** verify their subscription. |
| 448 | */ |
| 449 | void subscribe_page(void){ |
| 450 | int needCaptcha; |
| 451 | unsigned int uSeed; |
| 452 | const char *zDecoded; |
| 453 | char *zCaptcha; |
| 454 | |
| 455 | login_check_credentials(); |
| 456 | if( !g.perm.EmailAlert ){ |
| 457 | login_needed(g.anon.EmailAlert); |
| 458 | return; |
| 459 | } |
| 460 | style_header("Email Subscription"); |
| 461 | needCaptcha = P("usecaptcha")!=0 || login_is_nobody() |
| 462 | || login_is_special(g.zLogin); |
| 463 | form_begin(0, "%R/subscribe"); |
| 464 | @ <table class="subscribe"> |
| 465 | @ <tr> |
| 466 | @ <td class="form_label">Email Address:</td> |
| 467 | @ <td><input type="text" name="e" value="" size="30"></td> |
| 468 | @ <td></td> |
| 469 | @ </tr> |
| 470 | if( needCaptcha ){ |
| 471 | uSeed = captcha_seed(); |
| 472 | zDecoded = captcha_decode(uSeed); |
| 473 | zCaptcha = captcha_render(zDecoded); |
| 474 | @ <tr> |
| 475 | @ <td class="form_label">Security Code:</td> |
| 476 | @ <td><input type="text" name="captcha" value="" size="30"> |
| 477 | @ <input type="hidden" name="usecaptcha" value="1"></td> |
| 478 | @ <input type="hidden" name="captchaseed" value="%u(uSeed)"></td> |
| 479 | @ <td><span class="optionalTag">(copy from below)</span></td> |
| 480 | @ </tr> |
| 481 | } |
| 482 | @ <tr> |
| 483 | @ <td class="form_label">Nickname:</td> |
| 484 | @ <td><input type="text" name="nn" value="" size="30"></td> |
| 485 | @ <td><span class="optionalTag">(optional)</span></td> |
| 486 | @ </tr> |
| 487 | @ <tr> |
| 488 | @ <td class="form_label">Password:</td> |
| 489 | @ <td><input type="password" name="pw" value="" size="30"></td> |
| 490 | @ <td><span class="optionalTag">(optional)</span></td> |
| 491 | @ </tr> |
| 492 | @ <tr> |
| 493 | @ <td class="form_label">Options:</td> |
| 494 | @ <td><label><input type="checkbox" name="sa" value="0">\ |
| 495 | @ Announcements</label><br> |
| 496 | @ <label><input type="checkbox" name="sc" value="0">\ |
| 497 | @ Check-ins</label><br> |
| 498 | @ <label><input type="checkbox" name="st" value="0">\ |
| 499 | @ Ticket changes</label><br> |
| 500 | @ <label><input type="checkbox" name="sw" value="0">\ |
| 501 | @ Wiki</label><br> |
| 502 | @ <label><input type="checkbox" name="di" value="0">\ |
| 503 | @ Daily digest only</label><br></td> |
| 504 | @ </tr> |
| 505 | @ <tr> |
| 506 | @ <td></td> |
| 507 | @ <td><input type="submit" value="Submit"></td> |
| 508 | @ </tr> |
| 509 | @ </table> |
| 510 | if( needCaptcha ){ |
| 511 | @ <div class="captcha"><table class="captcha"><tr><td><pre> |
| 512 | @ %h(zCaptcha) |
| 513 | @ </pre> |
| 514 | @ Enter the 8 characters above in the "Security Code" box |
| 515 | @ </td></tr></table></div> |
| 516 | } |
| 517 | @ </form> |
| 518 | style_footer(); |
| 519 | } |
| 520 |