3 from rss_sqlite import Listing
7 from htmlentitydefs import name2codepoint
8 from gconf import client_get_default
9 from urllib2 import ProxyHandler
10 from threading import Thread
11 from os.path import isfile, isdir, exists
12 from os import mkdir, remove, stat, environ
14 CONFIGDIR = environ.get("HOME", "/home/user") + "/.feedingit"
15 #CONFIGDIR = "/home/user/.feedingit/"
18 #commands = [("addFeed","httpwww"), ("openFeed", "xxxx"), ("openArticle", ("feedid","artid"))]
28 return unichr(int(text[3:-1], 16))
30 return unichr(int(text[2:-1]))
36 text = unichr(name2codepoint[text[1:-1]])
39 return text # leave as is
40 return sub("&#?\w+;", fixup, text)
43 from cgi import escape
44 return escape(text).encode('ascii', 'xmlcharrefreplace')
48 listing = Listing(CONFIGDIR)
49 httpd = BaseHTTPServer.HTTPServer(("127.0.0.1", PORT), Handler)
53 def addFeed(self, url):
54 commands.append(("addFeed",url))
59 def openFeed(self, key):
60 commands.append( ("openFeed", key) )
62 def openArticle(self, key, id):
63 commands.append( ("openArticle", key, id) )
65 def automaticUpdate(self):
66 commands.append(("updateAll",))
67 # for cat in listing.getListOfCategories():
68 # for feed in listing.getSortedListOfKeys("Manual", category=cat):
70 # download = Download(listing, feeds)
73 class Download(Thread):
74 def __init__(self, listing, keys):
76 self.listing = listing
80 updateDbusHandler.UpdateStarted()
82 print "Start update: %s" % key
83 updatingFeeds.append(key)
84 (use_proxy, proxy) = config.getProxy()
87 self.listing.updateFeed(key, proxy=proxy, imageCache=config.getImageCache() )
89 self.listing.updateFeed(key, imageCache=config.getImageCache() )
91 print "Error updating feed: %s" %key
92 updatingFeeds.remove(key)
93 print "End update: %s" % key
94 updateDbusHandler.UpdateFinished()
96 class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
99 for cat in listing.getListOfCategories():
100 for feed in listing.getSortedListOfKeys("Manual", category=cat):
102 download = Download(listing, feeds)
105 def openTaskSwitch(self):
107 subprocess.Popen("dbus-send /com/nokia/hildon_desktop com.nokia.hildon_desktop.exit_app_view", shell=True)
109 def getCommands(self):
110 commandXml = "<commands>"
111 for item in commands:
112 if item[0]=="addFeed":
113 commandXml += "<command c='addFeed'>%s</command>" %(sanitize(item[1]))
114 if item[0]=="openFeed":
116 cat = str(listing.getFeedCategory(key))
117 commandXml += "<command c='openFeed' cat='%s'>%s</command>" % (sanitize(cat), sanitize(key) )
118 if item[0]=="openArticle":
120 cat = str(listing.getFeedCategory(key))
122 commandXml += "<command c='openArticle' cat='%s' key='%s'>%s</command>" %(sanitize(cat), sanitize(key), sanitize(articleid) )
123 if item[0]=="updateAll":
125 commands.remove(item)
126 commandXml += "</commands>"
129 def getConfigXml(self):
130 xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
131 xml += "<hideReadFeed>True</hideReadFeed>"
132 xml += "<hideReadArticles>True</hideReadArticles>"
136 def generateCategoryXml(self):
137 xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
138 for cat in listing.getListOfCategories():
140 xml += "<catname>%s</catname>" %sanitize(listing.getCategoryTitle(cat))
141 xml += "<catid>%s</catid>" % cat
146 def fix_title(self, title):
147 return escape(unescape(title).replace("<em>","").replace("</em>","").replace("<nobr>","").replace("</nobr>","").replace("<wbr>","").replace("—","-"))
149 def generateFeedsXml(self, catid):
150 xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
151 for key in listing.getSortedListOfKeys("Manual", category=catid):
153 xml += "<feedname>%s</feedname>" %sanitize(listing.getFeedTitle(key))
154 xml += "<feedid>%s</feedid>" %key
155 xml += "<unread>%s</unread>" %listing.getFeedNumberOfUnreadItems(key)
156 xml += "<updatedDate>%s</updatedDate>" %listing.getFeedUpdateTime(key)
157 xml += "<icon>%s</icon>" %listing.getFavicon(key)
158 if key in updatingFeeds:
159 xml += "<updating>True</updating>"
161 xml += "<updating>False</updating>"
166 def generateArticlesXml(self, key, onlyUnread, markAllAsRead):
167 feed = listing.getFeed(key)
168 if markAllAsRead=="True":
170 listing.updateUnread(key)
171 updateDbusHandler.ArticleCountUpdated()
172 xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
173 if onlyUnread == "False":
175 for id in feed.getIds(onlyUnread):
177 xml += "<title>%s</title>" %self.fix_title(feed.getTitle(id))
178 xml += "<articleid>%s</articleid>" %id
179 xml += "<unread>%s</unread>" %str(feed.isEntryRead(id))
180 xml += "<updatedDate>%s</updatedDate>" %feed.getDateStamp(id)
181 xml += "<path>%s</path>" %feed.getContentLink(id)
187 (req, sep, arg) = self.path.partition("?")
188 request = req.split("/")
191 args = arg.split("&")
194 arguments[ele[0]] = ele[1]
195 if request[1] == "categories":
196 xml = self.generateCategoryXml()
197 elif request[1] == "feeds":
199 xml = self.generateFeedsXml(catid)
200 elif request[1] == "articles":
202 onlyUnread = arguments.get("onlyUnread","False")
203 markAllAsRead = arguments.get("markAllAsRead", "False")
204 xml = self.generateArticlesXml(key, onlyUnread, markAllAsRead)
205 elif request[1] == "html":
208 feed = listing.getFeed(key)
210 file = open(feed.getContentLink(article))
211 html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
214 html = "<html><body>Error retrieving article</body></html>"
215 self.send_response(200)
216 self.send_header("Content-type", "text/html")
218 self.wfile.write(html)
219 #listing.updateUnread(key)
221 elif request[1] == "isUpdating":
224 if (key in updatingFeeds) or ((key=="") and (len(updatingFeeds)>0)):
225 xml += "<updating>True</updating>"
227 xml += "<updating>False</updating>"
228 xml += self.getCommands()
230 elif request[1] == "read":
233 feed = listing.getFeed(key)
234 feed.setEntryRead(article)
235 listing.updateUnread(key)
236 updateDbusHandler.ArticleCountUpdated()
237 self.send_response(200)
238 self.send_header("Content-type", "text/html")
240 self.wfile.write("OK")
242 elif request[1] == "config":
243 xml = self.getConfigXml()
244 elif request[1] == "home":
245 file = open(self.path)
246 self.send_response(200)
247 self.send_header("Content-type", "text/html")
249 self.wfile.write(file.read())
252 elif request[1] == "task":
253 self.openTaskSwitch()
254 xml = "<xml>OK</xml>"
255 elif request[1] == "deleteCat":
257 listing.removeCategory(key)
258 xml = "<xml>OK</xml>"
259 elif request[1] == "deleteFeed":
261 listing.removeFeed(key)
262 xml = "<xml>OK</xml>"
263 elif request[1] == "addFeed":
266 url = arguments.get("url","")
267 listing.addFeed(name, url, category=cat)
268 xml = "<xml>OK</xml>"
269 elif request[1] == "updateFeed":
271 download = Download(listing, [key,])
273 xml = "<xml>OK</xml>"
274 elif request[1]=="updateAll":
275 #app.automaticUpdate()
277 updateDbusHandler.ArticleCountUpdated()
278 xml = "<xml>OK</xml>"
279 elif request[1] == "addCat":
281 listing.addCategory(catName)
282 xml = "<xml>OK</xml>"
284 self.send_error(404, "File not found")
286 self.send_response(200)
287 self.send_header("Content-type", "text/xml")
289 self.wfile.write(xml.encode("utf-8"))
293 if not isdir(CONFIGDIR):
297 print "Error: Can't create configuration directory"
301 from config import Config
302 config = Config(None,CONFIGDIR+"config.ini")
308 # Start the HTTP server in a new thread
309 thread.start_new_thread(start_server, ())
311 # Initialize the glib mainloop, for dbus purposes
312 from feedingitdbus import ServerObject
313 from updatedbus import UpdateServerObject, get_lock
316 gobject.threads_init()
317 import dbus.mainloop.glib
318 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
320 global updateDbusHandler, dbusHandler
322 dbusHandler = ServerObject(app)
323 updateDbusHandler = UpdateServerObject(app)
325 mainloop = gobject.MainLoop()