unsubscribe.pl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #! /usr/bin/perl
  2. # Copyright (C) 2010–2021 Alex Schroeder <alex@gnu.org>
  3. # This program is free software: you can redistribute it and/or modify it under
  4. # the terms of the GNU General Public License as published by the Free Software
  5. # Foundation, either version 3 of the License, or (at your option) any later
  6. # version.
  7. #
  8. # This program is distributed in the hope that it will be useful, but WITHOUT
  9. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License along with
  13. # this program. If not, see <http://www.gnu.org/licenses/>.
  14. =head1 NAME
  15. unsubscribe.pl - mass unsubscribe from Oddmuse
  16. =head2 SYNOPSIS
  17. B<perl unsubscribe.pl> F<MAILDB> [B<--regexp=>I<REGEXP>]
  18. B<perl unsubscribe.pl> F<MAILDB> [B<--dump>]
  19. =head2 DESCRIPTION
  20. If you use the Mail Extension to Oddmuse, you end up with subscriptions to very
  21. old pages. This script helps you unsubsribe people from old pages.
  22. C<--regexp> indicates a regular expression matching pages names
  23. The mandatory F<MAILDB> argument is the file containing all the mail
  24. subscriptions.
  25. =head2 EXAMPLES
  26. Make a copy, unsubscribe people, check a dump of the remaining subscriptions,
  27. and move the file back to the wiki data directory.
  28. cp ~/alexschroeder/mail.db copy.db
  29. perl ~/src/oddmuse/scripts/unsubscribe.pl copy.db --regexp='20[01][0-9]'
  30. perl ~/src/oddmuse/scripts/unsubscribe.pl copy.db --dump
  31. mv copy.db ~/alexschroeder/mail.db
  32. =cut;
  33. use Modern::Perl;
  34. use Getopt::Long;
  35. use Encode qw(encode_utf8 decode_utf8);
  36. use DB_File;
  37. binmode(STDOUT, ":utf8");
  38. my $re = "";
  39. my $confirm;
  40. my $dump;
  41. GetOptions ("regexp=s" => \$re,
  42. "dump" => \$dump,
  43. "confirm" => \$confirm, );
  44. my $file = shift;
  45. die "Not a file: $file" unless -f $file;
  46. die "Unknown arguments: @ARGV" if @ARGV;
  47. sub UrlEncode {
  48. my $str = shift;
  49. return '' unless $str;
  50. my @letters = split(//, encode_utf8($str));
  51. my %safe = map {$_ => 1} ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '-', '_', '.', '!', '~', '*', "'", '(', ')', '#');
  52. foreach my $letter (@letters) {
  53. $letter = sprintf("%%%02x", ord($letter)) unless $safe{$letter};
  54. }
  55. return join('', @letters);
  56. }
  57. sub UrlDecode {
  58. my $str = shift;
  59. return '' unless $str;
  60. $str =~ s/%([0-9a-f][0-9a-f])/chr(hex($1))/eig;
  61. return decode_utf8($str);
  62. }
  63. tie my %h, "DB_File", $file;
  64. my $FS = "\x1e";
  65. if ($dump) {
  66. for my $key (keys %h) {
  67. my @value = split /$FS/, UrlDecode($h{$key});
  68. say UrlDecode($key), ": @value";
  69. }
  70. exit;
  71. }
  72. for my $raw (keys %h) {
  73. if ($raw =~ /@/) {
  74. # email address
  75. my $mail = UrlDecode($raw);
  76. my $value = $h{$raw};
  77. my @subscriptions = grep !/$re/, map { UrlDecode($_) } split /$FS/, $value;
  78. if (@subscriptions) {
  79. $h{$raw} = join $FS, map { UrlEncode($_) } @subscriptions if $confirm;
  80. say "> $mail: remains subscribed to @subscriptions";
  81. } else {
  82. delete $h{$raw} if $confirm;
  83. say "> $mail: unsubscribe from all pages";
  84. }
  85. } else {
  86. my $id = UrlDecode($raw);
  87. next unless $id =~ /$re/;
  88. delete $h{$raw} if $confirm;
  89. say "Delete $id";
  90. }
  91. }
  92. untie %h;
  93. say "Use --confirm to actually do it" unless $confirm;