summaryrefslogtreecommitdiff
path: root/lib/feed2imap/itemtomail.rb
blob: 6c70cbd52a7de1e4d2846e6245157e9ac9d54668 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
=begin
Feed2Imap - RSS/Atom Aggregator uploading to an IMAP Server
Copyright (c) 2005 Lucas Nussbaum <lucas@lucas-nussbaum.net>

This file contains classes to parse a feed and store it as a Channel object.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
=end

require 'rexml/document'
require 'time'
require 'rmail'
require 'feedparser'
require 'feedparser/text-output'
require 'feedparser/html-output'
require 'base64'
require 'rmail'
require 'digest/md5'

class String
  def needMIME
    utf8 = false
    begin
      self.unpack('U*').each do |c|
        if c > 127
          utf8 = true
          break
        end
      end
    rescue
      # safe fallback in case of problems
      utf8 = true
    end
    utf8
  end
end

def item_to_mail(config, item, id, updated, from = 'Feed2Imap', inline_images = false, wrapto = false)
  message = RMail::Message::new
  if item.creator and item.creator != ''
    if item.creator.include?('@')
      message.header['From'] = item.creator.chomp
    else
      message.header['From'] = "=?utf-8?b?#{Base64::encode64(item.creator.chomp).gsub("\n",'')}?= <#{config.default_email}>"
    end
  else
    message.header['From'] = "=?utf-8?b?#{Base64::encode64(from).gsub("\n",'')}?= <#{config.default_email}>"
  end
  message.header['To'] = "=?utf-8?b?#{Base64::encode64(from).gsub("\n",'')}?= <#{config.default_email}>"

  if item.date.nil?
    message.header['Date'] = Time::new.rfc2822
  else
    message.header['Date'] = item.date.rfc2822
  end
  message.header['X-Feed2Imap-Version'] = F2I_VERSION if defined?(F2I_VERSION)
  message.header['Message-Id'] = id
  message.header['X-F2IStatus'] = "Updated" if updated
  # treat subject. Might need MIME encoding.
  subj = item.title or (item.date and item.date.to_s) or item.link
  if subj
    if subj.needMIME
      message.header['Subject'] = "=?utf-8?b?#{Base64::encode64(subj).gsub("\n",'')}?="
    else
      message.header['Subject'] = subj
    end
  end
  textpart = RMail::Message::new
  textpart.header['Content-Type'] = 'text/plain; charset=utf-8; format=flowed'
  textpart.header['Content-Transfer-Encoding'] = '8bit'
  textpart.body = item.to_text(true, wrapto, false)
  htmlpart = RMail::Message::new
  htmlpart.header['Content-Type'] = 'text/html; charset=utf-8'
  htmlpart.header['Content-Transfer-Encoding'] = '8bit'
  htmlpart.body = item.to_html

  # inline images as attachments
  imgs = []
  if inline_images
    cids = []
    htmlpart.body.gsub!(/(<img[^>]+)src="(\S+?\/([^\/]+?\.(png|gif|jpe?g)))"([^>]*>)/i) do |match|
      # $2 contains url, $3 the image name, $4 the image extension
      begin
        image = Base64.encode64(HTTPFetcher::fetch($2, Time.at(0)).chomp) + "\n"
        cid = "#{Digest::MD5.hexdigest($2)}@#{config.hostname}"
        if not cids.include?(cid)
          cids << cid
          imgpart = RMail::Message.new
          imgpart.header.set('Content-ID', "<#{cid}>")
          type = $4
          type = 'jpeg' if type.downcase == 'jpg' # hack hack hack
          imgpart.header.set('Content-Type', "image/#{type}", 'name' => $3)
          imgpart.header.set('Content-Disposition', 'attachment', 'filename' => $3)
          imgpart.header.set('Content-Transfer-Encoding', 'base64')
          imgpart.body = image
          imgs << imgpart
        end
        # now to specify what to replace with
        newtag = "#{$1}src=\"cid:#{cid}\"#{$5}"
        #print "#{cid}: Replacing '#{$&}' with '#{newtag}'...\n"
        newtag
      rescue
        #print "Error while fetching image #{$2}: #{$!}...\n"
        $& # don't modify on exception
      end
    end
  end
  if imgs.length > 0
    message.header.set('Content-Type', 'multipart/related', 'type'=> 'multipart/alternative')
    texthtml = RMail::Message::new
    texthtml.header.set('Content-Type', 'multipart/alternative')
    texthtml.add_part(textpart)
    texthtml.add_part(htmlpart)
    message.add_part(texthtml)
    imgs.each do |i|
      message.add_part(i)
    end
  else
    message.header['Content-Type'] = 'multipart/alternative'
    message.add_part(textpart)
    message.add_part(htmlpart)
  end
  return message.to_s
end