You are not logged in.

#1 2011-09-25 19:14:45

jbiggs12
Member
From: USA
Registered: 2011-08-07
Posts: 14
Website

Conky Push Notifications

I was wondering if it would be possible if push notifications would be possible for conky and gmail. I realize that it wouldn't be (exactly) instantaneous depending on the refresh interval, but having a bash script running in the background, printing to a file when a new email came in.

Is this doable? I get push from Google for my calendar, mail, and contacts on my phone, so I know that the technology exists, but is it possible to apply this with Arch and Bash (or some other programming language useable on Linux)?

Offline

#2 2011-09-25 20:56:02

whitethorn
Member
Registered: 2010-05-02
Posts: 153

Re: Conky Push Notifications

I use this code with conky to check my gmail account

conky command

${execi 60 /home/$USER/path/to/following/script/gmail.sh}

Script to check emails (gmail.sh)

#!/bin/bash

gmail_login="" #login name
gmail_password="" #pass

dane="$(wget --secure-protocol=TLSv1 --timeout=3 -t 1 -q -O - \
https://${gmail_login}:${gmail_password}@mail.google.com/mail/feed/atom \
--no-check-certificate | grep 'fullcount' \
| sed -e 's/.*<fullcount>//;s/<\/fullcount>.*//' 2>/dev/null)"

if [ -z "$dane" ]; then
echo "No connection"
else
echo "$dane message(s)"
fi

It should be possible to change the script a bit and get it to send a notification if you get an email.

Offline

#3 2011-09-25 23:20:11

jbiggs12
Member
From: USA
Registered: 2011-08-07
Posts: 14
Website

Re: Conky Push Notifications

I already have a script for checking my Gmail, and I just keep it in my .conkyrc, no need for a bash script at all smile

Here it is:

${texeci 180 wget -t 0 --waitretry=20 -q --secure-protocol=TLSv1 --no-check-certificate --user=<username> --password=<password> https://mail.google.com/mail/feed/atom -O - | perl -ne 'if(s/\<(\/{0,1}fullcount\>//g) { print; }'}

What I was asking was if it would be possible for push notifications to work. That is, instead of requesting from the server every x amount of time, the server actually initiates the transaction with the client to tell it that there's new mail. They have a Microsoft Exchange server set up, I was wondering if a bash script could connect to the MS Exchange server and output the amount of unread messages to a text file that changes every time the computer's notified. Failing that, IMAP also has push set up with IDLE... I'm not sure how to implement it, so I was asking for help.

Offline

#4 2011-09-26 13:20:09

ANOKNUSA
Member
Registered: 2010-10-22
Posts: 2,141

Re: Conky Push Notifications

I've personally never seen anything like that.  If I may ask: do you have reall old hardware or a slow net connection or something?  Because if not, what difference does it make?  I suppose if you're expecting something important for work it might be useful, but then again you could simply keep gmail open and refresh the page every couple of minutes in that case, instead of trusting an important message to a script.

Last edited by ANOKNUSA (2011-09-26 13:22:34)

Offline

#5 2011-09-26 13:31:02

jbiggs12
Member
From: USA
Registered: 2011-08-07
Posts: 14
Website

Re: Conky Push Notifications

Gmail implements push in its desktop notifiers and on its notifiers for Chrome. I already 'refresh the page' every 3 minutes with the gmail conky script, so I already have a notification window of 3 minutes on the outside.... I'm mainly just wishing that I had the same implementation as my smartphone. If I can get my phone to get instant notifications, why can't I have the same for my computer?

I don't have a slow internet connection, I guess you could say that I'm just anal smile

By the way, whitethorn, I could be wrong but I'm fairly sure that you shouldn't include your username and password in the url. Use the --username and --password flags with wget instead, because otherwise people might be able to sniff out the url and snag your credentials.

Offline

#6 2011-09-26 22:29:02

whitethorn
Member
Registered: 2010-05-02
Posts: 153

Re: Conky Push Notifications

Good point, I'll have to get around to it sooner rather than later. Yeah I kinda realized what you were looking for after posting. Did a google search and came up with a couple of ideas, haven't tried them out yet, but it looks like interesting. The first link is probably the one I'd try.

http://blog.timstoop.nl/2009/03/11/pyth … -imaplib2/

for mac, but it's written in python
http://hmmtheresanidea.blogspot.com/200 … r-mac.html

Lol, I just noticed the links are from 2009 my googlefu ain't doing to well tonight. It's been around long enough someone has figured it out, I'm subscribing to this thread. smile

Offline

#7 2011-09-26 23:48:32

jbiggs12
Member
From: USA
Registered: 2011-08-07
Posts: 14
Website

Re: Conky Push Notifications

Here's what I've got so far:

http://dl.dropbox.com/u/3423954/imapconky.py

Unfortunately it doesn't do much... at the moment all I can get it to do is write to /tmp/newgmails every time a new message is received. I intended it to at least write the number of new messages, but all I can get it to write is "1"; the script was meant to show the messages one message at a time to stdout. I'm praying some Python guy can come along and fix this up, because I am in waaaay over my head (PHP/Perl here). I could have it update the conky command every time there was a new mail fetched to actually get the number of messages, but that just seems like a waste of cpu resources.

Refreshing upon deletion is also an issue -- at the moment the script is only set to pop every time the messages are received, not when there are any changes to the mailbox in general.

Anyone willing to spruce this up, by all means, do so. This is too close to die. smile

Offline

#8 2011-09-27 13:52:51

whitethorn
Member
Registered: 2010-05-02
Posts: 153

Re: Conky Push Notifications

So I think I've got it. Since this is pretty much my first real python program. Sorry for the horrible looking code. For this script to work you need imaplib2.py ( for IDLE / Imap PUSH functionality). At the moment it prints the amount of email messages to /tmp/newgmails.  I haven't gotten around to integrating it with conky yet. Although I do have a couple cool ideas, python and gamin ...

#!/usr/bin/python2
"""
Released under the MIT/X11 License

Copyright (c) 2010 -- Chris Kirkham

 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the "Software"), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
"""

__version__ = '0.1.1'
__author__  = 'Julian Gagnon'
__URL__     = 'n.A'
__credits__ = """

Chris and his wonderful post at http://hmmtheresanidea.blogspot.com/2009/09/imap-push-gmail-python-script-for-mac.html. Which was modified by Jeff Biggs, and then modified by me.
Jeff's modification removed the idea of sending Growl notifications, instead it simply prints the number of new messages to a file. You can do much more with this.

My Changes, added a unread messages check at inialization, then when updated (push arrives) recheck total unread messages.

FOR THIS TO WORK YOU MUST ENABLE IMAP ACCOUNT IN YOUR GMAIL ACCOUNT!!
YOU ALSO NEED imaplib2.py 

Enjoy!! :)

"""
__license__ = "MIT/X11"
__version__ = "1.0.1"


import threading, imaplib2, os, sys


#Three basic settings for you to change -- if you don't want command line input, replace the
#sys.argv[x]s with the desired username and/or password.

YourGmailUsername = ''
YourGmailPassword = ''

ServerTimeout     = 29 # Mins           (leave if you're not sure)

# This is where the magic happens. Change the code below at your peril!
# Obviously if you know what you're doing, or just want to fiddle, go ahead. Don't let this warning stop you!
# But, as it is, this should work. As before, make sure you have IMAP enabled.

#'True' to enter debug mode
DEBUG = False # debugMsg() prints the parameter passed if DEBUG is True


"""
The worker class for the thread. Letting a thread wait for the server to send something allows the
main thread (if that's what you call it??) to be used for other stuff -- waiting for UI, for example.
"""
class Idler(threading.Thread):

    imap = imaplib2.IMAP4_SSL("imap.gmail.com") # can be changed to another server if needed

    stopWaitingEvent = threading.Event()
    #Now, this stopWaitingEvent thing -- it really does make the whole thing work. Basically,
    #it holds a boolean value which is set and cleared using, oddly enough, the methods set() and
    #clear(). But, the good thing about it is that it has another method, wait(), which holds
    #execution until it has been set(). I cannot thank threading.Event() enough, I really couldn't
    #have done it without you!

    knownAboutMail = [] # will be a list of IDs of messages in the inbox
    killNow = False # stops execution of thread to allow propper closing of conns.

    def __init__(self, GMailUsername, GMailPassword):

        os.system('clear')
        debugMsg('DEBUG is ENABLED')
        debugMsg('__init__() entered')

        try:
            #establish connection to IMAP Server
            self.imap.LOGIN(GMailUsername, GMailPassword)
            self.imap.SELECT("INBOX")

            #get the IDs of all messages in the inbox and put in knowAboutMail
            typ, data = self.imap.SEARCH(None, 'ALL')

            #Get initial amount of unread emails
            unreadCount = len(self.imap.SEARCH(None,  'Unseen')[1][0].split())
            self.knownAboutMail = data[0].split()

            # Create temp file and fill with number unread emails
            f = open('/tmp/newgmails', 'w+')
            f.write(str(unreadCount))
            f.close()

            #now run the inherited __init__ method to create thread
            threading.Thread.__init__(self)

        except: #Uh Oh, something went wrong
            print 'ERROR: IMAP Issue. It could be one (or more) of the following:'
            print '- The impalib2.py file needs to be in the same directory as this file'
            print '- You\'re not connected to the internet'
            print '- Google\'s mail server(s) is/are down'
            print '- Your username and/or password is incorrect'
            sys.exit(1)

        debugMsg('__init__() exited')


    """
    The method invoked when the thread id start()ed. Enter a loop executing waitForServer()
    untill kill()ed. waitForServer() can, and should, be continuously executed to be alerted
    of new mail.
    """
    def run(self):
        debugMsg('run() entered')

        #loop until killNow is set by kill() method
        while not self.killNow:
            self.waitForServer()

            debugMsg('run() exited')

    """
    Called to stop the script. It stops the continuous while loop in run() and therefore
    stops the thread's execution.
    """
    def kill(self):
        self.killNow = True # to stop while loop in run()
        self.timeout = True # keeps waitForServer() nice
        self.stopWaitingEvent.set() # to let wait() to return and let execution continue


    """
    This is the block of code called by the run() method of the therad. It is what does all
    the waiting for new mail (well, and timeouts).
    """
    def waitForServer(self):
        debugMsg('waitForServer() entered')

        #init
        self.newMail = False
        self.timeout = False
        self.IDLEArgs = ''
        self.stopWaitingEvent.clear()

        def _IDLECallback(args):
            self.IDLEArgs = args
            self.stopWaitingEvent.set()
            #_IDLECallack() is entered when the IMAP server responds to the IDLE command when new
            #mail is received. The self.stopWaitingEvent.set() allows the .wait() to return and
            #therefore the rest of waitForServer().


        #attach callback function, and let server know it should tell us when new mail arrives
        self.imap.idle(timeout=60*ServerTimeout, callback=_IDLECallback)

        #execution will stay here until either:
        # - a new message is received; or
        # - the timeout has happened
        #       - we set the timout -- the RFC says the server has the right to forget about
        #         us after 30 mins of inactivity (i.e. not communicating with server for 30 mins).
        #         By sending the IDLE command every 29 mins, we won't be forgotten.
        # - Alternatively, the kill() method has been invoked.
        self.stopWaitingEvent.wait()

        #self.IDLEArgs has now been filled (if not kill()ed)

        if not self.killNow: # skips a chunk of code to sys.exit() more quickly.

            if self.IDLEArgs[0][1][0] == ('IDLE terminated (Success)'):
            # This (above) is sent when either: there has been a timeout (server sends); or, there
            # is new mail. We have to check manually to see if there is new mail.

                typ, data = self.imap.SEARCH(None, 'UNSEEN') # like before, get UNSEEN message IDs

                debugMsg('Data: ')
                debugMsg(data, 0)

                #see if each ID is new, and, if it is, make newMail True
                for id in data[0].split():
                    if not id in self.knownAboutMail:
                        self.newMail = self.newMail or True
                    else:
                        self.timeout = True
                        # gets executed if there are UNSEEN messages that we have been notified of,
                        # but we haven't yet read. In this case, it response was just a timeout.

                if data[0] == '': # no IDs, so it was a timeout (but no notified but UNSEEN mail)
                    self.timeout = True

            #now there has either been a timeout or a new message -- Do something...
            if self.newMail:
                          # here's where the actual notification magic happens!
                          # /tmp/newgmails is created in def main(), what happens here is the old value is read, added to, and then saved.
                          print 'New message. Writing to ~/tmp/newgmails ...'
                          # Recheck amount of unread emails in account
                          unreadCount = len(self.imap.SEARCH(None,  'Unseen')[1][0].split())
                          #write to file
                          f = open('/tmp/newgmails', 'w')
                          f.write(str(unreadCount))
                          f.close()

            elif self.timeout:
                debugMsg('INFO: A Timeout Occurred')

        debugMsg('waitForServer() exited')



"""
Simple procedure to output debug messages nicely.
"""
def debugMsg(msg, newline=1):
    global DEBUG
    if DEBUG:
        if newline:
            print ' '
        print msg


"""
Main bit of code to get the ball rolling. It starts the thread and waits for 'q' to be input.
That's it. Nice and simple.
"""
def main():
    global YourGmailUsername
    global YourGmailPassword

# Not pretty but I'm not that far in the python book
# use imaplib to find out how many unread emails we got

    idler = Idler(YourGmailUsername, YourGmailPassword)
    idler.start()

    print '* Waiting for mail...'
    q = ''
    while not q == 'q':
        q = raw_input('Type \'q\' followed by [ENTER] to quit: ')

    idler.kill()
    idler.imap.CLOSE()
    idler.imap.LOGOUT()
    sys.exit()



if __name__ == '__main__': # then this script is being run on its own, i.e. not imported
    main()
else:
    print 'I don\'t think you ment to import this'
    sys.exit(1)

Update: I just realized this doesn't update seen / deleted emails until a new one shows up. Not quite sure what's the best way to implement it now. I guess a mix script would probably be best, poll the server every couple minutes and push for updates.

Last edited by whitethorn (2011-09-27 20:13:07)

Offline

#9 2011-09-27 22:45:53

jbiggs12
Member
From: USA
Registered: 2011-08-07
Posts: 14
Website

Re: Conky Push Notifications

While I appreciate the reference, my name is Jack. :)

Instead of changing the script, try simply editing what's already there!

${texeci 180 wget -t 0 --waitretry=20 -q --secure-protocol=TLSv1 --no-check-certificate --user=<username> --password=<password> https://mail.google.com/mail/feed/atom -O - | perl -ne 'if(s/\<(\/{0,1}fullcount\>//g) { print; }' > /tmp/newgmails }
${exec cat /tmp/newgmails }

Keep the python script running in the background, and then just modify that line in your .conkyrc. It's still polled every few minutes but writes to /tmp/newgmails, and then every update_interval it reads from /tmp/newgmails. Ta-da!

I'm not marking this as solved just yet -- I want to see if some python guru can come along and integrate the two (if someone manages to find this before I find the time).

Thanks for your help, my .conkyrc applauds you!

Edit: A bit of tweaking also makes for some great dzen2 notifications, I posted a modified version of the script that I tweaked to my blog.

Last edited by jbiggs12 (2011-09-27 22:58:01)

Offline

#10 2011-09-29 15:50:35

whitethorn
Member
Registered: 2010-05-02
Posts: 153

Re: Conky Push Notifications

I made a couple changes to the script (with some help from a friend).

1) notify-send is used to display Sender and Subject and an Icon. smile
2) Added a loop to poll gmail for updates, no need to use your texeci oneliner. All that is now needed in conky is a cat /tmp/newgmails.
3) Added a SIGKILL catch which reacts to Ctrl+C as well as a to the kill command.
4) Renamed Jeff to Jack. My apologies.

What I might still try to deamonize it, fork it and redirect the output to a log of some kind.
Here's the link http://dl.dropbox.com/u/43386537/conkyimap.tar.gz

Offline

Board footer

Powered by FluxBB