#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Unity Mail, the Preferences Dialog
# Authors: Dmitry Shachnev <mitya57@gmail.com>
#          Robert Tari <robert.tari@gmail.com>
# License: GNU GPL 3 or higher; http://www.gnu.org/licenses/gpl.html

import UnityMail.imaplib2 as imaplib
import os.path
from socket import error as socketerror
from gi.repository import Gtk, GdkPixbuf, Gdk
from UnityMail import g_oSettings
from UnityMail.config import ConfigFile, config_file_path
from UnityMail.application import APPVERSION

MESSAGEACTION = {'OPEN': 1, 'MARK': 2, 'ASK': 3}

def utf7dec(lstInput):

    if not isinstance(lstInput, bytes):
        return lstInput

    lstResult = []
    lstBytes = bytearray()

    for nChar in lstInput:

        if nChar == b'&'[0] and not lstBytes:

            lstBytes.append(nChar)

        elif nChar == b'-'[0] and lstBytes:

            if len(lstBytes) == 1:
                lstResult.append('&')
            else:
                lstResult.append((b'+' + lstBytes[1:].replace(b',', b'/') + b'-').decode('utf-7'))

            lstBytes = bytearray()

        elif lstBytes:

            lstBytes.append(nChar)

        else:

            lstResult.append(chr(nChar))

    if lstBytes:
        lstResult.append((b'+' + lstBytes[1:].replace(b',', b'/') + b'-').decode('utf-7'))

    return ''.join(lstResult)

class ComboEntry(Gtk.ButtonBox):

    def __init__(self, strText, strId, **kwargs):

        Gtk.ButtonBox.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, layout_style=Gtk.ButtonBoxStyle.EXPAND, **kwargs)

        self.oComboBoxText = Gtk.ComboBoxText()
        self.oComboBoxText.append('HTTP:', _('Web page'))
        self.oComboBoxText.append('Exec:', _('Command'))
        self.oEntry = Gtk.Entry(text=strText[5:] if strText.startswith('Exec:') else strText)
        self.oEntry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'gtk-revert-to-saved-ltr')
        self.oEntry.connect('icon-press', self.onReset)
        self.oComboBoxText.set_active_id('Exec:' if strText.startswith('Exec:') else 'HTTP:')
        self.pack_start(self.oComboBoxText, False, False, 0)
        self.pack_start(self.oEntry, True, True, 0)
        self.set_homogeneous(False)
        self.strId = strId

    def onReset(self, oWidget, nPosition, oEvent):

        strText = g_oSettings.get_default_value(self.strId).get_string();
        self.oEntry.set_text(strText[5:] if strText.startswith('Exec:') else strText)
        self.oComboBoxText.set_active_id('Exec:' if strText.startswith('Exec:') else 'HTTP:')

    def getText(self):

        return ('Exec:' if self.oComboBoxText.get_active_id() == 'Exec:' else '') + self.oEntry.get_text()

class FileChooserButtonEx(Gtk.ButtonBox):

    def __init__(self, strFilename, **kwargs):

        Gtk.ButtonBox.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, layout_style=Gtk.ButtonBoxStyle.EXPAND, **kwargs)

        oButtonClear = Gtk.Button.new_from_icon_name('gtk-clear', Gtk.IconSize.BUTTON)
        oButtonClear.connect('clicked', self.onClear)
        oButtonOpen = Gtk.Button()
        oButtonOpen.connect('clicked', self.onOpen)
        self.oLabel = Gtk.Label(os.path.basename(strFilename) or _('(None)'), xalign=0)
        oImage = Gtk.Image.new_from_icon_name('gtk-open', Gtk.IconSize.BUTTON)
        oBox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        oBox.pack_start(oImage, False, False, 0)
        oBox.pack_start(self.oLabel, True, True, 0)
        oButtonOpen.add(oBox)
        self.pack_start(oButtonOpen, True, True, 0)
        self.pack_start(oButtonClear, False, False, 0)
        self.set_homogeneous(False)
        self.strFilename = strFilename

    def onClear(self, oWidget):

        self.strFilename = ''
        self.oLabel.set_text(_('(None)'))

    def onOpen(self, oWidget):

        oDlg = Gtk.FileChooserDialog(None, oWidget.get_toplevel(), 0, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.APPLY))

        if self.strFilename:
            oDlg.set_filename(self.strFilename)

        nResponse = oDlg.run()

        if nResponse == Gtk.ResponseType.APPLY:

            self.strFilename = oDlg.get_filename()
            self.oLabel.set_text(os.path.basename(self.strFilename))

        oDlg.destroy()

    def getFilename(self):

        return self.strFilename

class PreferencesDialog(Gtk.Dialog):

    def __init__(self):

        self.bInit = False
        self.initConfig()
        Gtk.Dialog.__init__(self, _('Unity Mail Preferences'), None, 0, (Gtk.STOCK_CONNECT, 100, Gtk.STOCK_APPLY, Gtk.ResponseType.APPLY, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
        self.set_icon_name('unity-mail')
        self.connect('destroy', lambda w: Gtk.main_quit())
        self.connect('response', self.onResponse)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_property('width-request', 640)
        self.set_property('height-request', 480)
        self.oNotebook = Gtk.Notebook(vexpand=True, margin_left=5, margin_top=5, margin_right=5)
        self.oNotebook.append_page(self.pageAccounts(), Gtk.Label(_('Accounts')))
        self.oNotebook.append_page(self.pageLinks(), Gtk.Label(_('Links')))
        self.oNotebook.append_page(self.pageOptions(), Gtk.Label(_('Options')))
        self.oNotebook.append_page(self.pageSupport(), Gtk.Label(_('Support')))
        self.oNotebook.append_page(self.pageAbout(), Gtk.Label(_('About')))
        oContentArea = self.get_content_area()
        oContentArea.set_property('vexpand', True)
        oContentArea.add(self.oNotebook)
        self.oButtonConnect = self.get_widget_for_response(100)
        self.oButtonApply = self.get_widget_for_response(Gtk.ResponseType.APPLY)
        self.lstDicts = [{'Host': 'imap.gmail.com', 'Port': '993', 'Login': '', 'Passwd': '', 'Folders': 'INBOX'}]
        self.set_keep_above(True)
        self.show_all()
        self.bInit = True
        self.nIndex = 0

    def onResponse(self, oWidget, nResponse):

        if nResponse == 100:

            self.oNotebook.set_current_page(0)
            self.oListStore.clear()
            self.getFolderList(True)
            self.updateUI()

    def getFolderList(self, bAutoselect):

        try:

            oImap = None

            try:

                oImap = imaplib.IMAP4_SSL(self.EntryHost.get_text(), int(self.EntryPort.get_text()))

            except Exception:

                oImap = imaplib.IMAP4(self.EntryHost.get_text(), int(self.EntryPort.get_text()))
                oImap.starttls()

            oImap.login(self.EntryLogin.get_text(), self.EntryPassword.get_text())

            for f in oImap.list()[1]:

                flags, b, c = utf7dec(f).partition(' ')
                separator, b, strName = c.partition(' ')
                strName = strName.replace('"', '').replace('/ ', '')

                if strName != '[Gmail]' and 'All Mail' not in strName:
                    self.oListStore.append([strName, strName.replace('[Gmail]/', ''), strName.upper() == 'INBOX' if bAutoselect else False])

            oImap.logout()

        except (imaplib.IMAP4.error, socketerror) as oError:

            oDlg = Gtk.MessageDialog(self, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, '')

            strError = str(oError)

            if strError.startswith("b'"):
                strError = strError[1:]

            if 'https://support.google.com/mail/accounts/answer/78754' in strError:

                oDlg.set_markup( _('Please visit the following link and enable access for less secure apps:') + '\n\n<a href="https://www.google.com/settings/security/lesssecureapps">https://www.google.com/settings/security/lesssecureapps</a>')
                oDlg.set_property('message_type', Gtk.MessageType.INFO)
                oDlg.set_title(_('Access blocked by Google'))

            else:

                oDlg.set_property('text', _('Failed to connect to mail account. The returned error was:') + '\n\n' + strError)
                oDlg.set_title(_('Connection failure'))

            oDlg.run()
            oDlg.destroy()

    def initConfig(self):

        self.nMaxCount = g_oSettings.get_int('max-item-count')
        self.bEnableNotifications = g_oSettings.get_boolean('enable-notifications')
        self.bPlaySound = g_oSettings.get_boolean('enable-sound')
        self.bHideCount = g_oSettings.get_boolean('hide-messages-count')
        self.strCommand = g_oSettings.get_string('exec-on-receive')
        self.strCustomSound = g_oSettings.get_string('custom-sound')
        self.bMergeConversation = g_oSettings.get_boolean('merge-messages')
        self.nMessageAction = g_oSettings.get_enum('message-action')
        self.dctURLs = {}
        self.dctURLs['Home'] = g_oSettings.get_string('home')
        self.dctURLs['Compose'] = g_oSettings.get_string('compose')
        self.dctURLs['Inbox'] = g_oSettings.get_string('inbox')
        self.dctURLs['Sent'] = g_oSettings.get_string('sent')

    def pageAccounts(self):

        acclabel = Gtk.Label(xalign=0, hexpand=True)
        acclabel.set_markup('<b>'+_('Choose an account')+'</b>')
        self.sb = Gtk.SpinButton.new_with_range(1, 1, 1)
        self.sb.set_numeric(True)
        self.sb.set_update_policy(Gtk.SpinButtonUpdatePolicy.IF_VALID)
        self.sb.connect('value-changed', self.onAccountChanged)
        self.addbtn = Gtk.Button.new_with_label(_('Add'))
        self.addbtn.connect('clicked', self.onAddAccount)
        self.rmbtn = Gtk.Button.new_with_label(_('Remove'))
        self.rmbtn.connect('clicked', self.onRemoveAccount)
        accbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5, hexpand=True)
        accbox.pack_start(self.sb, True, True, 0)
        accbox.pack_end(self.rmbtn, False, False, 0)
        accbox.pack_end(self.addbtn, False, False, 0)
        self.EntryHost = Gtk.Entry(hexpand=True)
        self.EntryHost.connect('changed', lambda w: self.updateUI())
        self.EntryPort = Gtk.Entry(hexpand=True)
        self.EntryPort.connect('changed', lambda w: self.updateUI())
        self.EntryLogin = Gtk.Entry(hexpand=True)
        self.EntryLogin.connect('changed', lambda w: self.updateUI())
        self.EntryPassword = Gtk.Entry(visibility=False, caps_lock_warning=True, hexpand=True)
        self.EntryPassword.connect('changed', lambda w: self.updateUI())
        srvlabel = Gtk.Label(xalign=0, margin_top=5, hexpand=True)
        srvlabel.set_markup('<b>'+_('Server data')+'</b>')
        infolabel = Gtk.Label(xalign=0, margin_top=5, hexpand=True)
        infolabel.set_markup('<b>'+_('Account data')+'</b>')
        self.oListStore = Gtk.ListStore(str, str, bool)
        oTreeView = Gtk.TreeView(self.oListStore, headers_visible=False, activate_on_single_click=True, margin_left=5, margin_top=5, margin_right=5, margin_bottom=5)
        oTreeView.connect('row-activated', self.onFolderActivated)
        oTreeViewColumnBool = Gtk.TreeViewColumn('bool', Gtk.CellRendererToggle(), active=2)
        oTreeViewColumnBool.get_cells()[0].set_property('xalign', 1.0)
        oTreeView.append_column(Gtk.TreeViewColumn('folder', Gtk.CellRendererText(), text=1))
        oTreeView.append_column(oTreeViewColumnBool)
        oFrame = Gtk.ScrolledWindow(shadow_type=Gtk.ShadowType.IN, hexpand=True, vexpand=True)
        oFrame.add(oTreeView)
        oGrid = Gtk.Grid(row_spacing=5, column_spacing=10, vexpand=True)
        oGrid.attach(srvlabel, 0, 0, 2, 1)
        oGrid.attach(Gtk.Label(_('Host:'), xalign=0), 0, 1, 1, 1)
        oGrid.attach(self.EntryHost, 1, 1, 1, 1)
        oGrid.attach(Gtk.Label(_('Port:'), xalign=0), 0, 2, 1, 1)
        oGrid.attach(self.EntryPort, 1, 2, 1, 1)
        oGrid.attach(infolabel, 0, 3, 2, 1)
        oGrid.attach(Gtk.Label(_('Login:'), xalign=0), 0, 4, 1, 1)
        oGrid.attach(self.EntryLogin, 1, 4, 1, 1)
        oGrid.attach(Gtk.Label(_('Password:'), xalign=0), 0, 5, 1, 1)
        oGrid.attach(self.EntryPassword, 1, 5, 1, 1)
        oGrid.attach(Gtk.Label(_('Folders:'), xalign=0), 0, 6, 1, 1)
        oGrid.attach(oFrame, 1, 6, 1, 1)
        page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, border_width=10, vexpand=True)
        page.add(acclabel)
        page.add(accbox)
        page.add(oGrid)

        return page

    def pageLinks(self):

        self.oEntryHome = ComboEntry(self.dctURLs['Home'], 'home', hexpand=True)
        self.oEntryCompose = ComboEntry(self.dctURLs['Compose'], 'compose', hexpand=True)
        self.oEntryInbox = ComboEntry(self.dctURLs['Inbox'], 'inbox', hexpand=True)
        self.oEntrySent = ComboEntry(self.dctURLs['Sent'], 'sent', hexpand=True)
        oGrid = Gtk.Grid(row_spacing=5, column_spacing=10)
        oGrid.attach(Gtk.Label(_('Home:'), xalign=0), 0, 0, 1, 1)
        oGrid.attach(self.oEntryHome, 1, 0, 1, 1)
        oGrid.attach(Gtk.Label(_('Compose:'), xalign=0), 0, 1, 1, 1)
        oGrid.attach(self.oEntryCompose, 1, 1, 1, 1)
        oGrid.attach(Gtk.Label(_('Inbox:'), xalign=0), 0, 2, 1, 1)
        oGrid.attach(self.oEntryInbox, 1, 2, 1, 1)
        oGrid.attach(Gtk.Label(_('Sent:'), xalign=0), 0, 3, 1, 1)
        oGrid.attach(self.oEntrySent, 1, 3, 1, 1)
        page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, border_width=10)
        page.add(oGrid)

        return page

    def pageOptions(self):

        self.oComboMessageAction = Gtk.ComboBoxText()
        self.oComboMessageAction.append(str(MESSAGEACTION['MARK']), _('Mark message as read'))
        self.oComboMessageAction.append(str(MESSAGEACTION['OPEN']), _('Open message in browser/Execute command'))
        self.oComboMessageAction.append(str(MESSAGEACTION['ASK']), _('Ask me what to do'))
        self.oComboMessageAction.set_active_id(str(self.nMessageAction))
        self.oSwitchMerge = Gtk.Switch(active=self.bMergeConversation, halign=Gtk.Align.END)
        self.notifyswitch = Gtk.Switch(active=self.bEnableNotifications, halign=Gtk.Align.END)
        self.sndswitch = Gtk.Switch(active=self.bPlaySound, halign=Gtk.Align.END)
        self.sndswitch.connect('notify::active', self.onSoundSwitchActivate)
        self.hcswitch = Gtk.Switch(active=self.bHideCount, halign=Gtk.Align.END)
        self.commandchooser = FileChooserButtonEx(self.strCommand)
        self.sndchooser = FileChooserButtonEx(self.strCustomSound)
        oGrid = Gtk.Grid(row_spacing=5, column_spacing=10)
        oGrid.attach(Gtk.Label(_('Enable notifications:'), xalign=0), 0, 0, 1, 1)
        oGrid.attach(self.notifyswitch, 1, 0, 1, 1)
        oGrid.attach(Gtk.Label(_('Play sound on messages receive:'), xalign=0), 0, 1, 1, 1)
        oGrid.attach(self.sndswitch, 1, 1, 1, 1)
        oGrid.attach(Gtk.Label(_('Merge messages from the same conversation:'), xalign=0), 0, 2, 1, 1)
        oGrid.attach(self.oSwitchMerge, 1, 2, 1, 1)
        oGrid.attach(Gtk.Label(_('Hide count when it is zero:'), xalign=0), 0, 3, 1, 1)
        oGrid.attach(self.hcswitch, 1, 3, 1, 1)
        oGrid.attach(Gtk.Label(_('When a message is activated:'), xalign=0), 0, 4, 1, 1)
        oGrid.attach(self.oComboMessageAction, 1, 4, 1, 1)
        commandbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        commandbox.add(Gtk.Label(_('Execute this command on messages receive:'), xalign=0))
        commandbox.pack_end(self.commandchooser, True, True, 0)

        if self.commandchooser.get_allocated_width() < 180:
            self.commandchooser.set_size_request(180, 0)

        self.sndbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10, sensitive=self.bPlaySound)
        self.sndbox.add(Gtk.Label(_('Custom sound to play:'), xalign=0))
        self.sndbox.pack_end(self.sndchooser, True, True, 0)

        if self.sndchooser.get_allocated_width() < 180:
            self.sndchooser.set_size_request(180, 0)

        page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, border_width=10)
        page.add(oGrid)
        page.add(commandbox)
        page.add(self.sndbox)

        return page

    def pageSupport(self):

        oGrid = Gtk.Grid(border_width=10, row_spacing=2)
        oGrid.attach(Gtk.Label(_('Report a bug/Request a feature'), xalign=0), 0, 0, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://bugs.launchpad.net/unity-mail/+filebug">https://bugs.launchpad.net/unity-mail/+filebug</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 1, 1, 1)
        oGrid.attach(Gtk.Label(_('Ask a question'), xalign=0), 0, 2, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://answers.launchpad.net/unity-mail/+addquestion">https://answers.launchpad.net/unity-mail/+addquestion</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 3, 1, 1)
        oGrid.attach(Gtk.Label(_('Help translate'), xalign=0), 0, 4, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://translations.launchpad.net/unity-mail/trunk">https://translations.launchpad.net/unity-mail/trunk</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 5, 1, 1)
        oGrid.attach(Gtk.Label(_('Project page'), xalign=0), 0, 6, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://launchpad.net/unity-mail">https://launchpad.net/unity-mail</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 7, 1, 1)
        oGrid.attach(Gtk.Label(_('Source code'), xalign=0), 0, 8, 1, 1)
        oGrid.attach(Gtk.Label('<a href="http://bazaar.launchpad.net/~robert-tari/unity-mail/trunk/files">http://bazaar.launchpad.net/~robert-tari/unity-mail/trunk/files</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 9, 1, 1)
        oGrid.attach(Gtk.Label(_('Repository'), xalign=0), 0, 10, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://launchpad.net/~robert-tari/+archive/ubuntu/main">https://launchpad.net/~robert-tari/+archive/ubuntu/main</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 11, 1, 1)
        oGrid.attach(Gtk.Label(_('Home page'), xalign=0), 0, 12, 1, 1)
        oGrid.attach(Gtk.Label('<a href="https://tari.in/www/software/unitymail/">https://tari.in/www/software/unitymail/</a>', xalign=0, use_markup=True, margin_bottom=5), 0, 13, 1, 1)

        return oGrid

    def pageAbout(self):

        oBox = Gtk.Box()
        oAboutDialog = Gtk.AboutDialog()
        oAboutDialog.set_license_type(Gtk.License.GPL_3_0)
        oAboutDialog.set_program_name('Unity Mail')
        oAboutDialog.set_copyright('Robert Tari 2016-2017')
        oAboutDialog.set_comments(_('Mail notifications and counter for Unity/MATE/Xfce/LXDE/etc.'))
        oAboutDialog.set_authors(['Dmitry Shachnev &lt;mitya57@gmail.com&gt;', 'Robert Tari &lt;robert.tari@gmail.com&gt;'])
        oAboutDialog.set_translator_credits(_('translator-credits'))
        oAboutDialog.set_version(APPVERSION)
        oAboutDialog.set_website('https://tari.in/www/software/unitymail/')
        oAboutDialog.set_website_label('https://tari.in/www/software/unitymail/')
        oAboutDialog.set_logo(GdkPixbuf.Pixbuf().new_from_file('/usr/share/icons/hicolor/scalable/apps/unity-mail.svg'))
        oAboutDialog.get_content_area().reparent(oBox)
        oAboutDialog.get_content_area().set_hexpand(True)

        lstChildren = oAboutDialog.action_area.get_children()

        for oWidget in lstChildren:

            if (isinstance(oWidget, Gtk.Button) and not isinstance(oWidget, Gtk.ToggleButton)) or (isinstance(oWidget, Gtk.ToggleButton) and len(lstChildren) == 3 and oWidget == lstChildren[1]):

                oWidget.set_property('no-show-all', True)
                oWidget.set_property('visible', False)

        return oBox

    def onFolderActivated(self, oView, nRow, oColumn):

        self.oListStore[nRow][2] = not self.oListStore[nRow][2]
        self.updateUI()

    def updateUI(self):

        bHasFolderSelection = [oRow for oRow in self.oListStore if oRow[2]]
        bHasAccountData = all([oWidget.get_text() for oWidget in [self.EntryHost, self.EntryPort, self.EntryLogin, self.EntryPassword]])
        bHasMultipleAccounts = len(self.lstDicts) > 1

        self.oButtonConnect.set_sensitive(bHasAccountData)
        self.oButtonApply.set_sensitive(bHasFolderSelection and bHasAccountData)
        self.rmbtn.set_sensitive(bHasMultipleAccounts)
        self.addbtn.set_sensitive(bHasFolderSelection and bHasAccountData)
        self.sb.set_sensitive(bHasFolderSelection and bHasAccountData and bHasMultipleAccounts)

    def run(self):

        if not self.lstDicts[0]['Passwd']:
            self.updateEntries()

        self.updateUI()
        Gtk.main()

    def saveAllSettings(self):

        g_oSettings.set_int('max-item-count', self.nMaxCount)
        g_oSettings.set_boolean('enable-notifications', self.notifyswitch.get_active())
        g_oSettings.set_boolean('enable-sound', self.sndswitch.get_active())
        g_oSettings.set_boolean('hide-messages-count', self.hcswitch.get_active())
        g_oSettings.set_string('exec-on-receive', self.commandchooser.getFilename())
        g_oSettings.set_string('custom-sound', self.sndchooser.getFilename())
        g_oSettings.set_boolean('merge-messages', self.oSwitchMerge.get_active())
        g_oSettings.set_enum('message-action', int(self.oComboMessageAction.get_active_id()))

        for strURL, oEntry in (('home', self.oEntryHome), ('compose', self.oEntryCompose), ('inbox', self.oEntryInbox), ('sent', self.oEntrySent)):
            g_oSettings.set_string(strURL, oEntry.getText())

    def onAddAccount(self, btn):

        self.updateAccounts()
        self.lstDicts.append({'Host': 'imap.gmail.com', 'Port': '993', 'Login': '', 'Passwd': '', 'Folders': 'INBOX'})
        self.sb.set_range(1, len(self.lstDicts))
        self.sb.set_value(len(self.lstDicts))
        self.updateUI()

    def onRemoveAccount(self, btn):

        self.updateAccounts()
        index = self.sb.get_value_as_int()-1

        del self.lstDicts[index]

        self.bInit = False
        self.sb.set_range(1, len(self.lstDicts))
        self.bInit = True
        self.updateEntries()
        self.updateUI()

        if index+1 > len(self.lstDicts):
            self.sb.set_value(index)

        self.updateUI()

    def setAccounts(self, lstDicts):

        self.bInit = False
        self.lstDicts = [dct for dct in lstDicts]
        self.nIndex = 0
        self.sb.set_range(1, len(lstDicts))
        self.updateEntries()
        self.updateUI()
        self.bInit = True

    def onAccountChanged(self, sb):

        self.updateAccounts()
        self.nIndex = self.sb.get_value_as_int() - 1
        self.updateEntries()
        self.updateUI()

    def onSoundSwitchActivate(self, sndswitch, param):

        self.sndbox.set_sensitive(sndswitch.get_active())

    def updateEntries(self):

        if self.lstDicts:

            nIndex = self.sb.get_value_as_int() - 1
            self.EntryHost.set_text(self.lstDicts[nIndex]['Host'])
            self.EntryPort.set_text(str(self.lstDicts[nIndex]['Port']))
            self.EntryLogin.set_text(self.lstDicts[nIndex]['Login'])
            self.EntryPassword.set_text(self.lstDicts[nIndex]['Passwd'])

            self.oListStore.clear()

            if self.lstDicts[nIndex]['Passwd']:

                self.getFolderList(False)

                lstFolders = self.lstDicts[nIndex]['Folders'].split('\t')

                for oRow in self.oListStore:
                    oRow[2] = oRow[0] in lstFolders

    def updateAccounts(self):

        if self.bInit:

            self.lstDicts[self.nIndex]['Host'] = self.EntryHost.get_text()

            if self.EntryPort.get_text():
                self.lstDicts[self.nIndex]['Port'] = self.EntryPort.get_text()
            else:
                self.lstDicts[self.nIndex]['Port'] = '993'

            self.lstDicts[self.nIndex]['Login'] = self.EntryLogin.get_text()
            self.lstDicts[self.nIndex]['Passwd'] = self.EntryPassword.get_text()
            self.lstDicts[self.nIndex]['Folders'] = '\t'.join([oRow[0] for oRow in self.oListStore if oRow[2]])
