imap2wiki 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #!/usr/bin/perl -w
  2. #
  3. # Copyright (C) 2012 Alex Schroeder <alex@gnu.org>
  4. #
  5. # This program is free software: you can redistribute it and/or modify it under
  6. # the terms of the GNU General Public License as published by the Free Software
  7. # Foundation, either version 3 of the License, or (at your option) any later
  8. # version.
  9. #
  10. # This program is distributed in the hope that it will be useful, but WITHOUT
  11. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License along with
  15. # this program. If not, see <http://www.gnu.org/licenses/>.
  16. use strict;
  17. use Getopt::Std;
  18. use LWP::UserAgent;
  19. use Net::IMAP::Simple;
  20. use Email::Simple;
  21. use Email::MIME;
  22. use IO::Socket::SSL; # fail unless this is available
  23. my $usage = "Usage:\n"
  24. . " imap2wiki TARGET SERVER PORT FROM TO MAIL_USER MAIL_PASSWORD \\\n"
  25. . " MAIL_USER MAIL_PASSWORD WIKI_USER [WIKI_PASSWORD]\n\n"
  26. . "TARGET is the base URL for the wiki.\n"
  27. . "SERVER is the IMAP server you are checking.\n"
  28. . "PORT is the port you are using.\n"
  29. . " (We assume that you must use SSL.)\n"
  30. . "FROM is sender you are looking for.\n"
  31. . "TO is recipient you are looking for.\n"
  32. . "MAIL_USER is the username to connect to the mail server.\n"
  33. . "MAIL_PASSWORD is the password to use for the mail server.\n"
  34. . "WIKI_USER is the username to use for the edit.\n"
  35. . "WIKI_PASSWORD is the password to use if required.\n"
  36. . "Example:\n"
  37. . " imap2wiki http://www.emacswiki.org/cgi-bin/test imap.gmail.com 993 \\\n"
  38. . " kensanata\@gmail.com kensanata+post\@gmail.com \\\n"
  39. . " kensanata\@gmail.com '*secret*' \\\n"
  40. . " Alex test\n\n";
  41. sub UrlEncode {
  42. my $str = shift;
  43. return '' unless $str;
  44. my @letters = split(//, $str);
  45. my @safe = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '-', '_', '.', '!',
  46. '~', '*', "'", '(', ')', '#');
  47. foreach my $letter (@letters) {
  48. my $pattern = quotemeta($letter);
  49. if (not grep(/$pattern/, @safe)) {
  50. $letter = sprintf("%%%02x", ord($letter));
  51. }
  52. }
  53. return join('', @letters);
  54. }
  55. sub GetRaw {
  56. my ($uri) = @_;
  57. my $ua = LWP::UserAgent->new;
  58. my $response = $ua->get($uri);
  59. return $response->content if $response->is_success;
  60. }
  61. sub PostRaw {
  62. my ($uri, $id, $data, $user, $pwd) = @_;
  63. my $ua = LWP::UserAgent->new;
  64. my $summary;
  65. if ($data =~ /^#FILE (\S+) ?(\S+)?\n/) {
  66. $summary = 'file upload';
  67. }
  68. my $response = $ua->post($uri, {title=>$id, text=>$data, raw=>1,
  69. summary=>$summary,
  70. username=>$user, pwd=>$pwd});
  71. warn "POST $id failed: " . $response->status_line . "\n"
  72. unless $response->is_success;
  73. return $response->is_success;
  74. }
  75. sub post {
  76. my ($target, $page, $data, $user, $pwd) = @_;
  77. $page =~ s/ /_/g;
  78. $page = UrlEncode ($page);
  79. return PostRaw($target, $page, $data, $user, $pwd);
  80. }
  81. sub main {
  82. my ($target, $server, $port, $from, $to,
  83. $mail_user, $mail_pwd, $wiki_user, $wiki_pwd) = @ARGV;
  84. # all parameters except the wiki password are mandatory
  85. for my $arg ($target, $server, $port, $from, $to,
  86. $mail_user, $mail_pwd, $wiki_user) {
  87. die $usage unless $arg;
  88. }
  89. my $imap = Net::IMAP::Simple->new($server, port=>$port, use_ssl=>1 )
  90. or die "Unable to connect to IMAP: $Net::IMAP::Simple::errstr\n";
  91. if (not $imap->login($mail_user, $mail_pwd)) {
  92. print STDERR "Login failed: " . $imap->errstr . "\n";
  93. exit(64);
  94. }
  95. my %result;
  96. my $rfrom = quotemeta($from);
  97. my $rto = quotemeta($to);
  98. # go through the inbox and look for appropriate mails
  99. my $num = $imap->select('INBOX');
  100. for (my $i = 1; $i <= $num; $i++) {
  101. # looking at headers only
  102. my $email = Email::Simple->new(join '', @{ $imap->top($i) } );
  103. if ($email->header("From") =~ /$rfrom/io
  104. and $email->header("To") =~ /$rto/io) {
  105. my $subject = $email->header('Subject');
  106. my $n = 1;
  107. # fetch the body and parse the MIME stuff
  108. $email = Email::MIME->new(join '', @{ $imap->get($i) } );
  109. $email->walk_parts(sub {
  110. my ($part) = @_;
  111. return if $part->subparts; # multipart
  112. my ($pagename, $data);
  113. warn $part->content_type;
  114. if ($part->content_type =~ m[text/plain]i) {
  115. ($pagename, $data) = ($subject, $part->body);
  116. } elsif ($part->content_type =~ m!(image/[a-z]+)!i) {
  117. ($pagename, $data) = ($subject . " " . $n++,
  118. "#FILE " . $1 . "\n" . $part->body_raw);
  119. }
  120. if ($pagename and $data) {
  121. warn "Posting $pagename\n";
  122. post($target, $pagename, $data, $wiki_user, $wiki_pwd)
  123. || die "Posting aborted, INBOX not expunged\n";
  124. }
  125. } );
  126. # mark as deleted
  127. $imap->delete($i);
  128. }
  129. }
  130. # expunge messages that are marked for deletion
  131. $imap->quit;
  132. }
  133. main();