#!/usr/bin/env python

from obfsproxy.transports.base import BaseTransport
import obfsproxy.common.log as logging
from obfsproxy.network.buffer import Buffer

from bananaphone import rh_decoder, rh_encoder


log = logging.get_obfslogger()

class BananaphoneTransport(BaseTransport):
    
    def __init__(self, transport_config):
        pass

    @classmethod
    def setup_encoding_model(self):

        # BUG: modify bananaphone.py to
        # accept the abridged arg as boolean?
        if hasattr(self,'abridged'):
            self.abridged = '--abridged'
        else:
            # this is the only transport option which has a default value
            self.abridged = None

        if self.modelName == 'markov':
            args = [ self.corpus, self.order, self.abridged ]
        elif self.modelName == 'random':
            args = [ self.corpus ]
        else:
            log.error("BananaphoneTransport: unsupported model type")
            return

        self.encode = rh_encoder(self.encodingSpec, self.modelName, *args)
        self.decode = rh_decoder(self.encodingSpec)

    def handle_socks_args(self, args):
        if args:
            log.error("args %s" % args)

            for arg in args:
                key,value = arg.split('=')
                setattr(self, key, value)

            self.setup_encoding_model()
        else:
            log.error("BananaphoneTransport: must specify server transport options")

    @classmethod
    def setup(cls, transport_config):

        # if we are the client then we receive the transport options
        # from handle_socks_args
        if cls.initiator:
            return

        transport_options = transport_config.getServerTransportOptions()
        if transport_options:
            for key in transport_options.keys():
                setattr(cls, key, transport_options[key])
            cls.setup_encoding_model()
        else:
            log.error("BananaphoneTransport: must specify server transport options")

    @classmethod
    def get_public_options(cls, transport_options):
        """ Only tell BridgeDB about our encodingSpec
        """
        return dict(encodingSpec = transport_options['encodingSpec'])

    def handshake(self, circuit):
        self.encoder = self.encode > circuit.downstream.write
        self.decoder = self.decode > circuit.upstream.write

    def receivedDownstream(self, data, circuit):
        self.decoder.send(data.read())
        return

    def receivedUpstream(self, data, circuit):
        self.encoder.send(data.read())
        return

    @classmethod
    def register_external_mode_cli(cls, subparser):
        subparser.add_argument('--corpus', type=str, help='Corpus file of words')
        subparser.add_argument('--encoding_spec', type=str, dest='encodingSpec', help='reverse hash encoding specification')
        subparser.add_argument('--model', type=str, dest='modelName')
        subparser.add_argument('--order', type=int)
        subparser.add_argument('--abridged', action='store_true', default=False,)
        super(BananaphoneTransport, cls).register_external_mode_cli(subparser)

    @classmethod
    def validate_external_mode_cli(cls, args):
        cls.corpus       = args.corpus
        cls.encodingSpec = args.encodingSpec
        cls.modelName    = args.modelName
        cls.order        = args.order
        cls.abridged     = args.abridged
        super(BananaphoneTransport, cls).validate_external_mode_cli(args)


class BananaphoneClient(BananaphoneTransport):
    initiator = True
    pass

class BananaphoneServer(BananaphoneTransport):
    initiator = False
    pass


@@ -345,56 +345,270 @@
     
-@classmethod%0A    def setup_encoding_model(self):
+def handle_socks_args(self, args):%0A        if not args:%0A            log.error(%22BananaphoneTransport: must specify server transport options%22)%0A            return%0A%0A        for arg in args:%0A            key,value = arg.split('=')%0A            setattr(self, key, value)
 %0A%0A  
@@ -1308,268 +1308,313 @@
     
-def handle_socks_args(self, args
+@classmethod%0A    def setup(cls, transport_config
 ):%0A
+%0A
        
+ #
  if 
-args:%0A            log.error(%22args %25s%22 %25 args)%0A%0A            for arg in args:%0A                key,value = arg.split('=')%0A                setattr(self, key, value)%0A%0A            self.setup_encoding_model()%0A        else
+we are the client then we receive the transport options%0A        # from handle_socks_args%0A        if cls.initiator:%0A            return%0A%0A        transport_options = transport_config.getServerTransportOptions()%0A        if not transport_options
 :%0A  
@@ -1700,44 +1700,102 @@
 s%22)%0A
-%0A    @classmethod%0A    def setup
+            return%0A%0A        for key in transport_options.keys():%0A            setattr
 (cls,
+ key,
  tra
@@ -1805,119 +1805,143 @@
 ort_
-config):%0A%0A        # if we are the client then we receive the transport options%0A        # from handle_socks_args
+options%5Bkey%5D)%0A%0A       # BUG: modify bananaphone.py to%0A        # accept the abridged arg as boolean?%0A        if hasattr(cls,'abridged'):
 %0A   
@@ -1949,53 +1949,84 @@
     
-if
+   
  cls.
-initiator:%0A            return%0A%0A       
+abridged = '--abridged'%0A        else:%0A            # this is the only
  tra
@@ -2035,337 +2035,470 @@
 port
-_
+ 
 option
-s = transport_config.getServerTransportOptions()%0A        if transport_options:%0A            for key in transport_options.keys():%0A                setattr(cls, key, transport_options%5Bkey%5D)%0A            cls.setup_encoding_model()%0A        else:%0A            log.error(%22BananaphoneTransport: must specify server transport options%22
+ which has a default value%0A            cls.abridged = None%0A%0A        if cls.modelName == 'markov':%0A            args = %5B cls.corpus, cls.order, cls.abridged %5D%0A        elif cls.modelName == 'random':%0A            args = %5B cls.corpus %5D%0A        else:%0A            log.error(%22BananaphoneTransport: unsupported model type%22)%0A            return%0A%0A        cls.encode = rh_encoder(cls.encodingSpec, cls.modelName, *args)%0A        cls.decode = rh_decoder(cls.encodingSpec
 )%0A%0A 

Fix setup and handle_socks_args