filter_conv_new.pl 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use XML::SimpleObject;
  4. # * This file is free software; you can redistribute it and/or modify it
  5. # * under the terms of the GNU General Public License as published by
  6. # * the Free Software Foundation; either version 3 of the License, or
  7. # * (at your option) any later version.
  8. # *
  9. # * This program is distributed in the hope that it will be useful, but
  10. # * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. # * General Public License for more details.
  13. # *
  14. # * You should have received a copy of the GNU General Public License
  15. # * along with this program; if not, write to the Free Software
  16. # * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. # *
  18. # * Copyright 2006 Paul Mangan <paul@claws-mail.org>
  19. # *
  20. #
  21. # Convert new style Sylpheed filter rules (Sylpheed >= 0.9.99) to
  22. # Claws Mail filtering rules
  23. #
  24. #
  25. # TABLE OF EQUIVALENTS
  26. #
  27. # SYLPHEED : Claws Mail
  28. #------------------------------------------------------
  29. #
  30. # NAME
  31. #
  32. # name : rulename
  33. #
  34. # CONDITION LIST
  35. #
  36. # bool or : |
  37. # bool and : &
  38. #
  39. # match-header (name From) : from
  40. # match-header (name To) : to
  41. # match-header (name Cc) : cc
  42. # match-header (name Subject) : subject
  43. # else...
  44. # match-header : header
  45. #
  46. # match-header (type contains) : [nothing]
  47. # match-header (type not-contain) : [append with ~]
  48. # match-header (type is) : [no equivalent] (use type contains)
  49. # match-header (type is-not) : [no equivalent] (use type not-contain)
  50. # match-header (type regex) : regexpcase
  51. # match-header (type not-regex) : regexpcase [append with ~]
  52. #
  53. # matcher-any-header ; headers-part
  54. # match-to-or-cc : to_or_cc
  55. # match-body-text : body_part
  56. # command-test : test
  57. # size (type gt) : size_greater
  58. # size (type lt) : size_smaller
  59. # age (type gt) : age_greater
  60. # age (type lt) : age_lower
  61. #
  62. # ACTION LIST
  63. #
  64. # move : move
  65. # copy : copy
  66. # not-receive : [no equivalent] (use type delete)
  67. # delete : delete
  68. # mark : mark
  69. # color-label : color
  70. # mark-as-read : mark_as_read
  71. # exec : execute
  72. # stop-eval : stop
  73. #
  74. my $old_config = "$ENV{HOME}/.sylpheed-2.0/filter.xml";
  75. my $older_config = "$ENV{HOME}/.sylpheed/filter.xml";
  76. my $old_filters;
  77. my $config_dir = `claws-mail --config-dir` or die("ERROR:
  78. You don't appear to have Claws Mail installed\n");
  79. chomp $config_dir;
  80. chdir($ENV{HOME} . "/$config_dir") or die("ERROR:
  81. Claws Mail config directory not found [~/$config_dir]
  82. You need to run Claws Mail once, quit it, and then rerun this script\n");
  83. if (-e $old_config) {
  84. $old_filters = $old_config;
  85. } elsif (-e $older_config) {
  86. $old_filters = $older_config;
  87. } else {
  88. print "ERROR:\n\tSylpheed filter not found\n\t[$old_config]\n\t[$older_config]\n";
  89. exit;
  90. }
  91. my $claws_version = `claws-mail --version`;
  92. $claws_version =~ s/^Claws Mail version //;
  93. my ($major, $minor) = split(/\./, $claws_version);
  94. my $version_test = 0;
  95. if ($major > 2 || ($major == 2 && $minor >= 3)) {
  96. $version_test = 1;
  97. }
  98. my $parser = XML::Parser->new(ErrorContext => 2, Style => "Tree");
  99. my $xmlobj = XML::SimpleObject->new($parser->parsefile($old_filters));
  100. my @conditions = ('match-header','match-to-or-cc','match-any-header',
  101. 'match-body-text','command-test','size','age');
  102. my @actions = ('copy','not-receive','mark','color-label','mark-as-read',
  103. 'exec','stop-eval','move','delete');
  104. my $standard_headers = qr/^(?:Subject|From|To|Cc)$/;
  105. my $negative_matches = qr/^(?:not-contain|is-not|not-regex)$/;
  106. my $numeric_matches = qr/^(?:size|age)$/;
  107. my $exact_matches = qr/^(?:move|copy|delete|mark)$/;
  108. my @new_filters = ("[filtering]");
  109. my $disabled = 0;
  110. my $bool;
  111. ## rules list
  112. foreach my $element ($xmlobj->child("filter")->children("rule")) {
  113. my $new_filter = "\n";
  114. if ($element->attribute("enabled")) {
  115. if ($element->attribute("enabled") eq "false") {
  116. if ($version_test) {
  117. $new_filter .= "disabled ";
  118. } else {
  119. $disabled++;
  120. next; # skip disabled rules
  121. }
  122. } elsif ($version_test) {
  123. $new_filter .= "enabled ";
  124. }
  125. }
  126. if ($element->attribute("name")) {
  127. my $name = $element->attribute("name");
  128. $name = clean_me($name);
  129. $new_filter .= "rulename \"$name\" ";
  130. }
  131. ## condition list
  132. foreach my $parent ($element->children("condition-list")) {
  133. if ($parent->attribute("bool")) {
  134. $bool = $parent->attribute("bool");
  135. $bool =~ s/or/|/;
  136. $bool =~ s/and/&/;
  137. }
  138. foreach my $condition (@conditions) {
  139. my $new_condition = 0;
  140. my $type;
  141. if ($parent->children("$condition")) {
  142. foreach my $sibling ($parent->children("$condition")) {
  143. if ($new_condition) {
  144. $new_filter .= " $bool ";
  145. }
  146. if ($sibling->attribute("type")) {
  147. $type = $sibling->attribute("type");
  148. if ($type =~ m/$negative_matches/) {
  149. $new_filter .= '~';
  150. }
  151. }
  152. if ($sibling->attribute("name")) {
  153. my $name = $sibling->attribute("name");
  154. if ($condition eq "match-header") {
  155. if ($name =~ m/$standard_headers/) {
  156. $new_filter .= lc($name) . " ";
  157. } else {
  158. $new_filter .= "header \"$name\" ";
  159. }
  160. }
  161. }
  162. if ($condition eq "match-any-header") {
  163. $new_filter .= "headers_part ";
  164. } elsif ($condition eq "match-header-content") {
  165. $new_filter .= "headers_cont ";
  166. } elsif ($condition eq "match-to-or-cc") {
  167. $new_filter .= "to_or_cc ";
  168. } elsif ($condition eq "match-body-text") {
  169. $new_filter .= "body_part ";
  170. } elsif ($condition eq "command-test") {
  171. $new_filter .= "test ";
  172. } elsif ($condition eq "size") {
  173. if ($type eq "gt") {
  174. $new_filter .= "size_greater ";
  175. } else {
  176. $new_filter .= "size_smaller ";
  177. }
  178. } elsif ($condition eq "age") {
  179. if ($type eq "gt") {
  180. $new_filter .= "age_greater ";
  181. } else {
  182. $new_filter .= "age_lower ";
  183. }
  184. }
  185. if ($condition !~ m/$numeric_matches/ &&
  186. $condition ne "command-test") {
  187. if ($type =~ m/regex/) {
  188. $new_filter .= "regexpcase ";
  189. } else {
  190. $new_filter .= "matchcase ";
  191. }
  192. }
  193. my $value = clean_me($sibling->value);
  194. if ($condition =~ m/$numeric_matches/) {
  195. $new_filter .= "$value";
  196. } else {
  197. $new_filter .= "\"$value\"";
  198. }
  199. $new_condition++;
  200. }
  201. }
  202. }
  203. }
  204. ## end of condition list
  205. ## action list
  206. foreach my $parent ($element->children("action-list")) {
  207. foreach my $action (@actions) {
  208. if ($parent->children("$action")) {
  209. foreach my $sibling ($parent->children("$action")) {
  210. if ($action =~ m/$exact_matches/) {
  211. $new_filter .= " $action";
  212. } elsif ($action eq "not-receive") {
  213. $new_filter .= " delete";
  214. } elsif ($action eq "color-label") {
  215. $new_filter .= " color";
  216. } elsif ($action eq "mark-as-read") {
  217. $new_filter .= " mark_as_read";
  218. } elsif ($action eq "exec") {
  219. $new_filter .= " execute";
  220. } elsif ($action eq "stop-eval") {
  221. $new_filter .= " stop";
  222. }
  223. if ($sibling->value) {
  224. my $value = clean_me($sibling->value);
  225. if ($action eq "color-label") {
  226. $new_filter .= " $value";
  227. } else {
  228. $new_filter .= " \"$value\"";
  229. }
  230. }
  231. }
  232. }
  233. }
  234. }
  235. ## end of action list
  236. push(@new_filters, $new_filter) if (defined($new_filter));
  237. }
  238. ## end of rules list
  239. push(@new_filters, "\n");
  240. # write new config
  241. open(MATCHERRC, ">>matcherrc");
  242. print MATCHERRC @new_filters;
  243. close(MATCHERRC);
  244. print "Converted ". ($#new_filters-1) . " filters\n";
  245. if ($disabled) {
  246. print "[$disabled disabled filter(s) not converted]\n";
  247. }
  248. exit;
  249. sub clean_me {
  250. my ($dirty) = @_;
  251. $dirty =~ s/\"/\\\"/g;
  252. $dirty =~ s/\n/ /g;
  253. return $dirty;
  254. }