From 7b59d6b3aedbba052a141abca55e6997c9b22ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Thu, 17 Nov 2016 11:45:24 +0100 Subject: [PATCH] GMail: Add ability to set a custom host/port/ssl etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GMail repository added in 81b86fb has the restriction that you can't override the host/port/ssl etc. There's no good reason for this, and I'd like to use some of the defaults while connecting to GMail via an stunnel, i.e.: $ grep -v -e ^# -e ^$ .stunnel.work-gmail-imap foreground = yes debug = info pid = [work-imap-gmail-ssl-tunnel] client = yes accept = 127.0.0.1:1431 connect = imap.gmail.com:993 delay = yes And then in my .offlineimaprc: type = Gmail remotehost = localhost remoteport = 1431 ssl = no While I was at it I also allowed overriding all the other previously hardcoded options, e.g. the "oauth2_request_url" can now be overridden to e.g. a local non-https proxy to sniff & debug the traffic going over the wire. This doesn't break any existing configuration, since we still use the provided defaults. It just allows odd uses like my own to use this repository while e.g. not having to supply "trashfolder", "spamfolder" & "oauth2_request_url". While I'm at it document in the offlineimap.conf that we're setting those options to defaults in this repository. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Nicolas Sebrecht --- offlineimap.conf | 12 +++++-- offlineimap/repository/Gmail.py | 64 ++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/offlineimap.conf b/offlineimap.conf index dbd2d1c..b1b36c9 100644 --- a/offlineimap.conf +++ b/offlineimap.conf @@ -1242,12 +1242,18 @@ remoteuser = username # Only "remoteuser" (or "remoteusereval" ) is mandatory. Default values for # other parameters are OK, and you should not need fiddle with those. # -# The Gmail repository will use hard-coded values for "remotehost", -# "remoteport", "tunnel" and "ssl". Any attempt to set those parameters will be -# silently ignored. For details, see +# The Gmail repository provides default values for "remotehost", +# "remoteport", "tunnel" and "ssl". For the defaults we use, see: # # http://mail.google.com/support/bin/answer.py?answer=78799&topic=12814 # +# In addition we provide defaults for "oauth2_request_url", +# "trashfolder" and "spamfolder". +# +# All of the defaults we provide can be overriden. E.g. you can +# override "remotehost"/"remoteport"/"ssl" if you'd like to connect to +# imap.gmail.com via a local stunnel instead of directly. +# # To enable GMail labels synchronisation, set the option "synclabels" in the # corresponding "Account" section. # diff --git a/offlineimap/repository/Gmail.py b/offlineimap/repository/Gmail.py index c7a0984..13dac2a 100644 --- a/offlineimap/repository/Gmail.py +++ b/offlineimap/repository/Gmail.py @@ -21,55 +21,68 @@ from offlineimap import folder, OfflineImapError class GmailRepository(IMAPRepository): """Gmail IMAP repository. - Falls back to hard-coded gmail host name and port, if none were specified: + This class just has default settings for GMail's IMAP service. So + you can do 'type = Gmail' instead of 'type = IMAP' and skip + specifying the hostname, port etc. See http://mail.google.com/support/bin/answer.py?answer=78799&topic=12814 - """ - # Gmail IMAP server hostname - HOSTNAME = "imap.gmail.com" - # Gmail IMAP server port - PORT = 993 - - OAUTH2_URL = 'https://accounts.google.com/o/oauth2/token' + for the values we use.""" def __init__(self, reposname, account): """Initialize a GmailRepository object.""" - # Enforce SSL usage - account.getconfig().set('Repository ' + reposname, - 'ssl', 'yes') IMAPRepository.__init__(self, reposname, account) - def gethost(self): """Return the server name to connect to. - Gmail implementation first checks for the usual IMAP settings - and falls back to imap.gmail.com if not specified.""" + We first check the usual IMAP settings, and then fall back to + imap.gmail.com if nothing is specified.""" try: return super(GmailRepository, self).gethost() except OfflineImapError: - # Nothing was configured, cache and return hardcoded one. - self._host = GmailRepository.HOSTNAME + # Nothing was configured, cache and return hardcoded + # one. See the parent class (IMAPRepository) for how this + # cache is used. + self._host = "imap.gmail.com" return self._host def getoauth2_request_url(self): - """Return the server name to connect to. + """Return the OAuth URL to request tokens from. - Gmail implementation first checks for the usual IMAP settings - and falls back to imap.gmail.com if not specified.""" + We first check the usual OAuth settings, and then fall back to + https://accounts.google.com/o/oauth2/token if nothing is + specified.""" url = super(GmailRepository, self).getoauth2_request_url() if url is None: # Nothing was configured, cache and return hardcoded one. - self.setoauth2_request_url(GmailRepository.OAUTH2_URL) + self.setoauth2_request_url("https://accounts.google.com/o/oauth2/token") else: self.setoauth2_request_url(url) return self.oauth2_request_url def getport(self): - return GmailRepository.PORT + """Return the port number to connect to. + + This Gmail implementation first checks for the usual IMAP settings + and falls back to 993 if nothing is specified.""" + + port = super(GmailRepository, self).getport() + + if port is None: + return 993 + else: + return port def getssl(self): - return 1 + ssl = self.getconfboolean('ssl', None) + + if ssl is None: + # Nothing was configured, return our default setting for + # GMail. Maybe this should look more similar to gethost & + # we could just rely on the global "ssl = yes" default. + return True + else: + return ssl def getpreauthtunnel(self): return None @@ -86,5 +99,8 @@ class GmailRepository(IMAPRepository): return self.getconf('trashfolder', '[Gmail]/Trash') def getspamfolder(self): - #: Gmail also deletes messages upon EXPUNGE in the Spam folder - return self.getconf('spamfolder','[Gmail]/Spam') + # Depending on the IMAP settings (Settings -> Forwarding and + # POP/IMAP -> IMAP Access -> "When I mark a message in IMAP as + # deleted") GMail might also deletes messages upon EXPUNGE in + # the Spam folder. + return self.getconf('spamfolder', '[Gmail]/Spam')