Bump to version 2.68. v2.68
authorLindsey Smith <lindsey@allthingsrss.com>
Fri, 1 Oct 2010 12:00:00 +0000 (12:00 +0000)
committerW. Trevor King <wking@tremily.us>
Thu, 4 Oct 2012 11:05:45 +0000 (07:05 -0400)
CHANGELOG
rss2email.py

index d9cf7ba67e4bb25b7fe40e78322e360baa062669..3ca50ade3e03c11fd9fa37052a0db76356b84f31 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+v2.68 (2010-10-01)
+    * Added ability to pause/resume checking of individual feeds through pause and unpause commands
+       * Added ability to import and export OPML feed lists through importopml and exportopml commands
+
+       
 v2.67 (2010-09-21)
     * Fixed entries that include an id which is blank (i.e., an empty string) were being resent 
     * Fixed some entries not being sent by email because they had bad From headers     
index 00fdbd7c54efd673372d239ed6d188254422d273..f23f7880aa4229dcf6804a99e677139df9e2d8bd 100755 (executable)
@@ -10,8 +10,12 @@ Usage:
   list
   reset
   delete n
+  pause n
+  unpause n
+  opmlexport
+  opmlimport filename
 """
-__version__ = "2.67"
+__version__ = "2.68"
 __author__ = "Lindsey Smith (lindsey@allthingsrss.com)"
 __copyright__ = "(C) 2004 Aaron Swartz. GNU GPL 2 or 3."
 ___contributors__ = ["Dean Jackson", "Brian Lalor", "Joey Hess", 
@@ -437,6 +441,7 @@ def getEmail(feed, entry):
 class Feed:
        def __init__(self, url, to):
                self.url, self.etag, self.modified, self.seen = url, None, None, {}
+               self.active = True
                self.to = to            
 
 def load(lock=1):
@@ -461,7 +466,11 @@ def load(lock=1):
                feeds = pickle.load(feedfileObject)
                if unix: 
                        fcntl.flock(feedfileObject.fileno(), locktype)
-
+       if feeds: 
+               for feed in feeds[1:]:
+                       if not hasattr(feed, 'active'): 
+                               feed.active = True
+               
        return feeds, feedfileObject
 
 def unlock(feeds, feedfileObject):
@@ -513,6 +522,8 @@ def run(num=None):
                for f in ifeeds:
                        try: 
                                feednum += 1
+                               if not f.active: continue
+                               
                                if VERBOSE: print >>warn, 'I: Processing [%d] "%s"' % (feednum, f.url)
                                r = {}
                                try:
@@ -633,7 +644,7 @@ def run(num=None):
                                        
                                        from_addr = getEmail(r.feed, entry)
                                        
-                                        name = h2t.unescape(getName(r, entry))
+                                       name = h2t.unescape(getName(r, entry))
                                        fromhdr = formataddr((name, from_addr,))
                                        tohdr = (f.to or default_to)
                                        subjecthdr = title
@@ -745,11 +756,53 @@ def list():
                print "default email:", default_to
        else: ifeeds = feeds; i = 0
        for f in ifeeds:
-               print `i`+':', f.url, '('+(f.to or ('default: '+default_to))+')'
+               active = '[*]' if f.active else '[ ]'
+               print `i`+':',active, f.url, '('+(f.to or ('default: '+default_to))+')'
                if not (f.to or default_to):
                        print "   W: Please define a default address with 'r2e email emailaddress'"
                i+= 1
 
+def opmlexport():
+       import xml.sax.saxutils
+       feeds, feedfileObject = load(lock=0)
+       
+       if feeds:
+               print '<?xml version="1.0" encoding="UTF-8"?>\n<opml version="1.0">\n<head>\n<title>rss2email OPML export</title>\n</head>\n<body>'
+               for f in feeds[1:]:
+                       url = xml.sax.saxutils.escape(f.url)
+                       print '<outline type="rss" text="%s" xmlUrl="%s"/>' % (url, url)
+               print '</body>\n</opml>'
+
+def opmlimport(importfile):
+       importfileObject = None
+       print 'Importing feeds from', importfile
+       if not os.path.exists(importfile):
+               print 'OPML import file "%s" does not exist.' % feedfile
+       try:
+               importfileObject = open(importfile, 'r')
+       except IOError, e:
+               print "OPML import file could not be opened: %s" % e
+               sys.exit(1)
+       try:
+               import xml.dom.minidom
+               dom = xml.dom.minidom.parse(importfileObject)
+               newfeeds = dom.getElementsByTagName('outline')
+       except:
+               print 'E: Unable to parse OPML file'
+               sys.exit(1)
+
+       feeds, feedfileObject = load(lock=1)
+       
+       import xml.sax.saxutils
+       
+       for f in newfeeds:
+               if f.hasAttribute('xmlUrl'):
+                       feedurl = f.getAttribute('xmlUrl')
+                       print 'Adding %s' % xml.sax.saxutils.unescape(feedurl)
+                       feeds.append(Feed(feedurl, None))
+                       
+       unlock(feeds, feedfileObject)
+
 def delete(n):
        feeds, feedfileObject = load()
        if (n == 0) and (feeds and isstr(feeds[0])):
@@ -763,6 +816,18 @@ def delete(n):
                        print >>warn, "W: feed IDs have changed, list before deleting again"
        unlock(feeds, feedfileObject)
        
+def toggleactive(n, active):
+       feeds, feedfileObject = load()
+       if (n == 0) and (feeds and isstr(feeds[0])):
+               print >>warn, "W: ID has to be equal to or higher than 1"
+       elif n >= len(feeds):
+               print >>warn, "W: no such feed"
+       else:
+               action = 'Unpausing' if active else 'Pausing'
+               print >>warn, "%s feed %s" % (action, feeds[n].url)
+               feeds[n].active = active
+       unlock(feeds, feedfileObject)
+       
 def reset():
        feeds, feedfileObject = load()
        if feeds and isstr(feeds[0]):
@@ -821,8 +886,24 @@ if __name__ == '__main__':
                        else:
                                raise InputError, "Action '%s' requires a number as its argument" % action
 
+               elif action in ("pause", "unpause"):
+                       if not args:
+                               raise InputError, "Action '%s' requires an argument" % action
+                       elif args[0].isdigit():
+                               active = (action == "unpause")
+                               toggleactive(int(args[0]), active)
+                       else:
+                               raise InputError, "Action '%s' requires a number as its argument" % action
+
                elif action == "reset": reset()
 
+               elif action == "opmlexport": opmlexport()
+
+               elif action == "opmlimport": 
+                       if not args:
+                               raise InputError, "OPML import '%s' requires a filename argument" % action
+                       opmlimport(args[0])
+
                else:
                        raise InputError, "Invalid action"