From 5690307c63e2af59c2cc605c16dcd9425cef8e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Sun, 20 Nov 2022 19:58:12 +0100 Subject: [PATCH] Update Gmail access with OAuth 2 --- examples/gmail.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++ examples/mail.py | 30 +++++++------------ 2 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 examples/gmail.py diff --git a/examples/gmail.py b/examples/gmail.py new file mode 100644 index 0000000..6262ef8 --- /dev/null +++ b/examples/gmail.py @@ -0,0 +1,76 @@ +# +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Setup : https://developers.google.com/gmail/api/quickstart/python +# Need to have credentials.json were you call main script +# +# File imported from https://github.com/googleworkspace/python-samples/blob/main/gmail/quickstart/quickstart.py +# + +from __future__ import print_function + +import os.path + +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build + +# If modifying these scopes, delete the file token.json. +SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] + +creds = None + +def _initCreds(): + global creds + if creds: return + + # The file token.json stores the user's access and refresh tokens, and is + # created automatically when the authorization flow completes for the first + # time. + if os.path.exists('token.json'): + creds = Credentials.from_authorized_user_file('./token.json', SCOPES) + # If there are no (valid) credentials available, let the user log in. + if not creds or not creds.valid: + if creds and creds.expired and creds.refresh_token: + creds.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file( + 'credentials.json', SCOPES) + creds = flow.run_local_server(port=0) + # Save the credentials for the next run + with open('token.json', 'w') as token: + token.write(creds.to_json()) + +def getUnreadMails(): + """Shows basic usage of the Gmail API. + Lists the user's Gmail labels. + """ + + _initCreds() + + service = build('gmail', 'v1', credentials=creds) + nbUnreadMessages = 0 + pageToken = '' + while True: + results = service.users().messages().list(userId='me', labelIds=['UNREAD'],\ + includeSpamTrash=False, pageToken=pageToken)\ + .execute() + nbUnreadMessages += len(results.get('messages', [])) + pageToken = results.get('nextPageToken', '') + if not pageToken: break + + return nbUnreadMessages diff --git a/examples/mail.py b/examples/mail.py index 885ceb0..03bf447 100755 --- a/examples/mail.py +++ b/examples/mail.py @@ -23,11 +23,11 @@ import time import requests from requests.auth import HTTPBasicAuth import xml.dom.minidom -import getpass from threading import Thread from signal import signal, SIGINT import sys from genericmonitor import * +from gmail import getUnreadMails PURPLE_CONV_UPDATE_UNSEEN = 4 PURPLE_MESSAGE_SEND = 0 @@ -59,31 +59,23 @@ class PidginConversation: class EventThread(Thread,GenericMonitor): SLEEP_TIME = 30 - MAIL_ADDRESS='XXX@gmail.com' def stop(self): self._stopLoop = True self.stopMainLoop() def _getMail(self): - address = "https://mail.google.com/mail/feed/atom" - auth = HTTPBasicAuth(self.MAIL_ADDRESS, self._mail_password) - req = requests.get(address, auth=auth) text = '' style = '' - if req.status_code == requests.codes.ok: - dom = xml.dom.minidom.parseString(req.text) - try: - nb_messages = int(dom.getElementsByTagName('fullcount')[0].firstChild.nodeValue) - if nb_messages == 1: - text = '1 msg' - elif nb_messages > 1: - text = '%d msgs' % (nb_messages) - style = 'color:white' - except Exception as e: - text = str(e) - else: - text = 'Mail error %d' % (req.status_code) + try: + nb_messages = getUnreadMails() + if nb_messages == 1: + text = '1 msg' + elif nb_messages > 1: + text = '%d msgs' % (nb_messages) + style = 'color:white' + except Exception as e: + text = str(e) self.mailWidget.setText(text) self.mailWidget.setStyle(style) @@ -103,8 +95,6 @@ class EventThread(Thread,GenericMonitor): self.add_signal_receiver(self.pidginMessageWrote, 'WroteChatMsg', 'im.pidgin.purple.PurpleInterface') self.add_signal_receiver(self.pidginConversationUpdated, 'ConversationUpdated', 'im.pidgin.purple.PurpleInterface') - self._mail_password = getpass.getpass('Enter password for address %s: ' % (self.MAIL_ADDRESS)) - self.mailWidget = GenericMonitorTextWidget('') mailItem = GenericMonitorItem('mail', [self.mailWidget]) self.mailGroup = GenericMonitorGroup('Mail', [mailItem])