[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#800163: jessie-pu: package cloudprint/0.11-5



Package: release.debian.org
Severity: normal
Tags: jessie
User: release.debian.org@packages.debian.org
Usertags: pu


Google has removed support for SASL authentication for Cloud Print services,
and is now requiring OAuth2 authentication. This breaks the version of
cloudprint which is in Jessie, making the package totally non-functional.

I attempted a targeted patch of upstream changes to pull in only
OAuth2-relevant content. It was neither clean, concise, nor stable. Instead, I
am proposing to modify the 3-month-old upstream 0.13 release for Jessie.

Changes required:
 - revert to support for the older python-daemon module
 - remove a setup.py version restriction on 'requests'

Debdiff attached, with patch detail on deleted files removed.


The change relative to 0.13 is here:

https://github.com/davesteele/cloudprint-service/compare/debian/0.13-1...updates-jessie


-- System Information:
Debian Release: stretch/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.0.0-2-amd64 (SMP w/6 CPU cores)
Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8)

diff -Nru cloudprint-0.11/cloudprint/cloudprint.py cloudprint-0.13/cloudprint/cloudprint.py
--- cloudprint-0.11/cloudprint/cloudprint.py	2014-01-05 19:29:25.000000000 -0500
+++ cloudprint-0.13/cloudprint/cloudprint.py	2015-07-08 23:10:28.000000000 -0400
@@ -1,231 +1,264 @@
 #!/usr/bin/env python
-import rest
-import platform
+# Copyright 2014 Jason Michalski <armooo@armooo.net>
+#
+# This file is part of cloudprint.
+#
+# cloudprint is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cloudprint is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cloudprint.  If not, see <http://www.gnu.org/licenses/>.
+
+import argparse
 import cups
+import datetime
 import hashlib
-import time
-import urllib2
-import tempfile
-import shutil
-import os
 import json
-import getpass
-import stat
-import sys
-import getopt
 import logging
 import logging.handlers
+import os
+import re
+import requests
+import shutil
+import stat
+import sys
+import tempfile
+import time
+import uuid
 
 import xmpp
 
 XMPP_SERVER_HOST = 'talk.google.com'
-XMPP_USE_SSL = True
 XMPP_SERVER_PORT = 5223
 
 SOURCE = 'Armooo-PrintProxy-1'
 PRINT_CLOUD_SERVICE_ID = 'cloudprint'
 CLIENT_LOGIN_URL = '/accounts/ClientLogin'
-PRINT_CLOUD_URL = '/cloudprint/'
+PRINT_CLOUD_URL = 'https://www.google.com/cloudprint/'
 
 # period in seconds with which we should poll for new jobs via the HTTP api,
 # when xmpp is connecting properly.
 # 'None' to poll only on startup and when we get XMPP notifications.
 # 'Fast Poll' is used as a workaround when notifications are not working.
-POLL_PERIOD=3600.0
-FAST_POLL_PERIOD=30.0
+POLL_PERIOD = 3600.0
+FAST_POLL_PERIOD = 30.0
 
 # wait period to retry when xmpp fails
-FAIL_RETRY=60
+FAIL_RETRY = 60
 
 # how often, in seconds, to send a keepalive character over xmpp
-KEEPALIVE=600.0
+KEEPALIVE = 600.0
+
+# failed job retries
+RETRIES = 1
+num_retries = 0
 
 LOGGER = logging.getLogger('cloudprint')
 LOGGER.setLevel(logging.INFO)
 
-class CloudPrintProxy(object):
+CLIENT_ID = '607830223128-rqenc3ekjln2qi4m4ntudskhnsqn82gn.apps.googleusercontent.com'
+CLIENT_KEY = 'T0azsx2lqDztSRyPHQaERJJH'
 
-    def __init__(self, verbose=True):
-        self.verbose = verbose
-        self.auth = None
-        self.cups= cups.Connection()
-        self.proxy =  platform.node() + '-Armooo-PrintProxy'
-        self.auth_path = os.path.expanduser('~/.cloudprintauth')
-        self.xmpp_auth_path = os.path.expanduser('~/.cloudprintauth.sasl')
-        self.username = None
-        self.password = None
-        self.sleeptime = 0
 
-    def get_auth(self):
-        if self.auth:
-            return self.auth
-        if not self.auth:
-            auth = self.get_saved_auth()
-            if auth:
-                return auth
-
-            r = rest.REST('https://www.google.com', debug=False)
-            try:
-                auth_response = r.post(
-                    CLIENT_LOGIN_URL,
-                    {
-                        'accountType': 'GOOGLE',
-                        'Email': self.username,
-                        'Passwd': self.password,
-                        'service': PRINT_CLOUD_SERVICE_ID,
-                        'source': SOURCE,
-                    },
-                    'application/x-www-form-urlencoded')
-                xmpp_response = r.post(CLIENT_LOGIN_URL,
-                    {
-                        'accountType': 'GOOGLE',
-                        'Email': self.username,
-                        'Passwd': self.password,
-                        'service': 'mail',
-                        'source': SOURCE,
-                    },
-                    'application/x-www-form-urlencoded')
-                jid = self.username if '@' in self.username else self.username + '@gmail.com'
-                sasl_token = ('\0%s\0%s' % (jid, xmpp_response['Auth'])).encode('base64')
-                file(self.xmpp_auth_path, 'w').write(sasl_token)
-            except rest.REST.RESTException, e:
-                if 'InvalidSecondFactor' in e.msg:
-                    raise rest.REST.RESTException(
-                        '2-Step',
-                        '403',
-                        'You have 2-Step authentication enabled on your '
-                        'account. \n\nPlease visit '
-                        'https://www.google.com/accounts/IssuedAuthSubTokens '
-                        'to generate an application-specific password.'
-                    )
-                else:
-                    raise
+class CloudPrintAuth(object):
+    def __init__(self, auth_path):
+        self.auth_path = auth_path
+        self.guid = None
+        self.email = None
+        self.xmpp_jid = None
+        self.exp_time = None
+        self.refresh_token = None
+        self._access_token = None
+
+    @property
+    def session(self):
+        s = requests.session()
+        s.headers['X-CloudPrint-Proxy'] = 'ArmoooIsAnOEM'
+        s.headers['Authorization'] = 'Bearer {0}'.format(self.access_token)
+        return s
+
+    @property
+    def access_token(self):
+        if datetime.datetime.now() > self.exp_time:
+            self.refresh()
+        return self._access_token
+
+    def no_auth(self):
+        return not os.path.exists(self.auth_path)
+
+    def login(self, name, description, ppd):
+        self.guid = str(uuid.uuid4())
+        reg_data = requests.post(
+            PRINT_CLOUD_URL + 'register',
+            {
+                'output': 'json',
+                'printer': name,
+                'proxy':  self.guid,
+                'capabilities': ppd.encode('utf-8'),
+                'defaults': ppd.encode('utf-8'),
+                'status': 'OK',
+                'description': description,
+                'capsHash': hashlib.sha1(ppd.encode('utf-8')).hexdigest(),
+            },
+            headers={'X-CloudPrint-Proxy': 'ArmoooIsAnOEM'},
+        ).json()
+        print 'Goto {0} to clame this printer'.format(reg_data['complete_invite_url'])
+
+        end = time.time() + int(reg_data['token_duration'])
+        while time.time() < end:
+            time.sleep(10)
+            print 'trying for the win'
+            poll = requests.get(
+                reg_data['polling_url'] + CLIENT_ID,
+                headers={'X-CloudPrint-Proxy': 'ArmoooIsAnOEM'},
+            ).json()
+            if poll['success']:
+                break
+        else:
+            print 'The login request timedout'
 
-            self.set_auth(auth_response['Auth'])
-            return self.auth
+        self.xmpp_jid = poll['xmpp_jid']
+        self.email = poll['user_email']
+        print 'Printer claimed by {0}.'.format(self.email)
+
+        token = requests.post(
+            'https://accounts.google.com/o/oauth2/token',
+            data={
+                'redirect_uri': 'oob',
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_KEY,
+                'grant_type': 'authorization_code',
+                'code': poll['authorization_code'],
+            }
+        ).json()
+
+        self.refresh_token = token['refresh_token']
+        self.refresh()
+
+        self.save()
+
+    def refresh(self):
+        token = requests.post(
+            'https://accounts.google.com/o/oauth2/token',
+            data={
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_KEY,
+                'grant_type': 'refresh_token',
+                'refresh_token': self.refresh_token,
+            }
+        ).json()
+        self._access_token = token['access_token']
+
+        slop_time = datetime.timedelta(minutes=15)
+        expires_in = datetime.timedelta(seconds=token['expires_in'])
+        self.exp_time = datetime.datetime.now() + (expires_in - slop_time)
 
-    def get_saved_auth(self):
+    def load(self):
         if os.path.exists(self.auth_path):
-            auth_file = open(self.auth_path)
-            self.auth = auth_file.read()
-            auth_file.close()
-            return self.auth
+            with open(self.auth_path) as auth_file:
+                auth_data = json.load(auth_file)
+            self.guid = auth_data['guid']
+            self.xmpp_jid = auth_data['xmpp_jid']
+            self.email = auth_data['email']
+            self.refresh_token = auth_data['refresh_token']
+
+        self.refresh()
 
-    def del_saved_auth(self):
+    def delete(self):
         if os.path.exists(self.auth_path):
             os.unlink(self.auth_path)
 
-    def set_auth(self, auth):
-            self.auth = auth
+    def save(self):
             if not os.path.exists(self.auth_path):
-                auth_file = open(self.auth_path, 'w')
-                os.chmod(self.auth_path, stat.S_IRUSR | stat.S_IWUSR)
-                auth_file.close()
-            auth_file = open(self.auth_path, 'w')
-            auth_file.write(self.auth)
-            auth_file.close()
-
-    def get_rest(self):
-        class check_new_auth(object):
-            def __init__(self, rest):
-                self.rest = rest
-
-            def __getattr__(in_self, key):
-                attr = getattr(in_self.rest, key)
-                if not attr:
-                    raise AttributeError()
-                if not hasattr(attr, '__call__'):
-                    return attr
-
-                def f(*arg, **karg):
-                    r = attr(*arg, **karg)
-                    if 'update-client-auth' in r.headers:
-                        self.set_auth(r.headers['update-client-auth'])
-                    return r
-                return f
+                with open(self.auth_path, 'w') as auth_file:
+                    os.chmod(self.auth_path, stat.S_IRUSR | stat.S_IWUSR)
+            with open(self.auth_path, 'w') as auth_file:
+                json.dump({
+                    'guid':  self.guid,
+                    'email': self.email,
+                    'xmpp_jid': self.xmpp_jid,
+                    'refresh_token': self.refresh_token,
+                    },
+                    auth_file
+                )
+
 
-        auth = self.get_auth()
-        return check_new_auth(rest.REST('https://www.google.com', auth=auth, debug=False))
+class CloudPrintProxy(object):
+
+    def __init__(self, auth):
+        self.auth = auth
+        self.sleeptime = 0
+        self.include = []
+        self.exclude = []
 
     def get_printers(self):
-        r = self.get_rest()
-        printers = r.post(
+        printers = self.auth.session.post(
             PRINT_CLOUD_URL + 'list',
             {
                 'output': 'json',
-                'proxy': self.proxy,
+                'proxy': self.auth.guid,
             },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM'},
-        )
-        return [ PrinterProxy(self, p['id'], p['name']) for p in printers['printers'] ]
+        ).json()
+        return [PrinterProxy(self, p['id'], p['name']) for p in printers['printers']]
 
     def delete_printer(self, printer_id):
-        r = self.get_rest()
-        docs = r.post(
+        self.auth.session.post(
             PRINT_CLOUD_URL + 'delete',
             {
-                'output' : 'json',
+                'output': 'json',
                 'printerid': printer_id,
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM'},
-        )
-        if self.verbose:
-            LOGGER.info('Deleted printer '+ printer_id)
+           },
+        ).raise_for_status()
+        LOGGER.debug('Deleted printer ' + printer_id)
 
     def add_printer(self, name, description, ppd):
-        r = self.get_rest()
-        r.post(
+        self.auth.session.post(
             PRINT_CLOUD_URL + 'register',
             {
-                'output' : 'json',
-                'printer' : name,
-                'proxy' :  self.proxy,
-                'capabilities' : ppd.encode('utf-8'),
-                'defaults' : ppd.encode('utf-8'),
-                'status' : 'OK',
-                'description' : description,
-                'capsHash' : hashlib.sha1(ppd.encode('utf-8')).hexdigest(),
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM'},
-        )
-        if self.verbose:
-            LOGGER.info('Added Printer ' + name)
+                'output': 'json',
+                'printer': name,
+                'proxy':  self.auth.guid,
+                'capabilities': ppd.encode('utf-8'),
+                'defaults': ppd.encode('utf-8'),
+                'status': 'OK',
+                'description': description,
+                'capsHash': hashlib.sha1(ppd.encode('utf-8')).hexdigest(),
+           },
+        ).raise_for_status()
+        LOGGER.debug('Added Printer ' + name)
 
     def update_printer(self, printer_id, name, description, ppd):
-        r = self.get_rest()
-        r.post(
+        self.auth.session.post(
             PRINT_CLOUD_URL + 'update',
             {
-                'output' : 'json',
-                'printerid' : printer_id,
-                'printer' : name,
-                'proxy' : self.proxy,
-                'capabilities' : ppd.encode('utf-8'),
-                'defaults' : ppd.encode('utf-8'),
-                'status' : 'OK',
-                'description' : description,
-                'capsHash' : hashlib.sha1(ppd.encode('utf-8')).hexdigest(),
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM'},
-        )
-        if self.verbose:
-            LOGGER.info('Updated Printer ' + name)
+                'output': 'json',
+                'printerid': printer_id,
+                'printer': name,
+                'proxy': self.auth.guid,
+                'capabilities': ppd.encode('utf-8'),
+                'defaults': ppd.encode('utf-8'),
+                'status': 'OK',
+                'description': description,
+                'capsHash': hashlib.sha1(ppd.encode('utf-8')).hexdigest(),
+           },
+        ).raise_for_status()
+        LOGGER.debug('Updated Printer ' + name)
 
     def get_jobs(self, printer_id):
-        r = self.get_rest()
-        docs = r.post(
+        docs = self.auth.session.post(
             PRINT_CLOUD_URL + 'fetch',
             {
-                'output' : 'json',
+                'output': 'json',
                 'printerid': printer_id,
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM'},
-        )
+           },
+        ).json()
 
         if not 'jobs' in docs:
             return []
@@ -233,30 +266,27 @@
             return docs['jobs']
 
     def finish_job(self, job_id):
-        r = self.get_rest()
-        r.post(
+        self.auth.session.post(
             PRINT_CLOUD_URL + 'control',
             {
-                'output' : 'json',
+                'output': 'json',
                 'jobid': job_id,
                 'status': 'DONE',
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM' },
-        )
+           },
+        ).json()
+        LOGGER.debug('Finished Job' + job_id)
 
     def fail_job(self, job_id):
-        r = self.get_rest()
-        r.post(
+        self.auth.session.post(
             PRINT_CLOUD_URL + 'control',
             {
-                'output' : 'json',
+                'output': 'json',
                 'jobid': job_id,
                 'status': 'ERROR',
-            },
-            'application/x-www-form-urlencoded',
-            { 'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM' },
-        )
+           },
+        ).json()
+        LOGGER.debug('Failed Job' + job_id)
+
 
 class PrinterProxy(object):
     def __init__(self, cpp, printer_id, name):
@@ -274,19 +304,27 @@
     def delete(self):
         return self.cpp.delete_printer(self.id)
 
-class App(object):
-    def __init__(self, cups_connection=None, cpp=None, printers=None, pidfile_path=None):
-        self.cups_connection = cups_connection
-        self.cpp = cpp
-        self.printers = printers
-        self.pidfile_path = pidfile_path
-        self.stdin_path = '/dev/null'
-        self.stdout_path = '/dev/null'
-        self.stderr_path = '/dev/null'
-        self.pidfile_timeout = 5
 
-    def run(self):
-        process_jobs(self.cups_connection, self.cpp, self.printers)
+#True if printer name matches *any* of the regular expressions in regexps
+def match_re(prn, regexps, empty=False):
+    if len(regexps):
+        try:
+            return re.match(regexps[0], prn, re.UNICODE) or match_re(prn, regexps[1:])
+        except Exception:
+            sys.stderr.write('cloudprint: invalid regular expression: ' + regexps[0] + '\n')
+            sys.exit(1)
+    else:
+        return empty
+
+
+def get_printer_info(cups_connection, printer_name):
+        with open(cups_connection.getPPD(printer_name)) as ppd_file:
+            ppd = ppd_file.read()
+        #This is bad it should use the LanguageEncoding in the PPD
+        #But a lot of utf-8 PPDs seem to say they are ISOLatin1
+        ppd = ppd.decode('utf-8')
+        description = cups_connection.getPrinterAttributes(printer_name)['printer-info']
+        return ppd, description
 
 
 def sync_printers(cups_connection, cpp):
@@ -294,210 +332,173 @@
     remote_printers = dict([(p.name, p) for p in cpp.get_printers()])
     remote_printer_names = set(remote_printers)
 
+    #Include/exclude local printers
+    local_printer_names = set([prn for prn in local_printer_names if match_re(prn, cpp.include, True)])
+    local_printer_names = set([prn for prn in local_printer_names if not match_re(prn, cpp.exclude)])
+
     #New printers
     for printer_name in local_printer_names - remote_printer_names:
         try:
-            ppd_file = open(cups_connection.getPPD(printer_name))
-            ppd = ppd_file.read()
-            ppd_file.close()
-            #This is bad it should use the LanguageEncoding in the PPD
-            #But a lot of utf-8 PPDs seem to say they are ISOLatin1
-            ppd = ppd.decode('utf-8')
-            description = cups_connection.getPrinterAttributes(printer_name)['printer-info']
+            ppd, description = get_printer_info(cups_connection, printer_name)
             cpp.add_printer(printer_name, description, ppd)
         except (cups.IPPError, UnicodeDecodeError):
             LOGGER.info('Skipping ' + printer_name)
 
     #Existing printers
     for printer_name in local_printer_names & remote_printer_names:
-        ppd_file = open(cups_connection.getPPD(printer_name))
-        ppd = ppd_file.read()
-        ppd_file.close()
-        #This is bad it should use the LanguageEncoding in the PPD
-        #But a lot of utf-8 PPDs seem to say they are ISOLatin1
-        try:
-            ppd = ppd.decode('utf-8')
-        except UnicodeDecodeError:
-            pass
-        description = cups_connection.getPrinterAttributes(printer_name)['printer-info']
+        ppd, description = get_printer_info(cups_connection, printer_name)
         remote_printers[printer_name].update(description, ppd)
 
     #Printers that have left us
     for printer_name in remote_printer_names - local_printer_names:
         remote_printers[printer_name].delete()
 
+
 def process_job(cups_connection, cpp, printer, job):
-    request = urllib2.Request(job['fileUrl'], headers={
-        'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM',
-        'Authorization' : 'GoogleLogin auth=%s' % cpp.get_auth()
-    })
+    global num_retries
 
     try:
-        pdf = urllib2.urlopen(request)
+        pdf = cpp.auth.session.get(job['fileUrl'], stream=True)
         tmp = tempfile.NamedTemporaryFile(delete=False)
-        shutil.copyfileobj(pdf, tmp)
+        shutil.copyfileobj(pdf.raw, tmp)
         tmp.flush()
 
-        request = urllib2.Request(job['ticketUrl'], headers={
-            'X-CloudPrint-Proxy' : 'ArmoooIsAnOEM',
-            'Authorization' : 'GoogleLogin auth=%s' % cpp.get_auth()
-        })
-        options = json.loads(urllib2.urlopen(request).read())
-        if 'request' in options: del options['request']
-        options = dict( (str(k), str(v)) for k, v in options.items() )
+        options = cpp.auth.session.get(job['ticketUrl']).json()
+        if 'request' in options:
+            del options['request']
 
-        cpp.finish_job(job['id'])
+        options = dict((str(k), str(v)) for k, v in options.items())
 
-        cups_connection.printFile(printer.name, tmp.name, job['title'], options)
+        # Cap the title length to 255, or cups will complain about invalid job-name
+        cups_connection.printFile(printer.name, tmp.name, job['title'][:255], options)
         os.unlink(tmp.name)
         LOGGER.info('SUCCESS ' + job['title'].encode('unicode-escape'))
 
-    except:
-        cpp.fail_job(job['id'])
-        LOGGER.error('ERROR ' + job['title'].encode('unicode-escape'))
+        cpp.finish_job(job['id'])
+        num_retries = 0
+
+    except Exception:
+        if num_retries >= RETRIES:
+            num_retries = 0
+            cpp.fail_job(job['id'])
+            LOGGER.error('ERROR ' + job['title'].encode('unicode-escape'))
+        else:
+            num_retries += 1
+            LOGGER.info('Job %s failed - Will retry' % job['title'].encode('unicode-escape'))
 
-def process_jobs(cups_connection, cpp, printers):
-    xmpp_auth = file(cpp.xmpp_auth_path).read()
+
+def process_jobs(cups_connection, cpp):
     xmpp_conn = xmpp.XmppConnection(keepalive_period=KEEPALIVE)
 
     while True:
+        printers = cpp.get_printers()
         try:
             for printer in printers:
                 for job in printer.get_jobs():
                     process_job(cups_connection, cpp, printer, job)
 
             if not xmpp_conn.is_connected():
-                xmpp_conn.connect(XMPP_SERVER_HOST,XMPP_SERVER_PORT,
-                                  XMPP_USE_SSL,xmpp_auth)
+                xmpp_conn.connect(XMPP_SERVER_HOST, XMPP_SERVER_PORT, cpp.auth)
 
             xmpp_conn.await_notification(cpp.sleeptime)
 
-        except:
+        except Exception:
             global FAIL_RETRY
-            LOGGER.error('ERROR: Could not Connect to Cloud Service. Will Try again in %d Seconds' % FAIL_RETRY)
+            LOGGER.exception('ERROR: Could not Connect to Cloud Service. Will Try again in %d Seconds' % FAIL_RETRY)
             time.sleep(FAIL_RETRY)
 
 
-def usage():
-    print sys.argv[0] + ' [-d][-l][-h][-c][-f][-v] [-p pid_file] [-a account_file]'
-    print '-d\t\t: enable daemon mode (requires the daemon module)'
-    print '-l\t\t: logout of the google account'
-    print '-p pid_file\t: path to write the pid to (default cloudprint.pid)'
-    print '-a account_file\t: path to google account ident data (default ~/.cloudprintauth)'
-    print '\t\t account_file format:\t <Google username>'
-    print '\t\t\t\t\t <Google password>'
-    print '-c\t\t: establish and store login credentials, then exit'
-    print '-f\t\t: use fast poll if notifications are not working'
-    print '-v\t\t: verbose logging'
-    print '-h\t\t: display this help'
-
 def main():
-    opts, args = getopt.getopt(sys.argv[1:], 'dlhp:a:cvf')
-    daemon = False
-    logout = False
-    pidfile = None
-    authfile = None
-    authonly = False
-    verbose = False
-    saslauthfile = None
-    fastpoll = False
-    for o, a in opts:
-        if o == '-d':
-            daemon = True
-        elif o == '-l':
-            logout = True
-        elif o == '-p':
-            pidfile = a
-        elif o == '-a':
-            authfile = a
-            saslauthfile = authfile+'.sasl'
-        elif o == '-c':
-            authonly = True
-        elif o == '-v':
-            verbose = True
-        elif o == '-f':
-            fastpoll = True
-        elif o =='-h':
-            usage()
-            sys.exit()
-    if not pidfile:
-        pidfile = 'cloudprint.pid'
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-d', dest='daemon', action='store_true',
+                        help='enable daemon mode (requires the daemon module)')
+    parser.add_argument('-l', dest='logout', action='store_true',
+                        help='logout of the google account')
+    parser.add_argument('-p', metavar='pid_file', dest='pidfile', default='cloudprint.pid',
+                        help='path to write the pid to (default %(default)s)')
+    parser.add_argument('-a', metavar='account_file', dest='authfile', default=os.path.expanduser('~/.cloudprintauth.json'),
+                        help='path to google account ident data (default %(default)s)')
+    parser.add_argument('-c', dest='authonly', action='store_true',
+                        help='establish and store login credentials, then exit')
+    parser.add_argument('-f', dest='fastpoll', action='store_true',
+                        help='use fast poll if notifications are not working')
+    parser.add_argument('-i', metavar='regexp', dest='include', default=[], action='append',
+                        help='include local printers matching %(metavar)s')
+    parser.add_argument('-x', metavar='regexp', dest='exclude', default=[], action='append',
+                        help='exclude local printers matching %(metavar)s')
+    parser.add_argument('-v', dest='verbose', action='store_true',
+                        help='verbose logging')
+    args = parser.parse_args()
 
     # if daemon, log to syslog, otherwise log to stdout
-    if daemon:
-        handler = logging.handlers.SysLogHandler(address='/dev/log')
+    if args.daemon:
+        handler = logging.handlers.SysLogHandler()
         handler.setFormatter(logging.Formatter(fmt='cloudprint.py: %(message)s'))
     else:
         handler = logging.StreamHandler(sys.stdout)
     LOGGER.addHandler(handler)
 
-    if verbose:
+    if args.verbose:
         LOGGER.info('Setting DEBUG-level logging')
         LOGGER.setLevel(logging.DEBUG)
 
+        import httplib
+        httplib.HTTPConnection.debuglevel = 1
+        requests_log = logging.getLogger("requests.packages.urllib3")
+        requests_log.setLevel(logging.DEBUG)
+        requests_log.propagate = True
+
+    auth = CloudPrintAuth(args.authfile)
+    if args.logout:
+        auth.delete()
+        LOGGER.info('logged out')
+        return
+
     cups_connection = cups.Connection()
-    cpp = CloudPrintProxy()
-    if authfile:
-        cpp.auth_path = authfile
-        cpp.xmpp_auth_path = saslauthfile
+    cpp = CloudPrintProxy(auth)
 
     cpp.sleeptime = POLL_PERIOD
-    if fastpoll:
+    if args.fastpoll:
         cpp.sleeptime = FAST_POLL_PERIOD
 
-    if logout:
-        cpp.del_saved_auth()
-        LOGGER.info('logged out')
+    cpp.include = args.include
+    cpp.exclude = args.exclude
+
+    printers = cups_connection.getPrinters().keys()
+    if not printers:
+        LOGGER.error('No printers found')
         return
 
-    # Check if authentification is needed
-    if not cpp.get_saved_auth():
-        if authfile and os.path.exists(authfile):
-            account_file = open(authfile)
-            cpp.username = account_file.next().rstrip()
-            cpp.password = account_file.next().rstrip()
-            account_file.close()
+    if auth.no_auth():
+        name = printers[0]
+        ppd, description = get_printer_info(cups_connection, name)
+        auth.login(name, description, ppd)
+    else:
+        auth.load()
 
-        else:
-          cpp.username = raw_input('Google username: ')
-          cpp.password = getpass.getpass()
+    sync_printers(cups_connection, cpp)
 
-    #try to login
-    while True:
-        try:
-            sync_printers(cups_connection, cpp)
-            break
-        except rest.REST.RESTException, e:
-            #not a auth error
-            if e.code != 403:
-                raise
-            #don't have a stored auth key
-            if not cpp.get_saved_auth():
-                raise
-            #reset the stored auth
-            cpp.set_auth('')
-
-    if authonly:
+    if args.authonly:
         sys.exit(0)
 
-    printers = cpp.get_printers()
-
-    if daemon:
+    if args.daemon:
         try:
-            from daemon import runner
+            import daemon
+            import daemon.pidfile
         except ImportError:
             print 'daemon module required for -d'
-            print '\tyum install python-daemon, or apt-get install python-daemon, or pip install python-daemon'
+            print '\tyum install python-daemon, or apt-get install python-daemon, or pip install cloudprint[daemon]'
             sys.exit(1)
-        
-        app = App(cups_connection=cups_connection,
-                  cpp=cpp, printers=printers,
-                  pidfile_path=os.path.abspath(pidfile))
-        sys.argv=[sys.argv[0], 'start']
-        daemon_runner = runner.DaemonRunner(app)
-        daemon_runner.do_action()
+
+        pidfile = daemon.pidfile.TimeoutPIDLockFile(
+            path=os.path.abspath(args.pidfile),
+            timeout=5,
+        )
+        with daemon.DaemonContext(pidfile=pidfile):
+            process_jobs(cups_connection, cpp)
+
     else:
-        process_jobs(cups_connection, cpp, printers)
+        process_jobs(cups_connection, cpp)
 
 if __name__ == '__main__':
     main()
diff -Nru cloudprint-0.11/cloudprint/__init__.py cloudprint-0.13/cloudprint/__init__.py
--- cloudprint-0.11/cloudprint/__init__.py	2012-09-13 19:08:21.000000000 -0400
+++ cloudprint-0.13/cloudprint/__init__.py	2015-06-08 00:57:22.000000000 -0400
@@ -0,0 +1,16 @@
+# Copyright 2014 Jason Michalski <armooo@armooo.net>
+#
+# This file is part of cloudprint.
+#
+# cloudprint is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cloudprint is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cloudprint.  If not, see <http://www.gnu.org/licenses/>.
diff -Nru cloudprint-0.11/cloudprint/xmpp.py cloudprint-0.13/cloudprint/xmpp.py
--- cloudprint-0.11/cloudprint/xmpp.py	2014-01-05 19:29:25.000000000 -0500
+++ cloudprint-0.13/cloudprint/xmpp.py	2015-06-08 00:57:22.000000000 -0400
@@ -1,3 +1,19 @@
+# Copyright 2014 Jason Michalski <armooo@armooo.net>
+# This file is part of cloudprint.
+#
+# cloudprint is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cloudprint is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+
+import base64
 import logging
 import ssl
 import socket
@@ -9,8 +25,9 @@
 
 LOGGER = logging.getLogger('cloudprint.xmpp')
 
+
 class XmppXmlHandler(object):
-    STREAM_TAG='{http://etherx.jabber.org/streams}stream'
+    STREAM_TAG = '{http://etherx.jabber.org/streams}stream'
 
     def __init__(self):
         self._stack = 0
@@ -48,6 +65,7 @@
         except IndexError:
             return None
 
+
 class XmppConnection(object):
     def __init__(self, keepalive_period=60.0):
         self._connected = False
@@ -96,7 +114,6 @@
             # need more data; block until it becomes available
             self._read_socket()
 
-
     def _check_for_notification(self):
         """Check for any notifications which have already been received"""
         return(self._handler.get_elem() is not None)
@@ -105,8 +122,7 @@
         LOGGER.info("Sending XMPP keepalive")
         self._write_socket(" ")
 
-
-    def connect(self, host, port, use_ssl, sasl_token):
+    def connect(self, host, port, auth):
         """Establish a new connection to the XMPP server"""
         # first close any existing socket
         self.close()
@@ -115,10 +131,10 @@
                     (host, port))
         self._xmppsock = socket.socket()
         self._wrappedsock = self._xmppsock
+        auth_string = base64.b64encode('\0{0}\0{1}'.format(auth.xmpp_jid, auth.access_token))
 
         try:
-            if use_ssl:
-                self._wrappedsock = ssl.wrap_socket(self._xmppsock)
+            self._wrappedsock = ssl.wrap_socket(self._xmppsock)
             self._wrappedsock.connect((host, port))
 
             self._handler = XmppXmlHandler()
@@ -126,9 +142,9 @@
 
             # https://developers.google.com/cloud-print/docs/rawxmpp
             self._msg('<stream:stream to="gmail.com" xml:lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams"; xmlns="jabber:client">')
-            self._msg('<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="X-GOOGLE-TOKEN" auth:allow-generated-jid="true" auth:client-uses-full-bind-result="true" xmlns:auth="http://www.google.com/talk/protocol/auth";>%s</auth>' % sasl_token)
+            self._msg('<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="X-OAUTH2">%s</auth>' % auth_string)
             self._msg('<stream:stream to="gmail.com" xml:lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams"; xmlns="jabber:client">')
-            iq = self._msg('<iq type="set" id="0"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>Armooo</resource></bind></iq>')
+            iq = self._msg('<iq type="set" id="0"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>cloud_print</resource></bind></iq>')
             bare_jid = iq[0][0].text.split('/')[0]
             self._msg('<iq type="set" id="2"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>')
             self._msg('<iq type="set" id="3" to="%s"><subscribe xmlns="google:push"><item channel="cloudprint.google.com" from="cloudprint.google.com"/></subscribe></iq>' % bare_jid)
@@ -139,23 +155,24 @@
         LOGGER.info("xmpp connection established")
         self._connected = True
 
-
     def close(self):
         """Close the connection to the XMPP server"""
-        if self._wrappedsock is not None:
+        try:
             self._wrappedsock.shutdown(socket.SHUT_RDWR)
             self._wrappedsock.close()
+        except:
+            # close() is best effort. Don't respond to failures
+            LOGGER.debug("Error encountered closing XMPP socket")
+        finally:
+            self._connected = False
+            self._nextkeepalive = 0
             self._wrappedsock = None
-        self._connected = False
-        self._nextkeepalive = 0
-
 
     def is_connected(self):
         """Check if we are connected to the XMPP server
         returns true if the connection is active; false otherwise"""
         return self._connected
 
-
     def await_notification(self, timeout):
         """wait for a timeout or event notification"""
         now = time.time()
@@ -203,4 +220,3 @@
             except:
                 self.close()
                 raise
-
diff -Nru cloudprint-0.11/cloudprint.egg-info/PKG-INFO cloudprint-0.13/cloudprint.egg-info/PKG-INFO
--- cloudprint-0.11/cloudprint.egg-info/PKG-INFO	2014-01-05 19:53:29.000000000 -0500
+++ cloudprint-0.13/cloudprint.egg-info/PKG-INFO	2015-07-08 23:17:23.000000000 -0400
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cloudprint
-Version: 0.11
+Version: 0.13
 Summary: Google cloud print proxy for linux/OSX
 Home-page: https://github.com/armooo/cloudprint
 Author: Jason Michalski
@@ -9,10 +9,14 @@
 Description: Share your CUPS printers with google's cloud print.
         Works with linux and OS X.
         
+        This software is a python implementation of a cloud print connector. Unlike
+        Google's linux connector, it does not require chrome to be installed on the server.
+        
+        
         Requires
         ---------------------------------------------------
-        python 2.6 or 2.7
-        pycups (can be tricky on OS X)
+        - python 2.6 or 2.7
+        - pycups (can be tricky on OS X) wich depends on libcups2-dev
         
         Usage
         ---------------------------------------------------
@@ -24,10 +28,14 @@
           -l              : logout of the current google account
           -p pid_file     : path to write the pid to (default cloudprint.pid)
           -a account_file : path to google account ident data (optional)
-                            account_file format:  <Google username>
-                                                  <Google password>
           -c              : establish and store login credentials, then exit
           -f              : 'fast poll', if notifications aren't working
+          -u              : store username/password in addition to login token
+                            to avoid authentication expiration
+          -i regexp       : include files matching regexp
+          -x regexp       : exclude filees matching regexp
+                            regexp: a Python regexp, which is matched against the
+                                    start of the printer name
           -h              : display this help
         
         Google accounts with 2 step verification enabled need to use an
@@ -43,12 +51,40 @@
           Password:
           Added Printer Brother-HL-2170W
         
+        Examples - Include/Exclude
+        ---------------------------------------------------
+        
+        Include only the printers "`lp`" and "`2up`":
+        ::
+        
+          cloudprint -i lp -i 2up
+        
+        Exclude all printers whose names start with "`GCP-`":
+        ::
+        
+          cloudprint -x GCP-
+        
+        By default, all printers are included.  For the include and exclude options,
+        the argument is a regular expression which is matched against the start of the
+        printer name.
+        
+        For example, to include all printers whose names begin "`lp`":
+        ::
+        
+          cloudprint -i lp # includes both lp and lp2up
+        
+        
         Install
         ---------------------------------------------------
         
         ::
         
           pip install cloudprint
+          or with optional daemon support
+          pip install cloudprint[daemon]
+        
+        After running cloudprint, verify that the connector successfully installed the cloud printer by visiting
+        http://www.google.com/cloudprint/manage.html.
         
 Platform: UNKNOWN
 Classifier: Development Status :: 4 - Beta
diff -Nru cloudprint-0.11/cloudprint.egg-info/requires.txt cloudprint-0.13/cloudprint.egg-info/requires.txt
--- cloudprint-0.11/cloudprint.egg-info/requires.txt	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/cloudprint.egg-info/requires.txt	2015-07-08 23:17:23.000000000 -0400
@@ -0,0 +1,5 @@
+requests >= 2.7.0
+pycups
+
+[daemon]
+python-daemon >= 2.0.0
\ No newline at end of file
diff -Nru cloudprint-0.11/cloudprint.egg-info/SOURCES.txt cloudprint-0.13/cloudprint.egg-info/SOURCES.txt
--- cloudprint-0.11/cloudprint.egg-info/SOURCES.txt	2014-01-05 19:53:29.000000000 -0500
+++ cloudprint-0.13/cloudprint.egg-info/SOURCES.txt	2015-07-08 23:17:23.000000000 -0400
@@ -4,10 +4,10 @@
 setup.py
 cloudprint/__init__.py
 cloudprint/cloudprint.py
-cloudprint/rest.py
 cloudprint/xmpp.py
 cloudprint.egg-info/PKG-INFO
 cloudprint.egg-info/SOURCES.txt
 cloudprint.egg-info/dependency_links.txt
 cloudprint.egg-info/entry_points.txt
+cloudprint.egg-info/requires.txt
 cloudprint.egg-info/top_level.txt
\ No newline at end of file
diff -Nru cloudprint-0.11/debian/changelog cloudprint-0.13/debian/changelog
--- cloudprint-0.11/debian/changelog	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/changelog	2015-09-27 10:39:41.000000000 -0400
@@ -1,3 +1,71 @@
+cloudprint (0.13-1+deb8u3) UNRELEASED; urgency=medium
+
+  * Modify for Jessie
+    - Brings OAuth support to Jessie.
+      (Closes: 799227, 800082)
+    - Remove version requirement on python-requests.
+    - Revert back to support for older python-daemon module.
+
+ -- David Steele <dsteele@gmail.com>  Thu, 24 Sep 2015 21:35:16 -0400
+
+cloudprint (0.13-1) unstable; urgency=low
+
+  * Upstream update, with bug fixes
+      Closes: 792055
+
+ -- David Steele <dsteele@gmail.com>  Sat, 11 Jul 2015 01:09:04 -0400
+
+cloudprint (0.12-3) unstable; urgency=low
+
+  * Clear out the old init file the right way (Closes: 791624).
+
+ -- David Steele <dsteele@gmail.com>  Mon, 06 Jul 2015 21:44:39 -0400
+
+cloudprint (0.12-2) unstable; urgency=low
+
+  * Don't remove the old auth file, in case the upgrade fails.
+
+ -- David Steele <dsteele@gmail.com>  Mon, 06 Jul 2015 08:59:05 -0400
+
+cloudprint (0.12-1) unstable; urgency=low
+
+  * Incorporate upstream 0.12.
+    - Different OAuth2 implementation.
+  * Adapt to incompatible change to python-daemon
+
+ -- David Steele <dsteele@gmail.com>  Mon, 08 Jun 2015 21:50:28 -0400
+
+cloudprint (0.11-9) unstable; urgency=low
+
+  * Remove the GNOME requirement for OAuth2.
+  * Remove old sysv-init files on install.
+  * Other minor changes.
+
+ -- David Steele <dsteele@gmail.com>  Fri, 05 Jun 2015 21:25:55 -0400
+
+cloudprint (0.11-8) unstable; urgency=low
+
+  * Fixes to declared dependencies.
+  * Better GUI detection.
+
+ -- David Steele <dsteele@gmail.com>  Wed, 03 Jun 2015 19:30:04 -0400
+
+cloudprint (0.11-7) unstable; urgency=low
+
+  * OAuth2 support, since the old SASL is not longer working.
+        (Closes: 787102)
+  * Replace sysv init with systemd.
+
+ -- David Steele <dsteele@gmail.com>  Sat, 30 May 2015 16:44:05 -0400
+
+cloudprint (0.11-6) unstable; urgency=low
+
+  * Limit print jobs names to avoid CUPS fail (thanks Alexandre Bury).
+  * Mark the Cloud Print job as failed if CUPS fails.
+  * Retry the print job on failure.
+
+ -- David Steele <dsteele@gmail.com>  Thu, 16 Apr 2015 21:39:22 -0400
+
 cloudprint (0.11-5) unstable; urgency=low
 
   * Fix init.d functionality breakage from daemon rename in 0.11-4.
diff -Nru cloudprint-0.11/debian/cloudprint.man.in cloudprint-0.13/debian/cloudprint.man.in
--- cloudprint-0.11/debian/cloudprint.man.in	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/cloudprint.man.in	2015-09-27 10:39:41.000000000 -0400
@@ -1,15 +1,15 @@
-.\" Copyright 2013-2014 David Steele <dsteele@gmail.com>
+.\" Copyright 2013-2015 David Steele <dsteele@gmail.com>
 .\" This file is part of cloudprint
 .\" Available under the terms of the GNU General Public License version 2 or later
-.TH PROG 1 2014-04-16 Linux "User Commands"
+.TH cloudprint 1 2015-05-31 Linux "User Commands"
 .SH NAME
-PROG \- share CUPS printers with Google Cloud Print
+cloudprint \- share CUPS printers with Google Cloud Print
 
 .SH SYNOPSIS
-\fBPROG\fP [\fIOPTION\fP]...
+\fBcloudprint\fP [\fIOPTION\fP]...
 
 .SH DESCRIPTION
-The \fBPROG\fP script makes locally defined CUPS printers available to
+The \fBcloudprint\fP script makes locally defined CUPS printers available to
 a Google account, enabling local or remote printing from such services as
 the Chrome browser, Chrome OS devices, or Android devices.
 
@@ -38,13 +38,13 @@
 .TP
 \fB\-l\fR
 log out of the Google account. This deletes the account identification file, requiring reauthentication the next time
-PROG is run.
+cloudprint is run.
 .TP
 \fB\-p\fR \fI<pid_file>\fR
 path to PID file in daemon mode (default \fIcloudprint.pid\fP).
 .TP
-\fB\-u\fR
-store username/password in addition to login token to avoid authentication expiration.
+\fB\-u\fR \fI<user name>\fR
+the Google service user name to use if authentication is needed.
 .TP
 \fB\-v\fR
 verbose logging.
@@ -55,9 +55,8 @@
 \fB\-h\fR
 display help
 .PP
-\fBPROG\fR will prompt for a username and password if the information has not been provided.
+\fBcloudprint\fR will prompt for a username and password if the information has not been provided.
 
-If two-factor authentication is enabled for the account, then an application-specific password must be used.
 
 .SH FILES
 .TP
@@ -68,4 +67,4 @@
 Default location for storing internal authentication tokens
 
 .SH SEE ALSO
-.BR cloudprint-service(7), cloudprintd(8), cloudprint(1)
+.BR cloudprint-service(7), cloudprintd(8), cloudprint(1), cps-auth(1)
diff -Nru cloudprint-0.11/debian/cloudprint-service.7 cloudprint-0.13/debian/cloudprint-service.7
--- cloudprint-0.11/debian/cloudprint-service.7	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/cloudprint-service.7	2015-09-27 10:39:41.000000000 -0400
@@ -1,38 +1,25 @@
-.\" (C) Copyright 2013-2014 David Steele <dsteele@gmail.com>,
+.\" (C) Copyright 2013-2015 David Steele <dsteele@gmail.com>,
 .\"
 .\" This file is part of cloudprint
 .\" Available under the terms of the GNU General Public License version 2 or later
-.TH CLOUDPRINT-SERVICE 7 2014-04-16 Linux "System Commands"
+.TH CLOUDPRINT-SERVICE 7 2015-05-31 Linux "System Commands"
 .SH NAME
 cloudprint-service \- manage the Google Cloud Print proxy
 
 .SH SYNOPSIS
 .TP
-service \fBcloudprintd\fR \fIlogin\fR
-Establish login credentials with Cloud Print, then immediately exit. This will
-prompt for a username and password, if necessary. If the account has two-factor
-authentication enabled, then an application-specific password must be used.
-This and all other \fBcloudprintd\fR service commands must be run as root.
-.TP
-service \fBcloudprintd\fR \fIstart\fR
+systemctl \fIstart\fR \fBcloudprintd.service\fR
 Start the \fBcloudprintd\fR service. This will fail if the credentials have not been
 established. The service will normally start automatically when the computer
 is running.
 .TP
-service \fBcloudprintd\fR \fIstop\fR
+systemctl \fIstop\fR \fBcloudprintd.service\fR
 Stop the \fBcloudprintd\fR service. Login credentials are not lost. Normally,
 the printer will continue to be shown as a valid destination. Any jobs spooled
 during that time will print when the service is restarted.
 .TP
-service \fBcloudprintd\fR \fIstatus\fR
+systemctl \fIstatus\fR \fBcloudprintd.service\fR
 Determine whether the service is running or not.
-.TP
-service \fBcloudprintd\fR \fIlogout\fR
-Delete the login credentials such that the service cannot be restarted without
-another 'login'.
-
-.P
-(...)
 
 .SH DESCRIPTION
 The \fBcloudprintd\fR services manages the operation of a Google Cloud Print
@@ -43,6 +30,8 @@
 can be shared from that account to others via the printer management page at
 \fIhttps://www.google.com/cloudprint?#printers\fR
 
+Authentication credentials can be established using the wrapper script
+\fBcps-auth\fR.
 .SH FILES
 .TP
 \fI/etc/default/cloudprintd\fR
@@ -50,4 +39,4 @@
 View the file for more details.
 
 .SH SEE ALSO
-.BR cloudprint(1), cloudprintd(8)
+.BR cloudprint(1), cloudprintd(8), cps-auth(1)
diff -Nru cloudprint-0.11/debian/cloudprint-service.cloudprintd.service cloudprint-0.13/debian/cloudprint-service.cloudprintd.service
--- cloudprint-0.11/debian/cloudprint-service.cloudprintd.service	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/cloudprint-service.cloudprintd.service	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,12 @@
+[Unit]
+Description=Google Cloud Print proxy service
+After=cups.service
+
+[Service]
+ExecStart=/usr/sbin/cloudprintd -a /var/lib/cloudprintd/authfile.json
+Type=simple
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
diff -Nru cloudprint-0.11/debian/cloudprint-service.install cloudprint-0.13/debian/cloudprint-service.install
--- cloudprint-0.11/debian/cloudprint-service.install	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/cloudprint-service.install	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1 @@
+debian/cps-auth usr/bin
diff -Nru cloudprint-0.11/debian/cloudprint-service.maintscript cloudprint-0.13/debian/cloudprint-service.maintscript
--- cloudprint-0.11/debian/cloudprint-service.maintscript	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/cloudprint-service.maintscript	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,2 @@
+rm_conffile /etc/init.d/cloudprintd 0.12-3~
+
diff -Nru cloudprint-0.11/debian/cloudprint-service.manpages cloudprint-0.13/debian/cloudprint-service.manpages
--- cloudprint-0.11/debian/cloudprint-service.manpages	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/cloudprint-service.manpages	2015-09-27 10:39:41.000000000 -0400
@@ -1,2 +1,3 @@
 debian/cloudprint-service.7
 debian/cloudprintd.8
+debian/cps-auth.1
diff -Nru cloudprint-0.11/debian/cloudprint-service.postinst cloudprint-0.13/debian/cloudprint-service.postinst
--- cloudprint-0.11/debian/cloudprint-service.postinst	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/cloudprint-service.postinst	2015-09-27 10:39:41.000000000 -0400
@@ -33,6 +33,11 @@
         rmdir /var/lib/cloudprint ; \
     fi
 
+    if [ -e /etc/init.d/cloudprintd/authfile.json \
+            -a -e /etc/init.d/cloudprintd/authfile ] ; then \
+        rm -f /etc/init.d/cloudprintd/authfile;
+    fi
+
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)
diff -Nru cloudprint-0.11/debian/control cloudprint-0.13/debian/control
--- cloudprint-0.11/debian/control	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/control	2015-09-27 10:39:41.000000000 -0400
@@ -2,8 +2,9 @@
 Maintainer: David Steele <dsteele@gmail.com>
 Section: net
 Priority: optional
-Build-Depends: python-setuptools (>= 0.6b3), python (>= 2.6.6-3), debhelper (>= 7.4.3)
-Standards-Version: 3.9.5
+Build-Depends: python-setuptools (>= 0.6b3), python (>= 2.6.6-3), debhelper (>= 7.4.3),
+                dh-systemd (>= 1.5), dh-python
+Standards-Version: 3.9.6
 X-Python-Version: >= 2.7
 Homepage: https://pypi.python.org/pypi/cloudprint/
 Vcs-Browser: https://github.com/davesteele/cloudprint-service
@@ -11,8 +12,9 @@
 
 Package: cloudprint
 Architecture: all
-Depends: python-cups, cups, python-daemon, ${misc:Depends}, ${python:Depends},
- python-pkg-resources, rsyslog | system-log-daemon
+Depends: python-cups, cups, python-daemon, ${misc:Depends},
+ python (>= 2.7), python-pkg-resources, rsyslog | system-log-daemon,
+ python-requests
 Description: Google Cloud Print proxy
  Worker script to support a Google Cloud Print proxy. This can make
  locally-configured printers to be accessed by local or remote users over
@@ -21,8 +23,7 @@
 Package: cloudprint-service
 Architecture: all
 Provides: cloudprintd
-Depends: cloudprint, ${misc:Depends},
- initscripts (>= 2.88dsf-13.3)
+Depends: cloudprint, ${misc:Depends}, systemd
 Description: provide a service for sharing printers on Google Cloud Print
  Share locally-defined CUPS printers with the Google Cloud Print service.
  The printers can be accessed locally or remotely by authorized users via
diff -Nru cloudprint-0.11/debian/cps-auth cloudprint-0.13/debian/cps-auth
--- cloudprint-0.11/debian/cps-auth	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/cps-auth	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+AUTHDIR=/var/lib/cloudprintd
+AUTHFILE=$AUTHDIR/authfile.json
+
+if [ ! -w $AUTHDIR ] ; then echo "Must run as root" ; exit 1 ; fi
+
+rm -f $AUTHFILE
+cloudprint -c -a $AUTHFILE
diff -Nru cloudprint-0.11/debian/cps-auth.1 cloudprint-0.13/debian/cps-auth.1
--- cloudprint-0.11/debian/cps-auth.1	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/cps-auth.1	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,27 @@
+.\" Copyright 2015 David Steele <dsteele@gmail.com>
+.\" This file is part of cloudprint
+.\" Available under the terms of the GNU General Public License version 2 or later
+.TH cps-auth 1 2015-05-31 Linux "User Commands"
+.SH NAME
+cps-auth \- Perform OAuth2 authentication for cloudprint-service
+
+.SH SYNOPSIS
+\fBcps-auth\fR [\fI<user name>\fR]
+
+.SH DESCRIPTION
+The \fBcps-auth\fR provide a wrapper for entering the required OAuth2
+credentials for \fBcloudprint-service\fR. It will prompt the user with a URL
+for claiming the printer, and wait for the process to complete. The
+credentials are stored for \fBcloudprint-service\fR.
+
+The command must be run as root.
+
+.SH FILES
+.TP
+\fI/var/lib/cloudprint/authfile.json\fR
+Credential storage location
+
+.SH SEE ALSO
+.BR cloudprint-service(7), cloudprintd(8), cloudprint(1),
+cps-auth(1)
+
diff -Nru cloudprint-0.11/debian/gbp.conf cloudprint-0.13/debian/gbp.conf
--- cloudprint-0.11/debian/gbp.conf	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/gbp.conf	2015-09-27 10:39:41.000000000 -0400
@@ -6,5 +6,6 @@
 [git-import-orig]
 dch = False
 
-[git-buildpackage]
+[buildpackage]
 prebuild = rm README.md
+postbuild = git checkout README.md cloudprint/__init__.py
diff -Nru cloudprint-0.11/debian/patches/0001-Change-the-name-of-the-main-script-in-the-module.patch cloudprint-0.13/debian/patches/0001-Change-the-name-of-the-main-script-in-the-module.patch
--- cloudprint-0.11/debian/patches/0001-Change-the-name-of-the-main-script-in-the-module.patch	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/patches/0001-Change-the-name-of-the-main-script-in-the-module.patch	2015-09-27 10:39:41.000000000 -0400
@@ -11,15 +11,15 @@
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/setup.py b/setup.py
-index ce5f16d..d064d57 100644
+index b8dcb10..3403caf 100644
 --- a/setup.py
 +++ b/setup.py
-@@ -27,7 +27,7 @@ setup(
+@@ -25,7 +25,7 @@ setup(
      packages=find_packages(exclude=['ez_setup']),
-     entry_points = {
+     entry_points={
          'console_scripts': [
 -            'cloudprint = cloudprint.cloudprint:main',
 +            'cloudprint-cmd = cloudprint.cloudprint:main',
          ],
      },
- )
+     install_requires=[
diff -Nru cloudprint-0.11/debian/patches/0002-Set-Python-path-to-load-the-right-daemon.patch cloudprint-0.13/debian/patches/0002-Set-Python-path-to-load-the-right-daemon.patch
--- cloudprint-0.11/debian/patches/0002-Set-Python-path-to-load-the-right-daemon.patch	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/patches/0002-Set-Python-path-to-load-the-right-daemon.patch	2015-09-27 10:39:41.000000000 -0400
@@ -1,28 +1,25 @@
-From: David Steele <dsteele@gmail.com>
-Date: Mon, 14 Apr 2014 21:21:45 -0400
+From: David Steele <daves@jessie>
+Date: Fri, 25 Sep 2015 22:41:02 -0400
 Subject: Set Python path to load the right daemon
 
-Some users are having a problem with the wrong daemon module
-being loaded. Modify the Python path to ensure that
-python-daemon is the one found.
-
-This uses Debian conventions, and is therefore Debian-only.
+Some users were reporting problems with loading the wrong daemon module.
+Modify the python path to ensure that python-daemon is the one found.
 ---
  cloudprint/cloudprint.py | 4 ++++
  1 file changed, 4 insertions(+)
 
 diff --git a/cloudprint/cloudprint.py b/cloudprint/cloudprint.py
-index f09a354..cdbf27f 100755
+index 2df3d58..f4a5d2d 100755
 --- a/cloudprint/cloudprint.py
 +++ b/cloudprint/cloudprint.py
-@@ -484,6 +484,10 @@ def main():
+@@ -483,6 +483,10 @@ def main():
  
-     if daemon:
+     if args.daemon:
          try:
 +            # workaround to avoid overloaded module
 +            prepath = '/usr/lib/pymodules/python%s.%s' % sys.version_info[0:2]
 +            sys.path.insert(0, prepath)
 +
-             from daemon import runner
+             import daemon
+             import daemon.pidfile
          except ImportError:
-             print 'daemon module required for -d'
diff -Nru cloudprint-0.11/debian/patches/0003-Specify-dev-log-as-the-logging-target-for-daemon.patch cloudprint-0.13/debian/patches/0003-Specify-dev-log-as-the-logging-target-for-daemon.patch
--- cloudprint-0.11/debian/patches/0003-Specify-dev-log-as-the-logging-target-for-daemon.patch	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/patches/0003-Specify-dev-log-as-the-logging-target-for-daemon.patch	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,22 @@
+From: David Steele <dsteele@gmail.com>
+Date: Thu, 9 Jul 2015 22:05:44 -0400
+Subject: Specify /dev/log as the logging target for daemon
+
+Debian disables the default UDP port, by default.
+---
+ cloudprint/cloudprint.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/cloudprint/cloudprint.py b/cloudprint/cloudprint.py
+index f4a5d2d..295da5f 100755
+--- a/cloudprint/cloudprint.py
++++ b/cloudprint/cloudprint.py
+@@ -432,7 +432,7 @@ def main():
+ 
+     # if daemon, log to syslog, otherwise log to stdout
+     if args.daemon:
+-        handler = logging.handlers.SysLogHandler()
++        handler = logging.handlers.SysLogHandler(address='/dev/log')
+         handler.setFormatter(logging.Formatter(fmt='cloudprint.py: %(message)s'))
+     else:
+         handler = logging.StreamHandler(sys.stdout)
diff -Nru cloudprint-0.11/debian/patches/0004-Allow-older-python-requests.patch cloudprint-0.13/debian/patches/0004-Allow-older-python-requests.patch
--- cloudprint-0.11/debian/patches/0004-Allow-older-python-requests.patch	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/patches/0004-Allow-older-python-requests.patch	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,25 @@
+From: David Steele <dsteele@gmail.com>
+Date: Fri, 25 Sep 2015 22:37:06 -0400
+Subject: Allow-older-python-requests
+
+Remove the version requirement on python-requests in setup.py. The tight
+requirement caused deb-packaged versions to fail on older distributions.
+
+===================================================================
+---
+ setup.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/setup.py b/setup.py
+index 3403caf..5c754e4 100644
+--- a/setup.py
++++ b/setup.py
+@@ -29,7 +29,7 @@ setup(
+         ],
+     },
+     install_requires=[
+-        'requests >= 2.7.0',
++        'requests',
+         'pycups',
+     ],
+     extras_require={
diff -Nru cloudprint-0.11/debian/patches/0005-Revert-Update-for-new-python-deamon.patch cloudprint-0.13/debian/patches/0005-Revert-Update-for-new-python-deamon.patch
--- cloudprint-0.11/debian/patches/0005-Revert-Update-for-new-python-deamon.patch	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/patches/0005-Revert-Update-for-new-python-deamon.patch	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,70 @@
+From: David Steele <daves@jessie>
+Date: Fri, 25 Sep 2015 22:43:14 -0400
+Subject: Revert "Update for new python-deamon"
+
+Use the old python-daemon on Jessit.
+
+This reverts commit 88acead3d1daf1fd63ca32bb3eddf57ab392fea5.
+
+Conflicts:
+	cloudprint/cloudprint.py
+---
+ cloudprint/cloudprint.py | 32 ++++++++++++++++++++++++--------
+ 1 file changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/cloudprint/cloudprint.py b/cloudprint/cloudprint.py
+index 295da5f..7bb6969 100755
+--- a/cloudprint/cloudprint.py
++++ b/cloudprint/cloudprint.py
+@@ -305,6 +305,21 @@ class PrinterProxy(object):
+         return self.cpp.delete_printer(self.id)
+ 
+ 
++class App(object):
++    def __init__(self, cups_connection=None, cpp=None, printers=None, pidfile_path=None):
++        self.cups_connection = cups_connection
++        self.cpp = cpp
++        self.printers = printers
++        self.pidfile_path = pidfile_path
++        self.stdin_path = '/dev/null'
++        self.stdout_path = '/dev/null'
++        self.stderr_path = '/dev/null'
++        self.pidfile_timeout = 5
++
++    def run(self):
++        process_jobs(self.cups_connection, self.cpp)
++
++
+ #True if printer name matches *any* of the regular expressions in regexps
+ def match_re(prn, regexps, empty=False):
+     if len(regexps):
+@@ -487,20 +502,21 @@ def main():
+             prepath = '/usr/lib/pymodules/python%s.%s' % sys.version_info[0:2]
+             sys.path.insert(0, prepath)
+ 
+-            import daemon
+-            import daemon.pidfile
++            from daemon import runner
+         except ImportError:
+             print 'daemon module required for -d'
+             print '\tyum install python-daemon, or apt-get install python-daemon, or pip install cloudprint[daemon]'
+             sys.exit(1)
+ 
+-        pidfile = daemon.pidfile.TimeoutPIDLockFile(
+-            path=os.path.abspath(args.pidfile),
+-            timeout=5,
++        # XXX printers is the google list
++        app = App(
++            cups_connection=cups_connection,
++            cpp=cpp,
++            pidfile_path=os.path.abspath(args.pidfile)
+         )
+-        with daemon.DaemonContext(pidfile=pidfile):
+-            process_jobs(cups_connection, cpp)
+-
++        sys.argv = [sys.argv[0], 'start']
++        daemon_runner = runner.DaemonRunner(app)
++        daemon_runner.do_action()
+     else:
+         process_jobs(cups_connection, cpp)
+ 
diff -Nru cloudprint-0.11/debian/patches/series cloudprint-0.13/debian/patches/series
--- cloudprint-0.11/debian/patches/series	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/patches/series	2015-09-27 10:39:41.000000000 -0400
@@ -1,18 +1,5 @@
 0001-Change-the-name-of-the-main-script-in-the-module.patch
 0002-Set-Python-path-to-load-the-right-daemon.patch
-0003-Disable-exception-processing-in-XMPP-close.patch
-0004-First-functional-include-exclude.patch
-0005-Code-cleanup-documentation.patch
-0006-Documentation-and-minor-code-cleanup.patch
-0007-Remove-debug-code.patch
-0008-Use-x-from-exclude.patch
-0009-Remove-whitespace-response-to-comment-from-armooo.patch
-0010-Catch-exception-for-invalid-regular-expressions.patch
-0011-cloudprint.py-Log-when-get_rest-changes-token.patch
-0012-Remove-alternate-username-pw-auth-file-format.patch
-0013-Add-u-option-to-store-username-password-with-sasl.patch
-0014-Refresh-XMPP-authentication-in-process_jobs.patch
-0015-Switch-from-getopt-to-argparse.patch
-0016-Use-argparse-args.patch
-0017-Fix-broken-reference-to-authfile.patch
-0018-Add-copywrite-headers-to-source-files.patch
+0003-Specify-dev-log-as-the-logging-target-for-daemon.patch
+0004-Allow-older-python-requests.patch
+0005-Revert-Update-for-new-python-deamon.patch
diff -Nru cloudprint-0.11/debian/rules cloudprint-0.13/debian/rules
--- cloudprint-0.11/debian/rules	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/rules	2015-09-27 10:39:41.000000000 -0400
@@ -4,7 +4,7 @@
 # Tue, 23 Apr 2013 19:42:12 -0400
 
 %:
-	dh $@ --with python2
+	dh $@ --with python2,systemd
 
 override_dh_auto_install:
 	python setup.py install --root=debian/cloudprint --install-layout=deb --install-lib=/usr/share/cloudprint --install-scripts=/usr/share/cloudprint
@@ -15,7 +15,7 @@
 	/bin/sed 's/cloudprintd 1/cloudprintd 8/' debian/cloudprintd.8 >debian/cloudprintd.8.tmp
 	/bin/mv debian/cloudprintd.8.tmp debian/cloudprintd.8
 
+override_dh_systemd_enable:
+	dh_systemd_enable --name=cloudprintd
 
-override_dh_installinit:
-	dh_installinit --name=cloudprintd
 
diff -Nru cloudprint-0.11/debian/TODO cloudprint-0.13/debian/TODO
--- cloudprint-0.11/debian/TODO	1969-12-31 19:00:00.000000000 -0500
+++ cloudprint-0.13/debian/TODO	2015-09-27 10:39:41.000000000 -0400
@@ -0,0 +1,4 @@
+
+- restore INCLUDE/EXCLUDE with a systemd wrapper script
+- replace GNOME requirement with X, by using webbrowser and xwininfo
+- merge with armoo OAUth2
diff -Nru cloudprint-0.11/debian/watch cloudprint-0.13/debian/watch
--- cloudprint-0.11/debian/watch	2015-09-27 10:54:15.000000000 -0400
+++ cloudprint-0.13/debian/watch	2015-09-27 10:39:41.000000000 -0400
@@ -1,2 +1,2 @@
 version=3
-https://pypi.python.org/packages/source/c/cloudprint/ cloudprint-(.+)\.tar\.gz
+http://pypi.debian.net/cloudprint/ .+cloudprint-(.+)\.tar\.gz
diff -Nru cloudprint-0.11/PKG-INFO cloudprint-0.13/PKG-INFO
--- cloudprint-0.11/PKG-INFO	2014-01-05 19:53:29.000000000 -0500
+++ cloudprint-0.13/PKG-INFO	2015-07-08 23:17:23.000000000 -0400
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cloudprint
-Version: 0.11
+Version: 0.13
 Summary: Google cloud print proxy for linux/OSX
 Home-page: https://github.com/armooo/cloudprint
 Author: Jason Michalski
@@ -9,10 +9,14 @@
 Description: Share your CUPS printers with google's cloud print.
         Works with linux and OS X.
         
+        This software is a python implementation of a cloud print connector. Unlike
+        Google's linux connector, it does not require chrome to be installed on the server.
+        
+        
         Requires
         ---------------------------------------------------
-        python 2.6 or 2.7
-        pycups (can be tricky on OS X)
+        - python 2.6 or 2.7
+        - pycups (can be tricky on OS X) wich depends on libcups2-dev
         
         Usage
         ---------------------------------------------------
@@ -24,10 +28,14 @@
           -l              : logout of the current google account
           -p pid_file     : path to write the pid to (default cloudprint.pid)
           -a account_file : path to google account ident data (optional)
-                            account_file format:  <Google username>
-                                                  <Google password>
           -c              : establish and store login credentials, then exit
           -f              : 'fast poll', if notifications aren't working
+          -u              : store username/password in addition to login token
+                            to avoid authentication expiration
+          -i regexp       : include files matching regexp
+          -x regexp       : exclude filees matching regexp
+                            regexp: a Python regexp, which is matched against the
+                                    start of the printer name
           -h              : display this help
         
         Google accounts with 2 step verification enabled need to use an
@@ -43,12 +51,40 @@
           Password:
           Added Printer Brother-HL-2170W
         
+        Examples - Include/Exclude
+        ---------------------------------------------------
+        
+        Include only the printers "`lp`" and "`2up`":
+        ::
+        
+          cloudprint -i lp -i 2up
+        
+        Exclude all printers whose names start with "`GCP-`":
+        ::
+        
+          cloudprint -x GCP-
+        
+        By default, all printers are included.  For the include and exclude options,
+        the argument is a regular expression which is matched against the start of the
+        printer name.
+        
+        For example, to include all printers whose names begin "`lp`":
+        ::
+        
+          cloudprint -i lp # includes both lp and lp2up
+        
+        
         Install
         ---------------------------------------------------
         
         ::
         
           pip install cloudprint
+          or with optional daemon support
+          pip install cloudprint[daemon]
+        
+        After running cloudprint, verify that the connector successfully installed the cloud printer by visiting
+        http://www.google.com/cloudprint/manage.html.
         
 Platform: UNKNOWN
 Classifier: Development Status :: 4 - Beta
diff -Nru cloudprint-0.11/README.rst cloudprint-0.13/README.rst
--- cloudprint-0.11/README.rst	2014-01-05 19:29:25.000000000 -0500
+++ cloudprint-0.13/README.rst	2015-07-08 23:11:07.000000000 -0400
@@ -1,10 +1,14 @@
 Share your CUPS printers with google's cloud print.
 Works with linux and OS X.
 
+This software is a python implementation of a cloud print connector. Unlike
+Google's linux connector, it does not require chrome to be installed on the server.
+
+
 Requires
 ---------------------------------------------------
-python 2.6 or 2.7
-pycups (can be tricky on OS X)
+- python 2.6 or 2.7
+- pycups (can be tricky on OS X) wich depends on libcups2-dev
 
 Usage
 ---------------------------------------------------
@@ -16,10 +20,14 @@
   -l              : logout of the current google account
   -p pid_file     : path to write the pid to (default cloudprint.pid)
   -a account_file : path to google account ident data (optional)
-                    account_file format:  <Google username>
-                                          <Google password>
   -c              : establish and store login credentials, then exit
   -f              : 'fast poll', if notifications aren't working
+  -u              : store username/password in addition to login token
+                    to avoid authentication expiration
+  -i regexp       : include files matching regexp
+  -x regexp       : exclude filees matching regexp
+                    regexp: a Python regexp, which is matched against the
+                            start of the printer name
   -h              : display this help
 
 Google accounts with 2 step verification enabled need to use an
@@ -35,9 +43,37 @@
   Password:
   Added Printer Brother-HL-2170W
 
+Examples - Include/Exclude
+---------------------------------------------------
+
+Include only the printers "`lp`" and "`2up`":
+::
+
+  cloudprint -i lp -i 2up
+
+Exclude all printers whose names start with "`GCP-`":
+::
+
+  cloudprint -x GCP-
+
+By default, all printers are included.  For the include and exclude options,
+the argument is a regular expression which is matched against the start of the
+printer name.
+
+For example, to include all printers whose names begin "`lp`":
+::
+
+  cloudprint -i lp # includes both lp and lp2up
+
+
 Install
 ---------------------------------------------------
 
 ::
 
   pip install cloudprint
+  or with optional daemon support
+  pip install cloudprint[daemon]
+
+After running cloudprint, verify that the connector successfully installed the cloud printer by visiting
+http://www.google.com/cloudprint/manage.html.
diff -Nru cloudprint-0.11/setup.py cloudprint-0.13/setup.py
--- cloudprint-0.11/setup.py	2014-01-05 19:30:14.000000000 -0500
+++ cloudprint-0.13/setup.py	2015-07-08 23:16:45.000000000 -0400
@@ -5,17 +5,15 @@
     use_setuptools()
     from setuptools import setup, find_packages
 
-import os.path
-
 setup(
     name='cloudprint',
-    version='0.11',
+    version='0.13',
     description='Google cloud print proxy for linux/OSX',
     long_description=open('README.rst').read(),
     author='Jason Michalski',
     author_email='armooo@armooo.net',
     url='https://github.com/armooo/cloudprint',
-    classifiers = [
+    classifiers=[
         'Development Status :: 4 - Beta',
         'Environment :: Console',
         'Intended Audience :: End Users/Desktop',
@@ -25,9 +23,16 @@
         'License :: OSI Approved :: GNU General Public License (GPL)',
     ],
     packages=find_packages(exclude=['ez_setup']),
-    entry_points = {
+    entry_points={
         'console_scripts': [
             'cloudprint = cloudprint.cloudprint:main',
         ],
     },
+    install_requires=[
+        'requests >= 2.7.0',
+        'pycups',
+    ],
+    extras_require={
+        'daemon': ['python-daemon >= 2.0.0'],
+    },
 )

Reply to: