184 lines
6.4 KiB
Python
Executable File
184 lines
6.4 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
#
|
|
# This program 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.
|
|
#
|
|
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
'''
|
|
Display number of mail from gmail account and Pidgin icon if there is some unread Pidgin message
|
|
'''
|
|
|
|
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 GenericMonitor, GenericMonitorGroup, GenericMonitorItem
|
|
|
|
PURPLE_CONV_UPDATE_UNSEEN = 4
|
|
PURPLE_MESSAGE_SEND = 0
|
|
|
|
class PidginConversation:
|
|
STATUS_SEEN = 0
|
|
STATUS_UNSEEN = 1
|
|
|
|
def __init__(self, _id):
|
|
self._id = _id
|
|
self.status = PidginConversation.STATUS_SEEN
|
|
self.nbMessages = 1
|
|
|
|
def updateNbMessages(self):
|
|
self.nbMessages += 1
|
|
# Status is seen until it changes
|
|
self.status = PidginConversation.STATUS_SEEN
|
|
|
|
def setSeen(self):
|
|
self.status = PidginConversation.STATUS_SEEN
|
|
|
|
def setUnseen(self):
|
|
self.nbMessages = 0
|
|
self.status = PidginConversation.STATUS_UNSEEN
|
|
|
|
def isSeen(self):
|
|
return (self.status == PidginConversation.STATUS_SEEN)
|
|
|
|
|
|
class EventThread(Thread,GenericMonitor):
|
|
SLEEP_TIME = 30
|
|
MAIL_ADDRESS='XXX@gmail.com'
|
|
|
|
def stop(self):
|
|
self._stopLoop = True
|
|
self.stopMainLoop()
|
|
|
|
def _getMail(self):
|
|
mailItem = GenericMonitorItem('mail')
|
|
mailGroup = GenericMonitorGroup('Mail', [mailItem])
|
|
|
|
address = "https://mail.google.com/mail/feed/atom"
|
|
auth = HTTPBasicAuth(self.MAIL_ADDRESS, self._mail_password)
|
|
req = requests.get(address, auth=auth)
|
|
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:
|
|
mailItem.text = '1 msg'
|
|
elif nb_messages > 1:
|
|
mailItem.text = '%d msgs' % (nb_messages)
|
|
mailItem.style = 'color:white'
|
|
except Exception as e:
|
|
mailItem.text = str(e)
|
|
else:
|
|
mailItem.text = 'Mail error %d' % (req.status_code)
|
|
|
|
self.notify(mailGroup)
|
|
|
|
def getEvents(self):
|
|
self._getMail()
|
|
|
|
def run(self):
|
|
self._stopLoop = False
|
|
self.setupMonitor()
|
|
self.pidgin_conversations = {}
|
|
|
|
self.add_signal_receiver(self.pidginMessageReceived, 'ReceivedImMsg', 'im.pidgin.purple.PurpleInterface')
|
|
self.add_signal_receiver(self.pidginMessageReceived, 'ReceivedChatMsg', 'im.pidgin.purple.PurpleInterface')
|
|
self.add_signal_receiver(self.pidginMessageWrote, 'WroteImMsg', 'im.pidgin.purple.PurpleInterface')
|
|
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))
|
|
|
|
while not self._stopLoop:
|
|
self.getEvents()
|
|
# Be more reactive on signal capture
|
|
for i in range(0, self.SLEEP_TIME):
|
|
if self._stopLoop: break
|
|
time.sleep(1)
|
|
|
|
def pidginMessageReceived(self, account, sender, message, conversation, flags):
|
|
pidginConversation = self.pidgin_conversations.get(conversation, None)
|
|
if not pidginConversation:
|
|
self.pidgin_conversations[conversation] = PidginConversation(conversation)
|
|
else:
|
|
pidginConversation.updateNbMessages()
|
|
|
|
def pidginMessageWrote(self, account, sender, message, conversation, flags):
|
|
if not (flags & (1 << PURPLE_MESSAGE_SEND)):
|
|
return
|
|
pidginConversation = self.pidgin_conversations.get(conversation, None)
|
|
if not pidginConversation:
|
|
self.pidgin_conversations[conversation] = PidginConversation(conversation)
|
|
pidginConversation = self.pidgin_conversations[conversation]
|
|
pidginConversation.setSeen()
|
|
pidginConversation.nbMessages = 1
|
|
|
|
def displayIcon(self):
|
|
pidginItem = GenericMonitorItem('pidgin', icon='/usr/share/icons/hicolor/22x22/apps/pidgin.png', iconStyle='icon-size:22px')
|
|
pidginGroup = GenericMonitorGroup('Pidgin', pidginItem)
|
|
self.notify(pidginGroup)
|
|
|
|
def pidginConversationUpdated(self, conversation, _type):
|
|
if _type != PURPLE_CONV_UPDATE_UNSEEN:
|
|
return
|
|
|
|
pidginConversation = self.pidgin_conversations.get(conversation, None)
|
|
if not pidginConversation:
|
|
return
|
|
|
|
if pidginConversation.isSeen():
|
|
if pidginConversation.nbMessages > 0:
|
|
pidginConversation.setUnseen()
|
|
else:
|
|
pidginConversation.setSeen()
|
|
|
|
# Message not seen by user
|
|
if not pidginConversation.isSeen():
|
|
self.displayIcon()
|
|
else:
|
|
deleteIcon = True
|
|
# Are all messages seen ?
|
|
for pConv in self.pidgin_conversations.values():
|
|
if not pConv.isSeen():
|
|
deleteIcon = False
|
|
break
|
|
if deleteIcon:
|
|
items = {'items':['pidgin@Pidgin']}
|
|
self.deleteItems(items)
|
|
|
|
def onActivate(self):
|
|
super().onActivate()
|
|
for pConv in self.pidgin_conversations.values():
|
|
if not pConv.isSeen():
|
|
self.displayIcon()
|
|
break
|
|
|
|
def signalHandler(signal_received, frame):
|
|
eventThread.stop()
|
|
eventThread.join()
|
|
groups = {'groups':['Mail', 'Pidgin']}
|
|
eventThread.deleteGroups(groups)
|
|
sys.exit(0)
|
|
|
|
eventThread = EventThread()
|
|
eventThread.start()
|
|
|
|
signal(SIGINT, signalHandler)
|
|
|
|
eventThread.runMainLoop()
|