Fixed some dbus calls
[feedingit] / src / FeedingIt-Web.py
1 import BaseHTTPServer
2 import sys
3 from rss_sqlite import Listing
4 from xml import sax
5 from cgi import escape
6 from re import sub
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
13
14 CONFIGDIR = "/home/user/.feedingit/"
15
16 updatingFeeds = []
17 #commands = [("addFeed","httpwww"), ("openFeed", "xxxx"), ("openArticle", ("feedid","artid"))]
18 commands = []
19
20 def unescape(text):
21     def fixup(m):
22         text = m.group(0)
23         if text[:2] == "&#":
24             # character reference
25             try:
26                 if text[:3] == "&#x":
27                     return unichr(int(text[3:-1], 16))
28                 else:
29                     return unichr(int(text[2:-1]))
30             except ValueError:
31                 pass
32         else:
33             # named entity
34             try:
35                 text = unichr(name2codepoint[text[1:-1]])
36             except KeyError:
37                 pass
38         return text # leave as is
39     return sub("&#?\w+;", fixup, text)
40
41 def sanitize(text):
42     from cgi import escape
43     return escape(text).encode('ascii', 'xmlcharrefreplace')
44
45 def start_server():
46     global listing
47     listing = Listing(CONFIGDIR)
48     httpd = BaseHTTPServer.HTTPServer(("127.0.0.1", PORT), Handler)
49     httpd.serve_forever()    
50
51 class App():
52     def addFeed(self, url):
53         commands.append(("addFeed",url))
54     
55     def getStatus(self):
56         pass
57     
58     def openFeed(self, key):
59         cat = listing.getFeedCategory(key)
60         commands.append( ("openFeed", cat, key) )
61     
62     def OpenArticle(self, key, id):
63         cat = listing.getFeedCategory(key)
64         commands.append( ("openArticle", (cat, key, id)) )
65     
66 class Download(Thread):
67     def __init__(self, listing, keys):
68         Thread.__init__(self)
69         self.listing = listing
70         self.keys = keys
71         
72     def run (self):
73         updateDbusHandler.UpdateStarted()
74         for key in self.keys:
75             print "Start update: %s" % key
76             updatingFeeds.append(key)
77             (use_proxy, proxy) = config.getProxy()
78             try:
79                 if use_proxy:
80                         self.listing.updateFeed(key, proxy=proxy, imageCache=config.getImageCache() )
81                 else:
82                         self.listing.updateFeed(key, imageCache=config.getImageCache() )
83             except:
84                 print "Error updating feed: %s" %key
85             updatingFeeds.remove(key)
86             print "End update: %s" % key
87         updateDbusHandler.UpdateFinished()
88
89 class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
90     def openTaskSwitch(self):
91         import subprocess
92         subprocess.Popen("dbus-send /com/nokia/hildon_desktop com.nokia.hildon_desktop.exit_app_view", shell=True)
93         
94     def automaticUpdate(self):
95         feeds = []
96         for cat in listing.getListOfCategories():
97             for feed in listing.getSortedListOfKeys("Manual", category=cat):
98                 feeds.append(feed)
99         print feeds
100         download = Download(listing, feeds)
101         download.start()
102     
103     def getCommands(self):
104         
105         commandXml = "<commands>"
106         for item in commands:
107             if item[0]=="addFeed":
108                 commandXml += "<command c='addFeed'>%s</command>" %(sanitize(item[1]))
109             if item[0]=="openFeed":
110                 commandXml += "<command c='openFeed' cat='%s'>%s</command>" % (sanitize(item[1]), sanitize(item[2]) )
111             if item[0]=="openArticle":
112                 commandXml += "<command c='openArticle' cat='%s' key='%s'>%s</command>" %(sanitize(item[1], sanitize(item[2][0]), sanitize(item[2][1])) )
113             commands.remove(item)
114         commandXml += "</commands>"
115         return commandXml
116     
117     def getConfigXml(self):
118         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
119         xml += "<hideReadFeed>True</hideReadFeed>"
120         xml += "<hideReadArticles>True</hideReadArticles>"
121         xml += "</xml>"
122         return xml
123     
124     def generateCategoryXml(self):
125         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
126         for cat in listing.getListOfCategories():
127             xml += "<category>"
128             xml += "<catname>%s</catname>" %listing.getCategoryTitle(cat)
129             xml += "<catid>%s</catid>" % cat
130             xml += "</category>"
131         xml += "</xml>"
132         return xml
133
134     def fix_title(self, title):
135         return escape(unescape(title).replace("<em>","").replace("</em>","").replace("<nobr>","").replace("</nobr>","").replace("<wbr>","").replace("&mdash;","-"))
136     
137     def generateFeedsXml(self, catid):
138         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
139         for key in listing.getSortedListOfKeys("Manual", category=catid):
140             xml += "<feed>"
141             xml += "<feedname>%s</feedname>" %listing.getFeedTitle(key)
142             xml += "<feedid>%s</feedid>" %key
143             xml += "<unread>%s</unread>" %listing.getFeedNumberOfUnreadItems(key)
144             xml += "<updatedDate>%s</updatedDate>" %listing.getFeedUpdateTime(key)
145             xml += "<icon>%s</icon>" %listing.getFavicon(key)
146             if key in updatingFeeds:
147                 xml += "<updating>True</updating>"
148             else:
149                 xml += "<updating>False</updating>"
150             xml += "</feed>"
151         xml += "</xml>"
152         return xml
153     
154     def generateArticlesXml(self, key, onlyUnread, markAllAsRead):
155         feed = listing.getFeed(key)
156         if markAllAsRead=="True":
157             feed.markAllAsRead()
158             listing.updateUnread(key)
159             updateDbusHandler.ArticleCountUpdated()
160         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
161         if onlyUnread == "False":
162             onlyUnread = False
163         for id in feed.getIds(onlyUnread):
164             xml += "<article>"
165             xml += "<title>%s</title>" %self.fix_title(feed.getTitle(id))
166             xml += "<articleid>%s</articleid>" %id
167             xml += "<unread>%s</unread>" %str(feed.isEntryRead(id))
168             xml += "<updatedDate>%s</updatedDate>" %feed.getDateStamp(id)
169             xml += "<path>%s</path>" %feed.getContentLink(id)
170             xml += "</article>"
171         xml += "</xml>"
172         return xml
173
174     def do_GET(self):
175         (req, sep, arg) = self.path.partition("?")
176         request = req.split("/")
177         arguments = {}
178         if arg != "":
179             args = arg.split("&")
180             for arg in args:
181                 ele = arg.split("=")
182                 arguments[ele[0]] = ele[1]
183         if request[1] == "categories":
184             xml = self.generateCategoryXml()
185         elif request[1] == "feeds":
186             catid = request[2]
187             xml = self.generateFeedsXml(catid)
188         elif request[1] == "articles":
189             key = request[2]
190             onlyUnread = arguments.get("onlyUnread","False")
191             markAllAsRead = arguments.get("markAllAsRead", "False")
192             xml = self.generateArticlesXml(key, onlyUnread, markAllAsRead)
193         elif request[1] == "html":
194             key = request[2]
195             article = request[3]
196             feed = listing.getFeed(key)
197             try:
198                 file = open(feed.getContentLink(article))
199                 html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
200                 file.close()
201             except:
202                 html = "<html><body>Error retrieving article</body></html>"
203             self.send_response(200)
204             self.send_header("Content-type", "text/html")
205             self.end_headers()
206             self.wfile.write(html)
207             #listing.updateUnread(key)
208             return
209         elif request[1] == "isUpdating":
210             xml = "<xml>"
211             key = request[2]
212             if (key in updatingFeeds) or ((key=="") and (len(updatingFeeds)>0)):
213                 xml += "<updating>True</updating>"
214             else:
215                 xml += "<updating>False</updating>"
216             xml += self.getCommands()
217             xml += "</xml>"
218         elif request[1] == "read":
219             key = request[2]
220             article = request[3]
221             feed = listing.getFeed(key)
222             feed.setEntryRead(article)
223             listing.updateUnread(key)
224             updateDbusHandler.ArticleCountUpdated()
225             self.send_response(200)
226             self.send_header("Content-type", "text/html")
227             self.end_headers()
228             self.wfile.write("OK")
229             return
230         elif request[1] == "config":
231             xml = self.getConfigXml()
232         elif request[1] == "home":
233             file = open(self.path)
234             self.send_response(200)
235             self.send_header("Content-type", "text/html")
236             self.end_headers()
237             self.wfile.write(file.read())
238             file.close()
239             return
240         elif request[1] == "task":
241             self.openTaskSwitch()
242             xml = "<xml>OK</xml>"
243         elif request[1] == "deleteCat":
244             key = request[2]
245             listing.removeCategory(key)
246             xml = "<xml>OK</xml>"
247         elif request[1] == "deleteFeed":
248             key = request[3]
249             listing.removeFeed(key)
250             xml = "<xml>OK</xml>"
251         elif request[1] == "addFeed":
252             cat = request[2]
253             name = request[3]
254             url = arguments.get("url","")
255             listing.addFeed(name, url, category=cat)
256             xml = "<xml>OK</xml>"
257         elif request[1] == "updateFeed":
258             key = request[2]
259             download = Download(listing, [key,])
260             download.start()
261             xml = "<xml>OK</xml>"
262         elif request[1]=="updateAll":
263             self.automaticUpdate()
264             updateDbusHandler.ArticleCountUpdated()
265             xml = "<xml>OK</xml>"
266         elif request[1] == "addCat":
267             catName = request[2]
268             listing.addCategory(catName)
269             xml = "<xml>OK</xml>"
270         else:
271             self.send_error(404, "File not found")
272             return
273         self.send_response(200)
274         self.send_header("Content-type", "text/xml")
275         self.end_headers()
276         self.wfile.write(xml.encode("utf-8"))
277
278 PORT = 8000
279
280 if not isdir(CONFIGDIR):
281     try:
282         mkdir(CONFIGDIR)
283     except:
284         print "Error: Can't create configuration directory"
285         from sys import exit
286         exit(1)
287
288 from config import Config
289 config = Config(None,CONFIGDIR+"config.ini")
290
291 import thread
292
293 #print "serving at port", PORT
294 thread.start_new_thread(start_server, ())
295
296 from feedingitdbus import ServerObject
297 from updatedbus import UpdateServerObject, get_lock
298 import gobject
299 gobject.threads_init()
300 import dbus.mainloop.glib
301 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
302 app = App()
303 dbusHandler = ServerObject(app)
304 updateDbusHandler = UpdateServerObject(app)
305 mainloop = gobject.MainLoop()
306 mainloop.run()