~woutc/specto/specto-dbus-client

« back to all changes in this revision

Viewing changes to spectlib/plugins/watch_web_greader.py

  • Committer: Jean-François Fortin Tam
  • Author(s): Wout Clymans
  • Date: 2008-07-22 23:22:49 UTC
  • Revision ID: jeff@kiki-20080722232249-l64srclhp6u6qyrw
WARNING: this commit contains all the significant changes that happened in a specto-woutc branch over the past year. Large change log follows. Some commit log lines were intentionally left out.

- A dialog with debug information is shown when specto has a system/programming error.
- Disable renaming watches in the listview, make it a Jump To action instead
- All mandatory fields have to be filled in now (add and edit watch)
- The error log now shows the lines in color according to the severity
- Better file size cache name
- Added more error-handling
- The filesize is now saved in a different cache file (not in watches.list), may fix issue 37?
- Icons are now shown in the combobox when you add a new watch (buggy, patches welcome)
- Improved the pop3, imap and gmail watches
- The gmail watch now saves what unread mails there already were last time
- Convert HTML entities for the web diff
- Moved some code so the file dialog will show faster
- A watch will be marked updated when you didn't clear it on quit.
- Removed double call to refresh the watch info
- Made a general gtkutil file where you can define widgets used in the edit and add watch windows
- Removed the class name from the logger
- Clear the watch when you open it using the balloon
- Make some watch names clearer
- Error log tab in notifier window
- Added "clear" button in the edit menu
- Show simple diff from webpage difference
- Console mode (specto --console or specto --console --help)
- Watch menu when you right-click a watch entry in the notifier window
- Ability to run a command when a watch is updated
- Ability to run a command when a watch is cleared
- Fields in the add and edit windows are now dynamic; when creating a new watch plugin, you don't have to write all the gui code anymore
- More space for the extra information in the info panel
- code cleanup
- use plugin-system

- Fix issue 150: Gmail.com - that address is disabled in Germany - hence you can't go to messages directly
- Fix issue 93: Gmail library can support no more than 19 new mails
- Fix issue 131: bombs on special characters
- Fix issue 134: harmonized colors
- Fix issue 119: don't let the log file get huge
- Fix issue 143: Site adress in "About" box is not clickable
- Fix issue 146: Per-watch option to prevent URL redirects; To use this option add "redirect = True" to the watch that is allowed to redirect
- Fix issue 145: abnormal behavior with ampersands in a web watch
- Fix issue 51: Specto stores passwords in plaintext (started keyring support)
- Fix issue 135: Proxy support (already proxy support for web watch)
- Fix issue 128: allow specifying a port for mail watches (add 'port = 323' to your watch config)
- Fix issue 132: removing a watch should remove its cache files
- Fix issue 136: Support specific folder monitor over IMAP (add 'folder = work' to your imap watch config)
- Fix issue 63: Google Reader Watch does not support more than 20 items
- Fix issue 39: POP3 & IMAP watches not on par with gmail watch's message counting logic
- Fix issue 100: gmail with google apps should point to the right domain when clicking Jump to
- Fix issue 95: statusbar should show something else when updates are done
- Fix issue 112: hide error log tabs when debug mode is deactivated
- Fix issue 101: show the import dialog after the file chooser
- Fix issue 114: removing a watch should show a confirmation dialog
- Fix issue 73: brackets in watch name lead to startup crash (brackets can now be used in the name!)
- Fix issue 69: startup fails due to wrong glade file path  
- Fix issue 12: provide more information
- Fix issue 13: watch list importing and exporting
- Fix issue 20: Organise specto source into modules
- Fix issue 33: ability to run a command instead of notifying
- Fix issue 54: freedesktop-compliant user directories
- Fix issue 72: "show in window list" preference is not saved
- Fix issue 77: don't mess up if ekiga's sound files are not present
- Fix issue 118: add http:// automatically for web watches (also @gmail.com added for gmail accounts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
# License along with this program; if not, write to the
21
21
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22
22
# Boston, MA 02111-1307, USA.
23
 
 
24
23
from spectlib.watch import Watch
 
24
import spectlib.config
25
25
from spectlib.i18n import _
26
 
 
27
 
import urllib
28
 
import urllib2
29
 
import re
30
 
import sys,os, string
31
 
from xml.dom import minidom, Node
32
 
 
33
 
import thread
34
 
import gtk, time
35
 
 
36
 
 
37
 
class Google_reader(Watch):
38
 
    """
39
 
    this watch will check if you have a new mail on your gmail account
40
 
    """
41
 
    updated = False
42
 
    actually_updated = False
43
 
    type = 5 
44
 
    
45
 
    
46
 
##    subscription_list_url = reader_url + '/api/0/subscription/list'
47
 
##    reading_url = reader_url + '/atom/user/-/state/com.google/reading-list'
48
 
##    read_items_url = reader_url + '/atom/user/-/state/com.google/read'
49
 
##    reading_tag_url = reader_url + '/atom/user/-/label/%s'
50
 
##    starred_url = reader_url + '/atom/user/-/state/com.google/starred'
51
 
##    subscription_url = reader_url + '/api/0/subscription/edit'
52
 
##    get_feed_url = reader_url + '/atom/feed/'
53
 
 
54
 
    
55
 
    def __init__(self, refresh, username, password, specto, id,  name = _("Unknown Google Reader Watch")):
56
 
        Watch.__init__(self, specto)
57
 
        self.name = name
58
 
        self.refresh = refresh
59
 
        self.user = username
60
 
        self.password = password
61
 
        self.id = id
62
 
        self.error = False
63
 
        self.news_titles = []
64
 
        self.oldMsg = 0
 
26
import spectlib.util
 
27
 
 
28
type = "Watch_web_greader"
 
29
type_desc = "Google Reader"
 
30
url = "http://www.google.com/reader/"
 
31
icon = 'internet-news-reader'
 
32
 
 
33
def get_add_gui_info():
 
34
    return [
 
35
            ("username", spectlib.gtkconfig.Entry("Username")),
 
36
            ("password", spectlib.gtkconfig.PasswordEntry("Password"))
 
37
            ]
 
38
 
 
39
 
 
40
class Watch_web_greader(Watch):
 
41
    """
 
42
    this watch will check if you have new news on your google reader account
 
43
    """
 
44
 
 
45
    def __init__(self, specto, id, values):
 
46
        watch_values = [ 
 
47
                        ( "username", spectlib.config.String(True) ),
 
48
                        ( "password", spectlib.config.String(True) ) 
 
49
                        ]
 
50
 
 
51
        self.standard_open_command = spectlib.util.return_webpage(url)
 
52
                
 
53
        #Init the superclass and set some specto values
 
54
        Watch.__init__(self, specto, id, values, watch_values)
 
55
 
 
56
        self.use_network = True
 
57
        self.icon = icon
 
58
        self.type_desc = type_desc
 
59
        self.cache_file = os.path.join(self.specto.CACHE_DIR, "greader" + self.username + ".cache")        
 
60
 
 
61
        #watch specific values
 
62
        self.unreadMsg = 0
65
63
        self.newMsg = 0
66
 
        self.source = "Specto"
67
 
        self.google_url = 'http://www.google.com'
68
 
        self.reader_url = self.google_url + '/reader'
69
 
        self.reading_url = self.reader_url + '/atom/user/-/state/com.google/reading-list'
70
 
        self.login_url = 'https://www.google.com/accounts/ClientLogin'
71
 
        self.token_url = self.reader_url + '/api/0/token'
72
 
        
73
 
        cacheSubDir__ = os.environ['HOME'] + "/.specto/cache/"
74
 
        if not os.path.exists(cacheSubDir__):
75
 
            os.mkdir(cacheSubDir__)
76
 
        self.cache_file = cacheSubDir__ + "googleReader.xml.cache"
77
 
                
78
 
    def dict_values(self):
79
 
        return { 'name': self.name, 'refresh': self.refresh, 'username': self.user, 'password':self.password, 'type':5 }
80
 
        
81
 
    def start_watch(self):
82
 
        """ Start the watch. """
83
 
        self.thread_update()
84
 
        
85
 
    def _real_update(self):
86
 
        lock = thread.allocate_lock()
87
 
        lock.acquire()
88
 
        t=thread.start_new_thread(self.update,(lock,))
89
 
        while lock.locked():
90
 
            while gtk.events_pending():
91
 
                gtk.main_iteration()
92
 
            time.sleep(0.05)
93
 
        while gtk.events_pending():
94
 
            gtk.main_iteration()
95
 
        
96
 
    def thread_update(self):
97
 
        if not self.specto.connection_manager.connected():
98
 
            self.specto.logger.log(_("No network connection detected"),
99
 
                                   "info", self.__class__)
100
 
            self.specto.connection_manager.add_callback(self._real_update)
101
 
            self.specto.mark_watch_busy(False, self.id)
102
 
        else :
103
 
            self._real_update()
104
 
        
105
 
    def update(self, lock):
106
 
        """ Check for new mails on your gmail account. """
107
 
        self.error = False
108
 
        self.specto.mark_watch_busy(True, self.id)
109
 
        self.specto.logger.log(_("Updating watch: \"%s\"") % self.name, "info", self.__class__)
110
 
        
 
64
        self.news_info = Feed_collection()
 
65
        self.or_more = ""
 
66
        
 
67
        self.read_cache_file()        
 
68
        
 
69
    def update(self):
 
70
        """ Check for new news on your greader account. """
111
71
        try:
112
 
            self.oldMsg = self.newMsg
113
72
            self.newMsg = 0
114
 
            SID = self.get_SID()
115
 
            f = file(self.cache_file , "w")
116
 
            f.write(str(self.get_reading_list(SID)))
 
73
            greader = Greader(self.username, self.password)
 
74
            unread, info_friends, info = greader.refresh()
 
75
            if unread[0] == -1:
 
76
                self.error = True
 
77
                self.specto.logger.log(_("Watch: \"%s\" has error: %s") % (self.name, unread[1]), "error", self.__class__)
 
78
            elif unread[0] == 1:#no unread items, we need to clear the watch
 
79
                    self.unreadMsg = unread[1]
 
80
                    self.actually_updated = False
 
81
                    self.specto.mark_watch_status("clear", self.id)
 
82
                    self.news_info = Feed_collection()
 
83
            else:
 
84
                self.unreadMsg = int(unread[1])
 
85
                                
 
86
                if self.unreadMsg == 1000:
 
87
                    self.or_more = " or more"
 
88
 
 
89
                self.news_info.clear_old()
 
90
   
 
91
                for feed in info:
 
92
                    _feed = Feed(feed, info[feed])
 
93
                    if self.news_info.add(_feed):
 
94
                        self.actually_updated = True
 
95
                        self.newMsg+=1
 
96
            
 
97
                self.news_info.remove_old()
 
98
                self.write_cache_file()
 
99
                    
 
100
        except:
 
101
            self.error = True
 
102
            self.specto.logger.log(_("Watch: \"%s\" has an unknown error") % self.name, "error", self.__class__)
 
103
        Watch.timer_update(self)
 
104
        
 
105
    def get_gui_info(self):
 
106
        return [ 
 
107
                ('Name', self.name),
 
108
                ('Last updated', self.last_updated),
 
109
                ('Username', self.username),
 
110
                ("Unread messages", str(self.unreadMsg) + self.or_more)
 
111
                ]
 
112
                
 
113
    def get_balloon_text(self):
 
114
        """ create the text for the balloon """
 
115
        unread_messages = self.news_info.get_unread_messages()
 
116
        if len(unread_messages) == 1:
 
117
            text = ("<b>%s</b> has a new newsitems in <b>%s</b>\n\n <b>totalling %s</b> unread items.") % (self.name, unread_messages[0].name, str(self.unreadMsg) + self.or_more)
 
118
        else:
 
119
            i = 0 #show max 4 feeds
 
120
            feed_info = ""
 
121
            while i < len(unread_messages) and i < 4:
 
122
                feed_info += unread_messages[i].name + ", "
 
123
                if i == 3 and i < len(unread_messages) - 1:
 
124
                    feed_info += "and others..."
 
125
                i += 1            
 
126
            feed_info = feed_info.rstrip(", ")    
 
127
            text = ("<b>%s</b> has received %d new newsitems in <b>%s</b>\n\n <b>totalling %s</b> unread items.") % (self.name, self.newMsg, feed_info, str(self.unreadMsg)  + self.or_more)    
 
128
        return text
 
129
    
 
130
    def get_extra_information(self):        
 
131
        i = 0
 
132
        feed_info = ""
 
133
        while i < len(self.news_info) and i < 4:
 
134
            feed_info += "<b>" + self.news_info[i].name + "</b>: <i>" + str(self.news_info[i].messages) + "</i>\n"
 
135
            if i == 3 and i < len(self.news_info) - 1:
 
136
                feed_info += "and others..."
 
137
            i += 1            
 
138
        return feed_info
 
139
                
 
140
                
 
141
    def read_cache_file(self):
 
142
        if os.path.exists(self.cache_file):
 
143
            try:
 
144
                f = open(self.cache_file, "r")
 
145
            except:
 
146
                self.specto.logger.log(_("There was an error reader the file %s") % self.cache_file, "critical", self.__class__)
 
147
            else:
 
148
                for line in f:
 
149
                    info = line.split("&Seperator;")
 
150
                    feed = Feed(info[0], info[1].replace("\n", ""))
 
151
                    self.news_info.add(feed)
 
152
 
 
153
            finally:
 
154
                f.close()
 
155
 
 
156
    def write_cache_file(self):
 
157
        try:
 
158
            f = open(self.cache_file, "w")
 
159
        except:
 
160
            self.specto.logger.log(_("There was an error opening the file %s") % self.cache_file, "critical", self.__class__)
 
161
        else:
 
162
            for feed in self.news_info:
 
163
                f.write(feed.name + "&Seperator;" + str(feed.messages) + "\n")
 
164
        finally:
117
165
            f.close()
118
 
            doc = minidom.parse(self.cache_file)
119
 
            rootNode = doc.documentElement
120
 
            attributes =[] 
121
 
            self.walk(rootNode, False, attributes)
122
 
            
123
 
            if self.oldMsg == 0 and self.newMsg == 0:#no unread messages, we need to clear the watch
124
 
                self.actually_updated=False
125
 
                self.specto.notifier.clear_watch("", self.id)
126
 
            if self.newMsg > 0:
127
 
                self.actually_updated=True
128
 
                if self.oldMsg == 0:
129
 
                    self.oldMsg = self.newMsg
130
 
        except:
131
 
            self.error = True
132
 
            self.specto.logger.log(_("Watch: \"%s\" has error: Error in processing cache file") % self.name, "error", self.__class__)
133
 
            
134
 
        self.specto.mark_watch_busy(False, self.id)
135
 
        Watch.update(self, lock)
136
 
        
137
 
    #login / get SED
138
 
    def get_SID(self):
139
 
        header = {'User-agent' : self.source}
140
 
        post_data = urllib.urlencode({ 'Email': self.user, 'Passwd': self.password, 'service': 'reader', 'source': self.source, 'continue': self.google_url, })
141
 
        request = urllib2.Request(self.login_url, post_data, header)
142
 
        
143
 
        try :
144
 
            f = urllib2.urlopen( request )
145
 
            result = f.read()
146
 
        
147
 
        except:
148
 
            self.specto.logger.log(_("Watch: \"%s\" has error: wrong username/password") % self.name, "error", self.__class__)
149
 
            
150
 
        return re.search('SID=(\S*)', result).group(1)
151
 
    
152
 
    def walk(self, parent, get_news, attributes):                              # [1]
153
 
        for node in parent.childNodes:
154
 
            if node.nodeType == Node.ELEMENT_NODE:
155
 
                attrs = node.attributes
156
 
                for attrName in attrs.keys():
157
 
                    attrNode = attrs.get(attrName)
158
 
                    attrValue = attrNode.nodeValue
159
 
                    if node.nodeName == "entry":
160
 
                        attributes.append(attrName)
161
 
                        get_news = True
162
 
                        
163
 
                    if node.nodeName == 'title' and get_news == True:
164
 
                        self.get_news_information(node, attrs, attrName)
165
 
                        get_news = False
166
 
                if 'gr:is-read-state-locked' in attributes:
167
 
                    get_news = False
168
 
                # Walk the child nodes.
169
 
                self.walk(node, get_news, attributes)
170
 
            
171
 
    def get_news_information(self,node, attrs, attrName):
172
 
        # Walk over any text nodes in the current node.
173
 
        content = []
174
 
        for child in node.childNodes:
175
 
            if child.nodeType == Node.TEXT_NODE:
176
 
                content.append(child.nodeValue)
177
 
                if content:
178
 
                    if content[0] not in self.news_titles:
179
 
                        #print content[0] #uncomment this to see the titles from the unread news items
180
 
                        self.news_titles.append(content[0])
181
 
                        self.newMsg +=1
182
 
    
183
 
    #get a feed of the users unread items    
184
 
    def get_reading_list(self,SID):
185
 
        return self.get_results(SID, self.reading_url)
186
 
    
187
 
    #get results from url
188
 
    def get_results(self, SID, url):
189
 
        header = {'User-agent' : self.source}
190
 
        header['Cookie']='Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID
191
 
 
192
 
        request = urllib2.Request(url, None, header)
193
 
        
194
 
        try :
195
 
            f = urllib2.urlopen( request )
196
 
            result = f.read()
197
 
        
198
 
        except:
199
 
            self.specto.logger.log(_("Watch: \"%s\" has error: Error getting data from %s") % self.name %url, "error", self.__class__)
200
 
        
201
 
        return result
202
 
        
203
 
    def set_username(self, username):
204
 
        """ Set the username for the watch. """
205
 
        self.user = username
206
 
        
207
 
    def set_password(self, password):
208
 
        """ Set the password for the watch. """
209
 
        self.password = password
 
166
            
 
167
    def remove_cache_files(self):
 
168
        os.unlink(self.cache_file)            
 
169
            
 
170
class Feed():
 
171
    
 
172
    def __init__(self, name, messages):
 
173
        self.name = name
 
174
        self.messages = int(messages)
 
175
        self.found = False
 
176
        self.new = False
 
177
        
 
178
class Feed_collection():
 
179
    
 
180
    def __init__(self):
 
181
        self.feed_collection = []
 
182
        
 
183
    def add(self, feed):            
 
184
        self.new = True
 
185
        self.updated = False
 
186
        for _feed in self.feed_collection:
 
187
            if feed.name == _feed.name:
 
188
                if feed.messages > _feed.messages:
 
189
                    self.new = False
 
190
                    self.updated = True
 
191
                    _feed.messages = feed.messages
 
192
                    _feed.found = True
 
193
                else:
 
194
                    _feed.messages = feed.messages
 
195
                    self.new = False
 
196
                    _feed.found = True
 
197
                                
 
198
        if self.new == True:
 
199
            feed.found = True
 
200
            feed.new = True
 
201
            self.feed_collection.append(feed)
 
202
            return True
 
203
        elif self.updated == True:
 
204
            feed.found = True
 
205
            feed.updated = True
 
206
            return True
 
207
        else:
 
208
            return False
 
209
        
 
210
    def __getitem__(self, id):
 
211
        return self.feed_collection[id]
 
212
    
 
213
    def __len__(self):
 
214
        return len(self.feed_collection)
 
215
    
 
216
    def remove_old(self):
 
217
        i = 0
 
218
        collection_copy = []
 
219
        for _feed in self.feed_collection:
 
220
            if _feed.found == True:
 
221
                collection_copy.append(_feed)
 
222
            i += 1
 
223
        self.feed_collection = collection_copy
 
224
          
 
225
    def clear_old(self):
 
226
        for _feed in self.feed_collection:
 
227
            _feed.found = False
 
228
            _feed.new = False
 
229
            _feed.updated = False
 
230
            
 
231
    def get_unread_messages(self):
 
232
        unread = []
 
233
        for _feed in self.feed_collection:
 
234
            if _feed.new == True or _feed.updated == True:
 
235
                unread.append(_feed)
 
236
        return unread
 
237
        
 
238
                
 
239
 
 
240
 
 
241
 
 
242
"""
 
243
grnotify
 
244
---------
 
245
GrNotify is a simple Python written tray application that will allow you to know when there are new items in the Google Reader.
 
246
 
 
247
GrNotify is written by Kristof Bamps
 
248
- And maintained by Bram Bonne and Eric Lembregts 
 
249
 
 
250
 
 
251
Dependencies
 
252
--------------
 
253
  * Python >= 2.2 <http://www.python.org>
 
254
  * PyXML >= 0.8.3 <http://pyxml.sourceforge.net>
 
255
  * PyGTK >= 2.0 <http://www.pygtk.org>
 
256
"""
 
257
import urllib
 
258
import urllib2
 
259
import xml.dom.minidom
 
260
import time
 
261
import os.path
 
262
import sys
 
263
 
 
264
###############################
 
265
#Variables
 
266
#
 
267
counter = 1 #boolean to show counter or not
 
268
numberFeeds = 5 #default maximum number of feeds of which info is shows
 
269
L = [] #contains feed ids and their number of unread items
 
270
names = [] #contains names of all feeds
 
271
feeds = 0 # number of feeds user is subscribed to
 
272
email = ''
 
273
passwd = ''
 
274
cookies = -1
 
275
old_unread = -1
 
276
unread = 0
 
277
 
 
278
################################
 
279
#Use cookies
 
280
#
 
281
COOKIEFILE = os.path.join(spectlib.util.get_path('tmp'), 'cookies.lwp')
 
282
# the path and filename to save your cookies in
 
283
 
 
284
cj = None
 
285
ClientCookie = None
 
286
cookielib = None
 
287
 
 
288
# Let's see if cookielib is available
 
289
try:
 
290
    import cookielib
 
291
except ImportError:
 
292
    # If importing cookielib fails
 
293
    # let's try ClientCookie
 
294
    try:
 
295
        import ClientCookie
 
296
    except ImportError:
 
297
    # ClientCookie isn't available either
 
298
        urlopen = urllib2.urlopen
 
299
        Request = urllib2.Request
 
300
    else:
 
301
    # imported ClientCookie
 
302
        urlopen = ClientCookie.urlopen
 
303
        Request = ClientCookie.Request
 
304
        cj = ClientCookie.LWPCookieJar()
 
305
 
 
306
else:
 
307
    # importing cookielib worked
 
308
    urlopen = urllib2.urlopen
 
309
    Request = urllib2.Request
 
310
    cj = cookielib.LWPCookieJar()
 
311
    # This is a subclass of FileCookieJar
 
312
    # that has useful load and save methods
 
313
 
 
314
if cj is not None:
 
315
# we successfully imported
 
316
# one of the two cookie handling modules
 
317
    if os.path.isfile(COOKIEFILE):
 
318
    # if we have a cookie file already saved
 
319
    # then load the cookies into the Cookie Jar
 
320
        cj.load(COOKIEFILE)
 
321
 
 
322
    # Now we need to get our Cookie Jar
 
323
    # installed in the opener;
 
324
    # for fetching URLs
 
325
    if cookielib is not None:
 
326
    # if we use cookielib
 
327
    # then we get the HTTPCookieProcessor
 
328
    # and install the opener in urllib2
 
329
        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
 
330
        urllib2.install_opener(opener)
 
331
 
 
332
    else:
 
333
    # if we use ClientCookie
 
334
    # then we get the HTTPCookieProcessor
 
335
    # and install the opener in ClientCookie
 
336
        opener = ClientCookie.build_opener(ClientCookie.HTTPCookieProcessor(cj))
 
337
        ClientCookie.install_opener(opener)
 
338
        
 
339
def getcookies ():
 
340
    url = 'https://www.google.com/accounts/ServiceLoginAuth'
 
341
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
 
342
    login = {'Email' : email,
 
343
        'Passwd' : passwd}
 
344
 
 
345
    data = urllib.urlencode(login)
 
346
 
 
347
    theurl = url
 
348
    # an example url that sets a cookie,
 
349
    # try different urls here and see the cookie collection you can make !
 
350
 
 
351
    txdata = data
 
352
    # if we were making a POST type request,
 
353
    # we could encode a dictionary of values here,
 
354
    # using urllib.urlencode(somedict)
 
355
 
 
356
    txheaders =  {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}
 
357
    # fake a user agent, some websites (like google) don't like automated exploration
 
358
 
 
359
    try:
 
360
        req = Request(theurl, txdata, txheaders)
 
361
        # create a request object
 
362
 
 
363
        handle = urlopen(req)
 
364
        # and open it to return a handle on the url
 
365
        
 
366
        del req
 
367
 
 
368
    except IOError, e:
 
369
        return 2         #we didn't get a connection
 
370
 
 
371
 
 
372
    if cj is None:        
 
373
        return 3         #we got a connection, but didn't get any cookies
 
374
    else:
 
375
        cj.save(COOKIEFILE)                     # save the cookies again
 
376
        return 1        #everything went ok
 
377
    
 
378
##########################
 
379
#Get the number of unread items
 
380
#
 
381
def getUnreadItems():
 
382
    global unread, L, feeds
 
383
    LISTFILE = os.path.join(spectlib.util.get_path('tmp'), 'list.xml')
 
384
    url = 'https://www.google.com/reader/api/0/unread-count?all=true'
 
385
    try:
 
386
        req = Request(url)
 
387
        response = urlopen(req)
 
388
        del req
 
389
    except IOError, e:
 
390
        return 2         #we didn't get a connection
 
391
    testxml = response.read()
 
392
    del response
 
393
    if '<object>' in testxml:
 
394
        fileHandle = open ( LISTFILE, 'w' ) 
 
395
        fileHandle.write (testxml)
 
396
        del testxml
 
397
        fileHandle.close()
 
398
        fileHandle = open ( LISTFILE )
 
399
        unread = xml.dom.minidom.parse(fileHandle)
 
400
        fileHandle.close()
 
401
        del fileHandle
 
402
        countlist = unread.getElementsByTagName('number')
 
403
        namelist = unread.getElementsByTagName('string')
 
404
        for count in countlist:
 
405
            if count.attributes["name"].value != 'count':
 
406
                countlist.remove (count)
 
407
        del unread
 
408
        del L[:]
 
409
        found = 0
 
410
        for i in xrange (0, len(countlist)):
 
411
            if 'state/com.google/reading-list' in namelist[i].firstChild.toxml():
 
412
                unread =  countlist[i].firstChild.toxml()
 
413
                found = 1
 
414
            else:
 
415
                L.append ((countlist[i].firstChild.toxml() , namelist[i].firstChild.toxml() ))
 
416
        del countlist[:]
 
417
        del namelist[:]
 
418
        if not found:        #if there aren't any subscribed feeds
 
419
            unread = '-1'
 
420
        L = sorted (L, compare)
 
421
        feeds = len(L)
 
422
        return 1
 
423
    else:
 
424
        return 0
 
425
        
 
426
##################################
 
427
#Set the names of feeds the user is subscribed to
 
428
#
 
429
def updateFeeds():
 
430
    global names, feeds
 
431
    LISTFILE = os.path.join(spectlib.util.get_path('tmp'), 'names.xml')
 
432
    url = 'http://www.google.com/reader/api/0/subscription/list'
 
433
    try:
 
434
        req = Request(url)
 
435
        response = urlopen(req)
 
436
        del req
 
437
    except IOError, e:
 
438
        return 2         #we didn't get a connection
 
439
    testxml = response.read()    #read the opened page
 
440
    del response
 
441
    if '<object>' in testxml:    #if we got a XML file
 
442
        fileHandle = open ( LISTFILE, 'w' ) 
 
443
        fileHandle.write (testxml)
 
444
        del testxml
 
445
        fileHandle.close
 
446
        fileHandle = open ( LISTFILE )
 
447
        document = xml.dom.minidom.parse(fileHandle)
 
448
        fileHandle.close()
 
449
        del fileHandle
 
450
        del names[:]
 
451
        feedlist = document.getElementsByTagName('string')
 
452
        for j in xrange (0, len(feedlist)):
 
453
            if (feedlist[j].attributes["name"].value == 'id' or feedlist[j].attributes["name"].value == 'title'):
 
454
                if ('/state/com.google/broadcast' in feedlist[j].firstChild.toxml() or feedlist[j].firstChild.toxml()[0] != 'u'):
 
455
                    names.append (feedlist[j].firstChild.toxml())
 
456
        del document
 
457
        del feedlist[:]
 
458
        
 
459
def readFeeds():
 
460
    global names
 
461
    LISTFILE = os.path.join(spectlib.util.get_path('tmp'), 'names.xml')
 
462
    if os.path.isfile(LISTFILE):
 
463
        fileHandle = open ( LISTFILE )
 
464
        document = xml.dom.minidom.parse(fileHandle)
 
465
        del names[:]
 
466
        feedlist = document.getElementsByTagName('string')
 
467
        for j in xrange (0, len(feedlist)):
 
468
            if (feedlist[j].attributes["name"].value == 'id' or feedlist[j].attributes["name"].value == 'title'):
 
469
                if ('/state/com.google/broadcast' in feedlist[j].firstChild.toxml() or feedlist[j].firstChild.toxml()[0] != 'u'):
 
470
                    names.append (feedlist[j].firstChild.toxml())
 
471
        del document
 
472
        del feedlist[:]
 
473
        fileHandle.close()
 
474
    else:
 
475
        updateFeeds()
 
476
        
 
477
#################################
 
478
#Compare function to sort the feeds by number of unread items
 
479
#
 
480
def compare(a,b):
 
481
    return cmp(int(b[0]), int(a[0]))
 
482
 
 
483
class Greader():
 
484
    def __init__(self, username, password):
 
485
        global unread, info, extra_info, extra_info_friends, email, passwd
 
486
        global config_changed
 
487
        email = username
 
488
        passwd = password
 
489
        
 
490
    def refresh(self):
 
491
        cookies = getcookies()
 
492
        if (cookies == 1):
 
493
            cookies = getUnreadItems()
 
494
        if (cookies == 0):
 
495
            info = -1, 'Wrong username or password'
 
496
            extra_info = ''
 
497
        if (cookies == 2 ):
 
498
            info = -1, 'Could not establish a connection to server'
 
499
            extra_info = ''
 
500
        if (cookies == 3):
 
501
            info = -1, 'Could not get cookies'
 
502
            extra_info = ''
 
503
        if (cookies != 1):
 
504
            cookies = getcookies()
 
505
 
 
506
        if (unread == '-1'):
 
507
            info = 1, 'You are not subscribed to any feeds'
 
508
        elif (unread == '0'):
 
509
            info = 1, 'No unread items'
 
510
        elif (unread >= '1'):
 
511
            info = 2, unread
 
512
            
 
513
        readFeeds()
 
514
        if (len(L) >= numberFeeds):
 
515
            i = numberFeeds
 
516
        else:
 
517
            i =  len(L)# - 1
 
518
        extra_info = {}
 
519
        extra_info_friends = ''
 
520
        for i in xrange (0,i):
 
521
            found = 0
 
522
            for j in xrange (0, len(names)):
 
523
                if not found:
 
524
                    if (str(L[i][1]) == names[j] or '/state/com.google/broadcast-friends' in L[i][1]) and int (L[i][0]) != 0:
 
525
                        found = 1
 
526
                        if ('/state/com.google/broadcast-friends' in L[i][1]):
 
527
                            extra_info_friends += str(L[i][0])
 
528
                        else:
 
529
                            extra_info.update({names[j+1]: int(L[i][0])})
 
530
        del L[:]   #set the table back to empty, so same items don't get added time after time
 
531
 
 
532
        try:
 
533
            #remove the cache files
 
534
            os.unlink(os.path.join(spectlib.util.get_path('tmp'), 'names.xml'))
 
535
            os.unlink(os.path.join(spectlib.util.get_path('tmp'), 'cookies.lwp'))
 
536
            os.unlink(os.path.join(spectlib.util.get_path('tmp'), 'list.xml'))
 
537
        except:
 
538
            pass
 
539
        cj.clear_session_cookies()
 
540
        return info, extra_info_friends, extra_info