def send_alert(self):
        """
            Notifies user according to requirements.
        """

        # check if user wants notifications
        if self.config['notify'] == False:
            return

        # check whether conditions are met
        if self.account['diff'] <= 0:
            return

        # check whether user wants an effect on the icon
        if self.config['anim'] == True:
            self.icon.DemandsAttention(True, self.config['how'])

        # check whether user wants a dialogue
        if self.config['dia'] == True:
            # checking our grammar ;) # we have at least one new email
            if self.account['count'] > 1:
                message = _("You have %s new emails") % (str(
                    self.account['count']))
            else:
                message = _("You have 1 new email")
            self.icon.ShowDialog(message, 3)

        # check whether user wants a sound
        if self.config['sound'] == True:
            try:
                os.popen('aplay ' + self.wav)
            except:
                # restore default sound file if custom is corrupted
                self.wav = os.path.abspath("./snd/pop.wav")
    def add_subscription(self, request=None):

        """
            Prompts user to add subscription details.
        """

        # if requesting new username:
        if request == 'username':
            # set dialogue flag to 'username'
            self.flag = 'username'
            # prompt for username
            message = _("Please, enter your Gmail username:"******"message" : message, "buttons" : "gtk-go-forward-ltr;cancel"},
                    {"widget-type" : "text-entry"})
        # if requesting new password:
        elif request == 'password':
            # set dialogue flag to 'password'
            self.flag = 'password'
            # prompt for password
            message = _("Please, enter your Gmail password:"******"message" : message, "buttons" : "ok;cancel"},
                    {"widget-type" : "text-entry", "visible" : False})
        # default request is to encrypt username and password
        else:
            # open, encode and write to subscription file
            file = open(self.subpath, 'wb')
            file.write(base64.b64encode(str(self.account['username']+ \
            '\n'+self.account['password']).encode('ascii')))
            file.close()
            # run subscription check as double check
            self.check_subscription()
    def send_alert(self):

        """
            Notifies user according to requirements.
        """

        # check if user wants notifications
        if self.config['notify'] == False:
            return

        # check whether conditions are met
        if self.account['diff'] <= 0:
            return
        
        # check whether user wants an effect on the icon
        if self.config['anim'] == True:
            self.icon.DemandsAttention(True, self.config['how'])

        # check whether user wants a dialogue
        if self.config['dia'] == True:
            # checking our grammar ;) # we have at least one new email
            if self.account['count'] > 1:
                message = _("You have %s new emails") % (str(self.account['count']))
            else:
                message = _("You have 1 new email")
            self.icon.ShowDialog(message, 3)

        # check whether user wants a sound
        if self.config['sound'] == True:
            try:
                os.popen('aplay ' + self.wav)
            except:
                # restore default sound file if custom is corrupted
                self.wav = os.path.abspath("./snd/pop.wav")
    def request_gmail(self):

        """
            Authenticates and requests inbox content from Gmail.
        """

        gmailfeed = 'https://mail.google.com/mail/feed/atom/'
        request = _urllib.Request(gmailfeed)

        # connect to Gmail
        error = None
        try:
            handle = _urllib.urlopen(request)
        except IOError as err:
            # here we will need "fail" as we receive a 401 error to get access
            error = err

        if not hasattr(error, 'code') or error.code != 401:
            # we got an error - but not a 401 error
            message = _("WARNING: Gmail applet failed to connect to Gmail atom feed.")
            self.error(message)
            return None

        # get the www-authenticate line from the headers
        authline = error.headers['www-authenticate']

        # from this header we extract scheme and realm
        authobject = re.compile(
                                r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"]([^'"]+)['"]''',
                                re.IGNORECASE)
        matchobject = authobject.match(authline)

        # make sure scheme and realm was found
        if not matchobject:
            message = _("WARNING: Gmail atom feed is badly formed: ")
            m = message + authline
            self.error(m)
            return None

        # check what scheme we have
        scheme = matchobject.group(1)
        if scheme.lower() != 'basic':
            message = _("WARNING: Gmail Applet is not equipped for authentication other than BASIC.")
            return self.error(message)

        # authenticate and get inbox content
        account = ('%s:%s' % (self.account['username'], self.account['password'])).encode('ascii')
        
        base64string = base64.encodestring(account)[:-1].decode()
        authheader = "Basic %s" % base64string
        request.add_header("Authorization", authheader)
        try:
            handle = _urllib.urlopen(request)
        except IOError as error:
            # here we shouldn't fail if the username/password is right
            message = _("WARNING: Gmail username or password may be wrong.")
            self.error(message)
            return None

        return handle
    def error(self, message):

        """
            Warns the user if an error occured.
        """

        # no need to update the icon
        if self.flag == 'error':
            return

        if self.config['info'] != 'quickinfo':
            # remove previous quickinfo if needed:
            self.icon.SetQuickInfo('')
            # get size from config:
            size = self.config['info'].split()[0]
            # pass size to filename:
            file = './img/gmail-error-'+size+'.svg'
            # set icon with error emblem
            self.icon.SetIcon(os.path.abspath(file))

        else:
            # reset icon in case needed
            self.icon.SetIcon(os.path.abspath('./icon'))
            # set quickinfo:
            self.icon.SetQuickInfo(_('Error!'))
        # check if any error is already known
        # or if the user is changing subscription details
        if self.flag != None:
            return
        # set error flag
        self.flag = 'error'
        self.account['count'] = -99 # to be sure that the icon will be updated
        # show dialogue
        self.icon.ShowDialog(message, 4)
    def on_answer_dialog(self, key, content):
        """
            Processes dialogue input for username and password.
        """

        # check user pressed the first button (OK) or Enter
        if key == 0 or key == CDApplet.DIALOG_KEY_ENTER:
            # check user entered something
            if len(content) > 0:
                # check if requesting username
                if self.flag == 'username':
                    # append account with username
                    self.account['username'] = format(content)
                    # request password
                    self.add_subscription('password')
                # check if requesting password
                elif self.flag == 'password':
                    # append account with password
                    self.account['password'] = format(content)
                    # finish up registration process
                    self.add_subscription()
                else:
                    # should not happen (kept in case another dialogue needs
                    # to be made in future).
                    pass
            else:
                message = _("Sorry, there was no input!")
                self.error(message)
    def error(self, message):
        """
            Warns the user if an error occured.
        """

        # no need to update the icon
        if self.flag == 'error':
            return

        if self.config['info'] != 'quickinfo':
            # remove previous quickinfo if needed:
            self.icon.SetQuickInfo('')
            # get size from config:
            size = self.config['info'].split()[0]
            # pass size to filename:
            file = './img/gmail-error-' + size + '.svg'
            # set icon with error emblem
            self.icon.SetIcon(os.path.abspath(file))

        else:
            # reset icon in case needed
            self.icon.SetIcon(os.path.abspath('./icon'))
            # set quickinfo:
            self.icon.SetQuickInfo(_('Error!'))
        # check if any error is already known
        # or if the user is changing subscription details
        if self.flag != None:
            return
        # set error flag
        self.flag = 'error'
        self.account['count'] = -99  # to be sure that the icon will be updated
        # show dialogue
        self.icon.ShowDialog(message, 4)
    def on_answer_dialog(self, key, content):

        """
            Processes dialogue input for username and password.
        """

        # check user pressed the first button (OK) or Enter
        if key == 0 or key == CDApplet.DIALOG_KEY_ENTER:
            # check user entered something
            if len(content) > 0:
                # check if requesting username
                if self.flag == 'username':
                    # append account with username
                    self.account['username'] = format(content)
                    # request password
                    self.add_subscription('password')
                # check if requesting password
                elif self.flag == 'password':
                    # append account with password
                    self.account['password'] = format(content)
                    # finish up registration process
                    self.add_subscription()
                else:
                    # should not happen (kept in case another dialogue needs
                    # to be made in future).
                    pass
            else:
                message = _("Sorry, there was no input!")
                self.error(message)
    def __init__(self, inbox):
        gtk.Menu.__init__(self)

        # get all mail from inbox
        for mail in inbox:
            # create label menu with markups
            string = '<b>' + html_escape(mail['author']) + ':</b>\n'

            # check if mail has subject / title
            if mail['title'] == None or len(mail['title']) == 0:
                string += '<i>(' + _('No Subject') + ')</i>'
            elif len(mail['title']) > 80:
                string += html_escape(mail['title'][:77]) + '...'
            else:
                string += html_escape(mail['title'])

            menu_item = gtk.ImageMenuItem()
            # the true label is set after with set_markup()
            menu_item.set_label('')
            try:
                menu_item.set_image(gtk.image_new_from_file('./img/menu-gmail.png'))
            except:
                menu_item.set_image(gtk.Image.new_from_file('./img/menu-gmail.png'))
            menu_item.get_children()[0].set_markup(string)
            menu_item.url = mail['link']
            menu_item.connect('activate', self.open_mail, mail)
            self.append(menu_item)
            menu_item.show()
            # add a separator if mail is not last in list
            if inbox.index(mail) != len(inbox) - 1:
                sep = gtk.SeparatorMenuItem()
                self.append(sep)
                sep.show()

        self.show()
    def check_subscription(self):
        """
            Checks which accounts the user subsribed to, gets usernames and
            passwords as well as how often the account should be checked.
        """

        # reset flag in case of prior error:
        self.flag = None

        # open subscription file and read data
        try:
            file = open(self.subpath, 'r')
            sub = file.read()
            file.close()
        except:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # check if there was any data
        if len(sub) < 1:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # if so process the data
        account = base64.b64decode(
            sub.strip('\n').encode('ascii')).decode().split('\n')

        # check if the data is correct
        if len(account) != 2:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # then process the data into account
        self.account = {
            'username': account[0],
            'password': account[1],
            'count': 0,
            'diff': 0
        }

        self.check_mail()
        self.repeat()
    def check_subscription(self):

        """
            Checks which accounts the user subsribed to, gets usernames and
            passwords as well as how often the account should be checked.
        """

        # reset flag in case of prior error:
        self.flag = None

        # open subscription file and read data
        try:
            file = open(self.subpath, 'r')
            sub = file.read()
            file.close()
        except:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # check if there was any data
        if len(sub) < 1:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # if so process the data
        account = base64.b64decode(sub.strip('\n').encode('ascii')).decode().split('\n')

        # check if the data is correct
        if len(account) != 2:
            message = _("Please fill in your Gmail account.")
            self.error(message)
            return

        # then process the data into account
        self.account = {'username': account[0],
            'password': account[1],
            'count': 0,
            'diff': 0}
        
        self.check_mail()
        self.repeat()
    def on_build_menu(self):

        """
            Appends items to right-click menu.
        """

        message_add_label = _("Add or change subscription")
        message_add_tooltip = _("Use this to add or change your Gmail account details.")
        message_middle_click = _("middle-click")
        message_check_label = _("Check inbox now")
        message_check_tooltip = _("Check Gmail inbox now if you can't wait.")
        message_new_mail = _("Write a mail")
        self.icon.AddMenuItems([{"widget-type" : CDApplet.MENU_ENTRY,
        "label": message_add_label,
        "icon" : "gtk-add",
        "menu" : CDApplet.MAIN_MENU_ID,
        "id" : 1,
        "tooltip" : message_add_tooltip},
        {"widget-type" : CDApplet.MENU_ENTRY,
        "label": message_check_label + " (" + message_middle_click + ")",
        "icon" : "gtk-refresh",
        "menu" : CDApplet.MAIN_MENU_ID,
        "id" : 2,
        "sensitive" : (len(self.account) > 1), # at least 'count' => -99
        "tooltip" : message_check_tooltip},
        {"widget-type" : CDApplet.MENU_ENTRY,
        "label": message_new_mail,
        "icon" : "gtk-new",
        "menu" : CDApplet.MAIN_MENU_ID,
        "id" : 3}])
	def __init__(self):
		super(TransparentPostIt, self).__init__()

		self.set_title(_('GTG PostIt'))
		self.resize(200, 100)
		# Tell GTK+ that we want to draw the windows background ourself.
		# If we don't do this then GTK+ will clear the window to the
		# opaque theme default color, which isn't what we want.
		self.set_app_paintable(True)
		# The X server sends us an expose event when the window becomes
		# visible on screen. It means we need to draw the contents.	On a
		# composited desktop expose is normally only sent when the window
		# is put on the screen. On a non-composited desktop it can be
		# sent whenever the window is uncovered by another.
		#
		# The screen-changed event means the display to which we are
		# drawing changed. GTK+ supports migration of running
		# applications between X servers, which might not support the
		# same features, so we need to check each time.		 
		self.connect('expose-event', self.expose)
		self.connect('screen-changed', self.screen_changed)
		# toggle title bar on click - we add the mask to tell 
		# X we are interested in this event
		self.set_decorated(False)
		self.add_events(gdk.BUTTON_PRESS_MASK)
		self.connect('button-press-event', self.clicked)

		self.supports_alpha = False
		
		# initialize for the current display
		self.screen_changed(self)

		sw = gtk.ScrolledWindow()
		sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
		self.textview = gtk.TextView()
		self.textview.set_wrap_mode(gtk.WRAP_WORD)
		self.textview.set_editable(False)
		self.textbuffer = self.textview.get_buffer()
		sw.add(self.textview)

		# to make it transparent:
		# 1 - be called when the textview widget gets realized:
		#      textview.connect("expose-event", textview_expose)
		self.textview.connect("expose-event", self.textview_expose)
		# 2 - in the expose callback, get the window corresponding to the drawing:
		#      textview_window = textview.get_window(gtk.TEXT_WINDOW_WIDGET) or
		#      textview_window = textview.get_window(gtk.TEXT_WINDOW_TEXT)
		# 3 - use cairo (like in expose) to draw the background of the gdk.Window

		self.add(sw)
		self.show_all()
    def __init__(self):
        super(TransparentPostIt, self).__init__()

        self.set_title(_('GTG PostIt'))
        self.resize(200, 100)
        # Tell GTK+ that we want to draw the windows background ourself.
        # If we don't do this then GTK+ will clear the window to the
        # opaque theme default color, which isn't what we want.
        self.set_app_paintable(True)
        # The X server sends us an expose event when the window becomes
        # visible on screen. It means we need to draw the contents.	On a
        # composited desktop expose is normally only sent when the window
        # is put on the screen. On a non-composited desktop it can be
        # sent whenever the window is uncovered by another.
        #
        # The screen-changed event means the display to which we are
        # drawing changed. GTK+ supports migration of running
        # applications between X servers, which might not support the
        # same features, so we need to check each time.
        self.connect('expose-event', self.expose)
        self.connect('screen-changed', self.screen_changed)
        # toggle title bar on click - we add the mask to tell
        # X we are interested in this event
        self.set_decorated(False)
        self.add_events(gdk.BUTTON_PRESS_MASK)
        self.connect('button-press-event', self.clicked)

        self.supports_alpha = False

        # initialize for the current display
        self.screen_changed(self)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        self.textview = gtk.TextView()
        self.textview.set_wrap_mode(gtk.WRAP_WORD)
        self.textview.set_editable(False)
        self.textbuffer = self.textview.get_buffer()
        sw.add(self.textview)

        # to make it transparent:
        # 1 - be called when the textview widget gets realized:
        #      textview.connect("expose-event", textview_expose)
        self.textview.connect("expose-event", self.textview_expose)
        # 2 - in the expose callback, get the window corresponding to the drawing:
        #      textview_window = textview.get_window(gtk.TEXT_WINDOW_WIDGET) or
        #      textview_window = textview.get_window(gtk.TEXT_WINDOW_TEXT)
        # 3 - use cairo (like in expose) to draw the background of the gdk.Window

        self.add(sw)
        self.show_all()
    def add_subscription(self, request=None):
        """
            Prompts user to add subscription details.
        """

        # if requesting new username:
        if request == 'username':
            # set dialogue flag to 'username'
            self.flag = 'username'
            # prompt for username
            message = _("Please, enter your Gmail username:"******"message": message,
                    "buttons": "gtk-go-forward-ltr;cancel"
                }, {"widget-type": "text-entry"})
        # if requesting new password:
        elif request == 'password':
            # set dialogue flag to 'password'
            self.flag = 'password'
            # prompt for password
            message = _("Please, enter your Gmail password:"******"message": message,
                "buttons": "ok;cancel"
            }, {
                "widget-type": "text-entry",
                "visible": False
            })
        # default request is to encrypt username and password
        else:
            # open, encode and write to subscription file
            file = open(self.subpath, 'wb')
            file.write(base64.b64encode(str(self.account['username']+ \
            '\n'+self.account['password']).encode('ascii')))
            file.close()
            # run subscription check as double check
            self.check_subscription()
    def get_inbox(self, xml_data):
        """
            Counts the unread messages from the XML inbox content.
        """

        inbox = []

        try:
            try:
                tree = libxml2.parseDoc(xml_data)
                path = tree.xpathNewContext()
                path.xpathRegisterNs('purl', 'http://purl.org/atom/ns#')
                entries = path.xpathEval('//purl:entry')
                if len(entries) > 0:
                    for entry in entries:
                        path.setContextNode(entry)
                        mail = {}
                        mail['title'] = path.xpathEval('purl:title')[0].content
                        mail['summary'] = path.xpathEval(
                            'purl:summary')[0].content
                        mail['link'] = path.xpathEval('purl:link')[0].prop(
                            'href')
                        mail['author'] = path.xpathEval(
                            'purl:author/purl:name')[0].content
                        inbox.append(mail)
            except:
                tree = etree.fromstring(xml_data)
                namespaces = {'purl': 'http://purl.org/atom/ns#'}
                entries = tree.xpath('purl:entry', namespaces=namespaces)
                if len(entries) > 0:
                    for entry in entries:
                        mail = {}
                        mail['title'] = entry.xpath(
                            'purl:title', namespaces=namespaces)[0].text
                        mail['summary'] = entry.xpath(
                            'purl:summary', namespaces=namespaces)[0].text
                        mail['link'] = entry.xpath(
                            'purl:link', namespaces=namespaces)[0].get('href')
                        mail['author'] = entry.xpath(
                            'purl:author/purl:name',
                            namespaces=namespaces)[0].text
                        inbox.append(mail)
            return inbox
        except:
            message = _("WARNING: there was an error reading XML content.")
            self.error(message)
            return None
    def get_inbox(self, xml_data):

        """
            Counts the unread messages from the XML inbox content.
        """

        inbox = []

        try:
            try:
                tree = libxml2.parseDoc(xml_data)
                path = tree.xpathNewContext()
                path.xpathRegisterNs('purl', 'http://purl.org/atom/ns#')
                entries = path.xpathEval('//purl:entry')
                if len(entries) > 0:
                    for entry in entries:
                        path.setContextNode(entry)
                        mail = {}
                        mail['title'] = path.xpathEval('purl:title')[0].content
                        mail['summary'] = path.xpathEval('purl:summary')[0].content
                        mail['link'] = path.xpathEval('purl:link')[0].prop('href')
                        mail['author'] = path.xpathEval('purl:author/purl:name')[0].content
                        inbox.append(mail)
            except:
                tree = etree.fromstring(xml_data)
                namespaces = {'purl':'http://purl.org/atom/ns#'}
                entries = tree.xpath('purl:entry', namespaces = namespaces)
                if len(entries) > 0:
                    for entry in entries:
                        mail = {}
                        mail['title'] = entry.xpath('purl:title', namespaces = namespaces)[0].text
                        mail['summary'] = entry.xpath('purl:summary', namespaces = namespaces)[0].text
                        mail['link'] = entry.xpath('purl:link', namespaces = namespaces)[0].get('href')
                        mail['author'] = entry.xpath('purl:author/purl:name', namespaces = namespaces)[0].text
                        inbox.append(mail)
            return inbox
        except:
            message = _("WARNING: there was an error reading XML content.")
            self.error(message)
            return None
    def __init__(self, inbox):
        gtk.Menu.__init__(self)

        # get all mail from inbox
        for mail in inbox:
            # create label menu with markups
            string = '<b>' + html_escape(mail['author']) + ':</b>\n'

            # check if mail has subject / title
            if mail['title'] == None or len(mail['title']) == 0:
                string += '<i>(' + _('No Subject') + ')</i>'
            elif len(mail['title']) > 80:
                string += html_escape(mail['title'][:77]) + '...'
            else:
                string += html_escape(mail['title'])

            menu_item = gtk.ImageMenuItem()
            # the true label is set after with set_markup()
            menu_item.set_label('')
            try:
                menu_item.set_image(
                    gtk.image_new_from_file('./img/menu-gmail.png'))
            except:
                menu_item.set_image(
                    gtk.Image.new_from_file('./img/menu-gmail.png'))
            menu_item.get_children()[0].set_markup(string)
            menu_item.url = mail['link']
            menu_item.connect('activate', self.open_mail, mail)
            self.append(menu_item)
            menu_item.show()
            # add a separator if mail is not last in list
            if inbox.index(mail) != len(inbox) - 1:
                sep = gtk.SeparatorMenuItem()
                self.append(sep)
                sep.show()

        self.show()
    def on_build_menu(self):
        """
            Appends items to right-click menu.
        """

        message_add_label = _("Add or change subscription")
        message_add_tooltip = _(
            "Use this to add or change your Gmail account details.")
        message_middle_click = _("middle-click")
        message_check_label = _("Check inbox now")
        message_check_tooltip = _("Check Gmail inbox now if you can't wait.")
        message_new_mail = _("Write a mail")
        self.icon.AddMenuItems([
            {
                "widget-type": CDApplet.MENU_ENTRY,
                "label": message_add_label,
                "icon": "gtk-add",
                "menu": CDApplet.MAIN_MENU_ID,
                "id": 1,
                "tooltip": message_add_tooltip
            },
            {
                "widget-type": CDApplet.MENU_ENTRY,
                "label":
                message_check_label + " (" + message_middle_click + ")",
                "icon": "gtk-refresh",
                "menu": CDApplet.MAIN_MENU_ID,
                "id": 2,
                "sensitive":
                (len(self.account) > 1),  # at least 'count' => -99
                "tooltip": message_check_tooltip
            },
            {
                "widget-type": CDApplet.MENU_ENTRY,
                "label": message_new_mail,
                "icon": "gtk-new",
                "menu": CDApplet.MAIN_MENU_ID,
                "id": 3
            }
        ])
    def request_gmail(self):
        """
            Authenticates and requests inbox content from Gmail.
        """

        gmailfeed = 'https://mail.google.com/mail/feed/atom/'
        request = _urllib.Request(gmailfeed)

        # connect to Gmail
        error = None
        try:
            handle = _urllib.urlopen(request)
        except IOError as err:
            # here we will need "fail" as we receive a 401 error to get access
            error = err

        if not hasattr(error, 'code') or error.code != 401:
            # we got an error - but not a 401 error
            message = _(
                "WARNING: Gmail applet failed to connect to Gmail atom feed.")
            self.error(message)
            return None

        # get the www-authenticate line from the headers
        authline = error.headers['www-authenticate']

        # from this header we extract scheme and realm
        authobject = re.compile(
            r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"]([^'"]+)['"]''',
            re.IGNORECASE)
        matchobject = authobject.match(authline)

        # make sure scheme and realm was found
        if not matchobject:
            message = _("WARNING: Gmail atom feed is badly formed: ")
            m = message + authline
            self.error(m)
            return None

        # check what scheme we have
        scheme = matchobject.group(1)
        if scheme.lower() != 'basic':
            message = _(
                "WARNING: Gmail Applet is not equipped for authentication other than BASIC."
            )
            return self.error(message)

        # authenticate and get inbox content
        account = ('%s:%s' % (self.account['username'],
                              self.account['password'])).encode('ascii')

        base64string = base64.encodestring(account)[:-1].decode()
        authheader = "Basic %s" % base64string
        request.add_header("Authorization", authheader)
        try:
            handle = _urllib.urlopen(request)
        except IOError as error:
            # here we shouldn't fail if the username/password is right
            message = _("WARNING: Gmail username or password may be wrong.")
            self.error(message)
            return None

        return handle