
import re

from twisted.internet import protocol, reactor

import managesieve

class BaseClient(managesieve.ManageSieveClient):
    def __init__(self, uid, secret):
        managesieve.ManageSieveClient.__init__(self)
        self.uid = uid
        self.secret = secret

    def gotInitialCaps(self):
        assert 'STARTTLS' in self.capabilities
        d = self.startTLS()
        d.addCallback(self._startedTLS)

    def _startedTLS(self, _):
        d = self.authenticate(self.uid, self.secret)
        d.addCallback(self._authenticated)

    def _authenticated(self, (code, result)):
        self.ready()

    def ready(self):
        pass

    def done(self):
        reactor.stop()

    def error(self, failure):
        print 'error: %s' % failure.getErrorMessage()
        self.done()

class GetClient(BaseClient):
    def __init__(self, uid, secret, name):
        BaseClient.__init__(self, uid, secret)
        self.name = name

    def ready(self):
        d = self.getScript(self.name)
        d.addCallbacks(self._gotScript, self.error)

    def _gotScript(self, script):
        print script
        self.done()

class PutClient(BaseClient):
    def __init__(self, uid, secret, name, script):
        BaseClient.__init__(self, uid, secret)
        self.name = name
        self.script = script

    def ready(self):
        d = self.putScript(self.name, self.script)
        d.addCallbacks(self._putScript, self.error)

    def _putScript(self, code):
        print code
        self.done()

class ListClient(BaseClient):
    def ready(self):
        d = self.listScripts()
        d.addCallbacks(self._gotScriptList, self.error)

    def _gotScriptList(self, (scripts, active)):
        for script in scripts:
            if script == active:
                print '%s*' % script
            else:
                print script

        self.done()

class DeleteClient(BaseClient):
    def __init__(self, uid, secret, name):
        BaseClient.__init__(self, uid, secret)
        self.name = name

    def ready(self):
        d = self.deleteScript(self.name)
        d.addCallbacks(self._scriptDeleted, self.error)

    def _scriptDeleted(self, code):
        print code
        self.done()

class SetActiveClient(BaseClient):
    def __init__(self, uid, secret, name):
        BaseClient.__init__(self, uid, secret)
        self.name = name

    def ready(self):
        d = self.setActive(self.name)
        d.addCallbacks(self._scriptDeleted, self.error)

    def _scriptDeleted(self, code):
        print code
        self.done()

def list():
    return ListClient, ()

def get(name):
    return GetClient, (name,)

def put(name, path):
    script = file(path).read()
    return PutClient, (name, script)

def delete(name):
    return DeleteClient, (name,)

def setactive(name):
    return SetActiveClient, (name,)

def read_config(path):
    match = re.match('(?:username: )?([^@]+)@(.*)\n(?:password: )?(.*)',
        file(path).read())

    if not match:
        raise ValueError("couldn't read config file")

    return match.groups()

def usage(s):
    print >>sys.stderr, 'Usage:'
    print >>sys.stderr
    print >>sys.stderr, s.rstrip()
    print >>sys.stderr
    print >>sys.stderr, 'Auth file is in the format:'
    print >>sys.stderr
    print >>sys.stderr, '  username: user@example.org'
    print >>sys.stderr, '  password: secret'

def main(args):
    commands = {
        'list': (),
        'get': ('name',),
        'put': ('name', 'file'),
        'delete': ('name',),
        'setactive': ('name',),
    }

    if len(args) < 3 or args[2] not in commands:
        s = ''.join([
            '  %s config %s %s\n' % (args[0], command, ' '.join(names))
            for command, names in commands.iteritems()])
        usage(s)
        return 1

    configfile, command, rest = args[1], args[2], args[3:]

    if len(rest) != len(commands[command]):
        usage('  %s config %s %s' %
            (args[0], command, ' '.join(commands[command])))
        return 1

    proto_cls, proto_args = globals()[command](*rest)
    uid, host, secret = read_config(configfile)

    class Protocol(proto_cls):
        def __init__(self):
            proto_cls.__init__(self, uid, secret, *proto_args)

    c = protocol.ClientCreator(reactor, Protocol)
    c.connectTCP(host, managesieve.PORT)
    reactor.run()

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

