Add a Message-ID header and set the type to the type of the content in the rss
[rss2maildir.git] / rss2maildir.py
1 #!/usr/bin/python
2
3 import mailbox
4 import sys
5 import os
6 import stat
7 import urllib
8
9 import feedparser
10
11 import email
12
13 import datetime
14 import random
15 import string
16
17 import socket
18
19 from optparse import OptionParser
20 from ConfigParser import SafeConfigParser
21
22 from base64 import b64encode
23
24
25 def parse_and_deliver(maildir, url, statedir):
26     md = mailbox.Maildir(maildir)
27     fp = feedparser.parse(url)
28     for item in fp["items"]:
29         # things that we need in the message
30         msg = email.message_from_string("")
31         msg.set_unixfrom("\"%s\" <rss2maildir@localhost>" %(url))
32         msg.add_header("From", "\"%s\" <rss2maildir@localhost>" %(item["author"]))
33         msg.add_header("To", "\"%s\" <rss2maildir@localhost>" %(url))
34         msg.add_header("Date", datetime.datetime(*item["created_parsed"][0:6]).strftime("%a, %e %b %Y %T -0000"))
35         msg.add_header("Subject", item["title"])
36         msg.set_charset("utf8")
37         msg.set_default_type(item["content"][0]["type"])
38         msg.set_type(item["content"][0]["type"])
39         msg.set_payload(b64encode(item["content"][0]["value"]))
40
41         msg.add_header("Message-ID", "<" + datetime.datetime.now().strftime("%Y%m%d%H%M") + "." + "".join([random.choice(string.ascii_letters + string.digits) for a in range(0,6)]) + "@" + socket.gethostname() + ">")
42
43         # start by working out the filename we should be writting to, we do
44         # this following the normal maildir style rules
45         fname = str(os.getpid()) + "." + socket.gethostname() + "." + "".join([random.choice(string.ascii_letters + string.digits) for a in range(0,10)]) + "." + datetime.datetime.now().strftime('%s')
46         fn = os.path.join(maildir, "tmp", fname)
47         fh = open(fn, "w")
48         fh.write(msg.as_string())
49         fh.close()
50         # now move it in to the new directory
51         newfn = os.path.join(maildir, "new", fname)
52         os.link(fn, newfn)
53         os.unlink(fn)
54
55 # first off, parse the command line arguments
56
57 oparser = OptionParser()
58 oparser.add_option(
59     "-c", "--conf", dest="conf",
60     help="location of config file"
61     )
62 oparser.add_option(
63     "-s", "--statedir", dest="statedir",
64     help="location of directory to store state in"
65     )
66
67 (options, args) = oparser.parse_args()
68
69 # check for the configfile
70
71 configfile = None
72
73 if options.conf != None:
74     # does the file exist?
75     try:
76         os.stat(options.conf)
77         configfile = options.conf
78     except:
79         # should exit here as the specified file doesn't exist
80         sys.stderr.write("Config file %s does not exist. Exiting.\n" %(options.conf,))
81         sys.exit(2)
82 else:
83     # check through the default locations
84     try:
85         os.stat("%s/.rss2maildir.conf" %(os.environ["HOME"],))
86         configfile = "%s/.rss2maildir.conf" %(os.environ["HOME"],)
87     except:
88         try:
89             os.stat("/etc/rss2maildir.conf")
90             configfile = "/etc/rss2maildir.conf"
91         except:
92             sys.stderr.write("No config file found. Exiting.\n")
93             sys.exit(2)
94
95 # Right - if we've got this far, we've got a config file, now for the hard
96 # bits...
97
98 scp = SafeConfigParser()
99 scp.read(configfile)
100
101 maildir_root = "RSSMaildir"
102 state_dir = "state"
103
104 if options.statedir != None:
105     state_dir = options.statedir
106     try:
107         mode = os.stat(state_dir)[stat.ST_MODE]
108         if not stat.S_ISDIR(mode):
109             sys.stderr.write("State directory (%s) is not a directory\n" %(state_dir))
110             sys.exit(1)
111     except:
112         # try to make the directory
113         try:
114             os.mkdir(state_dir)
115         except:
116             sys.stderr.write("Couldn't create statedir %s" %(state_dir))
117             sys.exit(1)
118 elif scp.has_option("general", "state_dir"):
119     new_state_dir = scp.get("general", "state_dir")
120     try:
121         mode = os.stat(state_dir)[stat.ST_MODE]
122         if not stat.S_ISDIR(mode):
123             sys.stderr.write("State directory (%s) is not a directory\n" %(state_dir))
124             sys.exit(1)
125     except:
126         # try to create it
127         try:
128             os.mkdir(new_state_dir)
129             state_dir = new_state_dir
130         except:
131             sys.stderr.write("Couldn't create state directory %s\n" %(new_state_dir))
132             sys.exit(1)
133
134 if scp.has_option("general", "maildir_root"):
135     maildir_root = scp.get("general", "maildir_root")
136
137 try:
138     mode = os.stat(maildir_root)[stat.ST_MODE]
139     if not stat.S_ISDIR(mode):
140         sys.stderr.write("Maildir Root %s is not a directory\n" %(maildir_root))
141         sys.exit(1)
142 except:
143     try:
144         os.mkdir(maildir_root)
145     except:
146         sys.stderr.write("Couldn't create Maildir Root %s\n" %(maildir_root))
147         sys.exit(1)
148
149 feeds = scp.sections()
150 try:
151     feeds.remove("general")
152 except:
153     pass
154
155 for section in feeds:
156     # check if the directory exists
157     maildir = None
158     try:
159         maildir = scp.get(section, "maildir")
160     except:
161         maildir = section
162
163     maildir = urllib.urlencode(((section, maildir),)).split("=")[1]
164     maildir = os.path.join(maildir_root, maildir)
165
166     try:
167         exists = os.stat(maildir)
168         if stat.S_ISDIR(exists[stat.ST_MODE]):
169             # check if there's a new, cur and tmp directory
170             try:
171                 mode = os.stat(os.path.join(maildir, "cur"))[stat.ST_MODE]
172             except:
173                 os.mkdir(os.path.join(maildir, "cur"))
174                 if not stat.S_ISDIR(mode):
175                     sys.stderr.write("Broken maildir: %s\n" %(maildir))
176             try:
177                 mode = os.stat(os.path.join(maildir, "tmp"))[stat.ST_MODE]
178             except:
179                 os.mkdir(os.path.join(maildir, "tmp"))
180                 if not stat.S_ISDIR(mode):
181                     sys.stderr.write("Broken maildir: %s\n" %(maildir))
182             try:
183                 mode = os.stat(os.path.join(maildir, "new"))[stat.ST_MODE]
184                 if not stat.S_ISDIR(mode):
185                     sys.stderr.write("Broken maildir: %s\n" %(maildir))
186             except:
187                 os.mkdir(os.path.join(maildir, "new"))
188         else:
189             sys.stderr.write("Broken maildir: %s\n" %(maildir))
190     except:
191         try:
192             os.mkdir(maildir)
193         except:
194             sys.stderr.write("Couldn't create root maildir %s\n" %(maildir))
195             sys.exit(1)
196         try:
197             os.mkdir(os.path.join(maildir, "new"))
198             os.mkdir(os.path.join(maildir, "cur"))
199             os.mkdir(os.path.join(maildir, "tmp"))
200         except:
201             sys.stderr.write("Couldn't create required maildir directories for %s\n" %(section,))
202             sys.exit(1)
203
204     # right - we've got the directories, we've got the section, we know the
205     # url... lets play!
206
207     parse_and_deliver(maildir, section, state_dir)