Fossil SCM
Add the "fossil email subscribers" and "fossil email unsubscribe" commands.
Commit
ba60f8744c69d6122d56186fcb7fa9df8740f9434715dc3021be67a77e6b277c
Parent
44f9f3559795393…
1 file changed
+79
-9
+79
-9
| --- src/email.c | ||
| +++ src/email.c | ||
| @@ -453,10 +453,18 @@ | ||
| 453 | 453 | ** COMMAND: email |
| 454 | 454 | ** |
| 455 | 455 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 456 | 456 | ** |
| 457 | 457 | ** Subcommands: |
| 458 | +** | |
| 459 | +** exec Compose and send pending email alerts. | |
| 460 | +** Some installations may want to do this via | |
| 461 | +** a cron-job to make sure alerts are sent | |
| 462 | +** in a timely manner. | |
| 463 | +** Options: | |
| 464 | +** | |
| 465 | +** --digest Send digests | |
| 458 | 466 | ** |
| 459 | 467 | ** inbound [FILE] Receive an inbound email message. This message |
| 460 | 468 | ** is analyzed to see if it is a bounce, and if |
| 461 | 469 | ** necessary, subscribers may be disabled. |
| 462 | 470 | ** |
| @@ -474,18 +482,28 @@ | ||
| 474 | 482 | ** --stdout |
| 475 | 483 | ** --subject|-S SUBJECT |
| 476 | 484 | ** |
| 477 | 485 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 478 | 486 | ** Or change the value of a single email setting. |
| 487 | +** | |
| 488 | +** subscribers [PATTERN] List all subscribers matching PATTERN. | |
| 489 | +** | |
| 490 | +** unsubscribe EMAIL Remove a single subscriber with the given EMAIL. | |
| 479 | 491 | */ |
| 480 | 492 | void email_cmd(void){ |
| 481 | 493 | const char *zCmd; |
| 482 | 494 | int nCmd; |
| 483 | 495 | db_find_and_open_repository(0, 0); |
| 484 | 496 | email_schema(); |
| 485 | 497 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 486 | 498 | nCmd = (int)strlen(zCmd); |
| 499 | + if( strncmp(zCmd, "exec", nCmd)==0 ){ | |
| 500 | + u32 eFlags = 0; | |
| 501 | + if( find_option("digest",0,0)!=0 ) eFlags |= SENDALERT_DIGEST; | |
| 502 | + verify_all_options(); | |
| 503 | + email_send_alerts(eFlags); | |
| 504 | + }else | |
| 487 | 505 | if( strncmp(zCmd, "inbound", nCmd)==0 ){ |
| 488 | 506 | Blob email; |
| 489 | 507 | const char *zInboundDir = db_get("email-receive-dir",""); |
| 490 | 508 | verify_all_options(); |
| 491 | 509 | if( g.argc!=3 && g.argc!=4 ){ |
| @@ -564,12 +582,12 @@ | ||
| 564 | 582 | email_send(&hdr, &body, 0, zDest); |
| 565 | 583 | } |
| 566 | 584 | blob_zero(&hdr); |
| 567 | 585 | blob_zero(&body); |
| 568 | 586 | blob_zero(&prompt); |
| 569 | - } | |
| 570 | - else if( strncmp(zCmd, "settings", nCmd)==0 ){ | |
| 587 | + }else | |
| 588 | + if( strncmp(zCmd, "settings", nCmd)==0 ){ | |
| 571 | 589 | int isGlobal = find_option("global",0,0)!=0; |
| 572 | 590 | int nSetting; |
| 573 | 591 | const Setting *pSetting = setting_info(&nSetting); |
| 574 | 592 | db_open_config(1, 0); |
| 575 | 593 | verify_all_options(); |
| @@ -586,13 +604,41 @@ | ||
| 586 | 604 | pSetting = setting_info(&nSetting); |
| 587 | 605 | for(; nSetting>0; nSetting--, pSetting++ ){ |
| 588 | 606 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 589 | 607 | print_setting(pSetting); |
| 590 | 608 | } |
| 591 | - } | |
| 592 | - else{ | |
| 593 | - usage("inbound|reset|send|setting"); | |
| 609 | + }else | |
| 610 | + if( strncmp(zCmd, "subscribers", nCmd)==0 ){ | |
| 611 | + Stmt q; | |
| 612 | + verify_all_options(); | |
| 613 | + if( g.argc!=3 && g.argc!=4 ) usage("subscribers [PATTERN]"); | |
| 614 | + if( g.argc==4 ){ | |
| 615 | + char *zPattern = g.argv[3]; | |
| 616 | + db_prepare(&q, | |
| 617 | + "SELECT semail FROM subscriber" | |
| 618 | + " WHERE semail LIKE '%%%q%%' OR suname LIKE '%%%q%%'" | |
| 619 | + " OR semail GLOB '*%q*' or suname GLOB '*%q*'" | |
| 620 | + " ORDER BY semail", | |
| 621 | + zPattern, zPattern, zPattern, zPattern); | |
| 622 | + }else{ | |
| 623 | + db_prepare(&q, | |
| 624 | + "SELECT semail FROM subscriber" | |
| 625 | + " ORDER BY semail"); | |
| 626 | + } | |
| 627 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 628 | + fossil_print("%s\n", db_column_text(&q, 0)); | |
| 629 | + } | |
| 630 | + db_finalize(&q); | |
| 631 | + }else | |
| 632 | + if( strncmp(zCmd, "unsubscribe", nCmd)==0 ){ | |
| 633 | + verify_all_options(); | |
| 634 | + if( g.argc!=4 ) usage("unsubscribe EMAIL"); | |
| 635 | + db_multi_exec( | |
| 636 | + "DELETE FROM subscriber WHERE semail=%Q", g.argv[3]); | |
| 637 | + }else | |
| 638 | + { | |
| 639 | + usage("exec|inbound|reset|send|setting|subscribers|unsubscribe"); | |
| 594 | 640 | } |
| 595 | 641 | } |
| 596 | 642 | |
| 597 | 643 | /* |
| 598 | 644 | ** Do error checking on a submitted subscription form. Return TRUE |
| @@ -1393,10 +1439,31 @@ | ||
| 1393 | 1439 | email_footer(&out); |
| 1394 | 1440 | fossil_print("%s", blob_str(&out)); |
| 1395 | 1441 | blob_zero(&out); |
| 1396 | 1442 | db_end_transaction(0); |
| 1397 | 1443 | } |
| 1444 | + | |
| 1445 | +/* | |
| 1446 | +** COMMAND: test-add-alerts | |
| 1447 | +** | |
| 1448 | +** Usage: %fossil test-add-alerts EVENTID ... | |
| 1449 | +** | |
| 1450 | +** Add one or more events to the pending_alert queue. Use this | |
| 1451 | +** command during testing to force email notifications for specific | |
| 1452 | +** events. | |
| 1453 | +*/ | |
| 1454 | +void test_add_alert_cmd(void){ | |
| 1455 | + int i; | |
| 1456 | + db_find_and_open_repository(0, 0); | |
| 1457 | + verify_all_options(); | |
| 1458 | + db_begin_transaction(); | |
| 1459 | + email_schema(); | |
| 1460 | + for(i=2; i<g.argc; i++){ | |
| 1461 | + db_multi_exec("INSERT INTO pending_alert(eventId) VALUES(%Q)", g.argv[i]); | |
| 1462 | + } | |
| 1463 | + db_end_transaction(0); | |
| 1464 | +} | |
| 1398 | 1465 | |
| 1399 | 1466 | #if INTERFACE |
| 1400 | 1467 | /* |
| 1401 | 1468 | ** Flags for email_send_alerts() |
| 1402 | 1469 | */ |
| @@ -1416,17 +1483,18 @@ | ||
| 1416 | 1483 | Blob hdr, body; |
| 1417 | 1484 | const char *zUrl; |
| 1418 | 1485 | const char *zRepoName; |
| 1419 | 1486 | const char *zFrom; |
| 1420 | 1487 | |
| 1421 | - if( !email_enabled() ) return; | |
| 1488 | + db_begin_transaction(); | |
| 1489 | + if( !email_enabled() ) goto send_alerts_done; | |
| 1422 | 1490 | zUrl = db_get("email-url",0); |
| 1423 | - if( zUrl==0 ) return; | |
| 1491 | + if( zUrl==0 ) goto send_alerts_done; | |
| 1424 | 1492 | zRepoName = db_get("email-subname",0); |
| 1425 | - if( zRepoName==0 ) return; | |
| 1493 | + if( zRepoName==0 ) goto send_alerts_done; | |
| 1426 | 1494 | zFrom = db_get("email-self",0); |
| 1427 | - if( zFrom==0 ) return; | |
| 1495 | + if( zFrom==0 ) goto send_alerts_done; | |
| 1428 | 1496 | db_multi_exec( |
| 1429 | 1497 | "DROP TABLE IF EXISTS temp.wantalert;" |
| 1430 | 1498 | "CREATE TEMP TABLE wantalert(eventId TEXT);" |
| 1431 | 1499 | ); |
| 1432 | 1500 | if( flags & SENDALERT_DIGEST ){ |
| @@ -1493,6 +1561,8 @@ | ||
| 1493 | 1561 | }else{ |
| 1494 | 1562 | db_multi_exec("UPDATE pending_alert SET sentSep=true"); |
| 1495 | 1563 | } |
| 1496 | 1564 | db_multi_exec("DELETE FROM pending_alert WHERE sentDigest AND sentSep"); |
| 1497 | 1565 | } |
| 1566 | +send_alerts_done: | |
| 1567 | + db_end_transaction(0); | |
| 1498 | 1568 | } |
| 1499 | 1569 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -453,10 +453,18 @@ | |
| 453 | ** COMMAND: email |
| 454 | ** |
| 455 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 456 | ** |
| 457 | ** Subcommands: |
| 458 | ** |
| 459 | ** inbound [FILE] Receive an inbound email message. This message |
| 460 | ** is analyzed to see if it is a bounce, and if |
| 461 | ** necessary, subscribers may be disabled. |
| 462 | ** |
| @@ -474,18 +482,28 @@ | |
| 474 | ** --stdout |
| 475 | ** --subject|-S SUBJECT |
| 476 | ** |
| 477 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 478 | ** Or change the value of a single email setting. |
| 479 | */ |
| 480 | void email_cmd(void){ |
| 481 | const char *zCmd; |
| 482 | int nCmd; |
| 483 | db_find_and_open_repository(0, 0); |
| 484 | email_schema(); |
| 485 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 486 | nCmd = (int)strlen(zCmd); |
| 487 | if( strncmp(zCmd, "inbound", nCmd)==0 ){ |
| 488 | Blob email; |
| 489 | const char *zInboundDir = db_get("email-receive-dir",""); |
| 490 | verify_all_options(); |
| 491 | if( g.argc!=3 && g.argc!=4 ){ |
| @@ -564,12 +582,12 @@ | |
| 564 | email_send(&hdr, &body, 0, zDest); |
| 565 | } |
| 566 | blob_zero(&hdr); |
| 567 | blob_zero(&body); |
| 568 | blob_zero(&prompt); |
| 569 | } |
| 570 | else if( strncmp(zCmd, "settings", nCmd)==0 ){ |
| 571 | int isGlobal = find_option("global",0,0)!=0; |
| 572 | int nSetting; |
| 573 | const Setting *pSetting = setting_info(&nSetting); |
| 574 | db_open_config(1, 0); |
| 575 | verify_all_options(); |
| @@ -586,13 +604,41 @@ | |
| 586 | pSetting = setting_info(&nSetting); |
| 587 | for(; nSetting>0; nSetting--, pSetting++ ){ |
| 588 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 589 | print_setting(pSetting); |
| 590 | } |
| 591 | } |
| 592 | else{ |
| 593 | usage("inbound|reset|send|setting"); |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | /* |
| 598 | ** Do error checking on a submitted subscription form. Return TRUE |
| @@ -1393,10 +1439,31 @@ | |
| 1393 | email_footer(&out); |
| 1394 | fossil_print("%s", blob_str(&out)); |
| 1395 | blob_zero(&out); |
| 1396 | db_end_transaction(0); |
| 1397 | } |
| 1398 | |
| 1399 | #if INTERFACE |
| 1400 | /* |
| 1401 | ** Flags for email_send_alerts() |
| 1402 | */ |
| @@ -1416,17 +1483,18 @@ | |
| 1416 | Blob hdr, body; |
| 1417 | const char *zUrl; |
| 1418 | const char *zRepoName; |
| 1419 | const char *zFrom; |
| 1420 | |
| 1421 | if( !email_enabled() ) return; |
| 1422 | zUrl = db_get("email-url",0); |
| 1423 | if( zUrl==0 ) return; |
| 1424 | zRepoName = db_get("email-subname",0); |
| 1425 | if( zRepoName==0 ) return; |
| 1426 | zFrom = db_get("email-self",0); |
| 1427 | if( zFrom==0 ) return; |
| 1428 | db_multi_exec( |
| 1429 | "DROP TABLE IF EXISTS temp.wantalert;" |
| 1430 | "CREATE TEMP TABLE wantalert(eventId TEXT);" |
| 1431 | ); |
| 1432 | if( flags & SENDALERT_DIGEST ){ |
| @@ -1493,6 +1561,8 @@ | |
| 1493 | }else{ |
| 1494 | db_multi_exec("UPDATE pending_alert SET sentSep=true"); |
| 1495 | } |
| 1496 | db_multi_exec("DELETE FROM pending_alert WHERE sentDigest AND sentSep"); |
| 1497 | } |
| 1498 | } |
| 1499 |
| --- src/email.c | |
| +++ src/email.c | |
| @@ -453,10 +453,18 @@ | |
| 453 | ** COMMAND: email |
| 454 | ** |
| 455 | ** Usage: %fossil email SUBCOMMAND ARGS... |
| 456 | ** |
| 457 | ** Subcommands: |
| 458 | ** |
| 459 | ** exec Compose and send pending email alerts. |
| 460 | ** Some installations may want to do this via |
| 461 | ** a cron-job to make sure alerts are sent |
| 462 | ** in a timely manner. |
| 463 | ** Options: |
| 464 | ** |
| 465 | ** --digest Send digests |
| 466 | ** |
| 467 | ** inbound [FILE] Receive an inbound email message. This message |
| 468 | ** is analyzed to see if it is a bounce, and if |
| 469 | ** necessary, subscribers may be disabled. |
| 470 | ** |
| @@ -474,18 +482,28 @@ | |
| 482 | ** --stdout |
| 483 | ** --subject|-S SUBJECT |
| 484 | ** |
| 485 | ** settings [NAME VALUE] With no arguments, list all email settings. |
| 486 | ** Or change the value of a single email setting. |
| 487 | ** |
| 488 | ** subscribers [PATTERN] List all subscribers matching PATTERN. |
| 489 | ** |
| 490 | ** unsubscribe EMAIL Remove a single subscriber with the given EMAIL. |
| 491 | */ |
| 492 | void email_cmd(void){ |
| 493 | const char *zCmd; |
| 494 | int nCmd; |
| 495 | db_find_and_open_repository(0, 0); |
| 496 | email_schema(); |
| 497 | zCmd = g.argc>=3 ? g.argv[2] : "x"; |
| 498 | nCmd = (int)strlen(zCmd); |
| 499 | if( strncmp(zCmd, "exec", nCmd)==0 ){ |
| 500 | u32 eFlags = 0; |
| 501 | if( find_option("digest",0,0)!=0 ) eFlags |= SENDALERT_DIGEST; |
| 502 | verify_all_options(); |
| 503 | email_send_alerts(eFlags); |
| 504 | }else |
| 505 | if( strncmp(zCmd, "inbound", nCmd)==0 ){ |
| 506 | Blob email; |
| 507 | const char *zInboundDir = db_get("email-receive-dir",""); |
| 508 | verify_all_options(); |
| 509 | if( g.argc!=3 && g.argc!=4 ){ |
| @@ -564,12 +582,12 @@ | |
| 582 | email_send(&hdr, &body, 0, zDest); |
| 583 | } |
| 584 | blob_zero(&hdr); |
| 585 | blob_zero(&body); |
| 586 | blob_zero(&prompt); |
| 587 | }else |
| 588 | if( strncmp(zCmd, "settings", nCmd)==0 ){ |
| 589 | int isGlobal = find_option("global",0,0)!=0; |
| 590 | int nSetting; |
| 591 | const Setting *pSetting = setting_info(&nSetting); |
| 592 | db_open_config(1, 0); |
| 593 | verify_all_options(); |
| @@ -586,13 +604,41 @@ | |
| 604 | pSetting = setting_info(&nSetting); |
| 605 | for(; nSetting>0; nSetting--, pSetting++ ){ |
| 606 | if( strncmp(pSetting->name,"email-",6)!=0 ) continue; |
| 607 | print_setting(pSetting); |
| 608 | } |
| 609 | }else |
| 610 | if( strncmp(zCmd, "subscribers", nCmd)==0 ){ |
| 611 | Stmt q; |
| 612 | verify_all_options(); |
| 613 | if( g.argc!=3 && g.argc!=4 ) usage("subscribers [PATTERN]"); |
| 614 | if( g.argc==4 ){ |
| 615 | char *zPattern = g.argv[3]; |
| 616 | db_prepare(&q, |
| 617 | "SELECT semail FROM subscriber" |
| 618 | " WHERE semail LIKE '%%%q%%' OR suname LIKE '%%%q%%'" |
| 619 | " OR semail GLOB '*%q*' or suname GLOB '*%q*'" |
| 620 | " ORDER BY semail", |
| 621 | zPattern, zPattern, zPattern, zPattern); |
| 622 | }else{ |
| 623 | db_prepare(&q, |
| 624 | "SELECT semail FROM subscriber" |
| 625 | " ORDER BY semail"); |
| 626 | } |
| 627 | while( db_step(&q)==SQLITE_ROW ){ |
| 628 | fossil_print("%s\n", db_column_text(&q, 0)); |
| 629 | } |
| 630 | db_finalize(&q); |
| 631 | }else |
| 632 | if( strncmp(zCmd, "unsubscribe", nCmd)==0 ){ |
| 633 | verify_all_options(); |
| 634 | if( g.argc!=4 ) usage("unsubscribe EMAIL"); |
| 635 | db_multi_exec( |
| 636 | "DELETE FROM subscriber WHERE semail=%Q", g.argv[3]); |
| 637 | }else |
| 638 | { |
| 639 | usage("exec|inbound|reset|send|setting|subscribers|unsubscribe"); |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | /* |
| 644 | ** Do error checking on a submitted subscription form. Return TRUE |
| @@ -1393,10 +1439,31 @@ | |
| 1439 | email_footer(&out); |
| 1440 | fossil_print("%s", blob_str(&out)); |
| 1441 | blob_zero(&out); |
| 1442 | db_end_transaction(0); |
| 1443 | } |
| 1444 | |
| 1445 | /* |
| 1446 | ** COMMAND: test-add-alerts |
| 1447 | ** |
| 1448 | ** Usage: %fossil test-add-alerts EVENTID ... |
| 1449 | ** |
| 1450 | ** Add one or more events to the pending_alert queue. Use this |
| 1451 | ** command during testing to force email notifications for specific |
| 1452 | ** events. |
| 1453 | */ |
| 1454 | void test_add_alert_cmd(void){ |
| 1455 | int i; |
| 1456 | db_find_and_open_repository(0, 0); |
| 1457 | verify_all_options(); |
| 1458 | db_begin_transaction(); |
| 1459 | email_schema(); |
| 1460 | for(i=2; i<g.argc; i++){ |
| 1461 | db_multi_exec("INSERT INTO pending_alert(eventId) VALUES(%Q)", g.argv[i]); |
| 1462 | } |
| 1463 | db_end_transaction(0); |
| 1464 | } |
| 1465 | |
| 1466 | #if INTERFACE |
| 1467 | /* |
| 1468 | ** Flags for email_send_alerts() |
| 1469 | */ |
| @@ -1416,17 +1483,18 @@ | |
| 1483 | Blob hdr, body; |
| 1484 | const char *zUrl; |
| 1485 | const char *zRepoName; |
| 1486 | const char *zFrom; |
| 1487 | |
| 1488 | db_begin_transaction(); |
| 1489 | if( !email_enabled() ) goto send_alerts_done; |
| 1490 | zUrl = db_get("email-url",0); |
| 1491 | if( zUrl==0 ) goto send_alerts_done; |
| 1492 | zRepoName = db_get("email-subname",0); |
| 1493 | if( zRepoName==0 ) goto send_alerts_done; |
| 1494 | zFrom = db_get("email-self",0); |
| 1495 | if( zFrom==0 ) goto send_alerts_done; |
| 1496 | db_multi_exec( |
| 1497 | "DROP TABLE IF EXISTS temp.wantalert;" |
| 1498 | "CREATE TEMP TABLE wantalert(eventId TEXT);" |
| 1499 | ); |
| 1500 | if( flags & SENDALERT_DIGEST ){ |
| @@ -1493,6 +1561,8 @@ | |
| 1561 | }else{ |
| 1562 | db_multi_exec("UPDATE pending_alert SET sentSep=true"); |
| 1563 | } |
| 1564 | db_multi_exec("DELETE FROM pending_alert WHERE sentDigest AND sentSep"); |
| 1565 | } |
| 1566 | send_alerts_done: |
| 1567 | db_end_transaction(0); |
| 1568 | } |
| 1569 |