# Path: src/petmail/errors.py
# class CommandError(Exception):
#     def __init__(self, msg):
#         self.msg = msg
# 
# class ContactNotReadyError(Exception):
#     pass
# 
# Path: src/petmail/mailbox/channel.py
# def parse_msgC(msgC):
# def find_channel_from_CIDToken(db, CIDToken):
# def find_channel_from_CIDBox(db, CIDBox):
# def build_channel_keylist(db, known_cid):
# def filter_on_known_channel_pubkey(keylist, known_channel_pubkey_s):
# def find_channel_list(db, CIDToken, CIDBox):
# def decrypt_msgD(msgD, keylist):
# def decrypt_CIDBox(CIDKey, CIDBox):
# def check_msgE(msgE, pubkey2_s, sender_verfkey_s, highest_seqnum):
# def validate_msgC(CIDKey, channel_pubkey,
#                   seqnum_from_msgE, CIDBox, CIDToken, msgD):
# def process_msgC(db, msgC):
# def build_CIDToken(CIDKey, seqnum):
#     def __init__(self, db, cid):
#     def send(self, payload):
#     def createMsgC(self, payload):
#     def createTransports(self):
#     def make_transport(self, trecord):
# class OutboundChannel:
# 
# Path: src/petmail/mailbox/retrieval.py
# class LocalRetriever(service.MultiService):
# class NotListResponseError(Exception):
# class WrongPubkeyError(Exception):
# class NotFetchResponseError(Exception):
# class WrongFetchTokenError(Exception):
# class HTTPRetriever(service.MultiService):
#     def __init__(self, descriptor, got_msgC, server):
# def encrypt_list_request(serverpubkey, RT, offset=0, now=None, tmppriv=None):
# def decrypt_list_entry(boxed, symkey, tmppub):
# def decrypt_fetch_response(symkey, fetch_token, boxed):
#     def __init__(self, descriptor, got_msgC):
#     def start_source(self):
#     def handle_SSE(self, name, data):
#         def _start_polling_again(_):
#     def fetch(self, _):
#         def _fetched(page):
#         def _delete(_):
#         def _fetch_more(_):
# ENABLE_POLLING = False
# 
# Path: src/petmail/eventual.py
# def eventually(cb, *args, **kwargs):
#     """This is the eventual-send operation, used as a plan-coordination
#     primitive. The callable will be invoked (with args and kwargs) in a later
#     reactor turn. Doing 'eventually(a); eventually(b)' guarantees that a will
#     be called before b.
# 
#     Any exceptions that occur in the callable will be logged with log.err().
#     If you really want to ignore them, be sure to provide a callable that
#     catches those exceptions.
# 
#     This function returns None. If you care to know when the callable was
#     run, be sure to provide a callable that notifies somebody.
#     """
#     _theSimpleQueue.append(cb, args, kwargs)


import os.path, json, time
from twisted.application import service
from twisted.python import log
from nacl.public import PrivateKey
from nacl.signing import SigningKey, VerifyKey
from nacl.encoding import HexEncoder as Hex
from . import invitation, rrid
from .errors import CommandError, ContactNotReadyError
from .mailbox import channel, retrieval
from .eventual import eventually

    def command_invite(self, petname, maybe_code=None, reqid=None,
                       override_transports=None, offer_mailbox=False,
                       accept_mailbox_offer=False,
                       _debug_when_done=None):
        #if offer_mailbox:
        #    code = "mailbox-" + code

        if maybe_code:
            count = self.db.execute("SELECT COUNT(*) FROM addressbook"
                                    " WHERE invitation_state != ?"
                                    "  AND invitation_code=?",
                                    (invitation.INVITE_COMPLETE, maybe_code)
                                    ).fetchone()[0]
            if count:
                raise CommandError("invitation code already in use")

        my_signkey = SigningKey.generate()
        channel_key = PrivateKey.generate()
        my_CID_key = os.urandom(32)

        base_transports = self.get_transports()
        if override_transports:
            base_transports = override_transports
        transports = self.individualize_transports(base_transports)

        channel = { "channel_pubkey": channel_key.public_key.encode(Hex),
                    "CID_key": my_CID_key.encode("hex"),
                    "transports": transports.values(),
                     }

# Path: src/petmail/errors.py
# class CommandError(Exception):
#     def __init__(self, msg):
#         self.msg = msg
# 
# class ContactNotReadyError(Exception):
#     pass
# 
# Path: src/petmail/mailbox/channel.py
# def parse_msgC(msgC):
# def find_channel_from_CIDToken(db, CIDToken):
# def find_channel_from_CIDBox(db, CIDBox):
# def build_channel_keylist(db, known_cid):
# def filter_on_known_channel_pubkey(keylist, known_channel_pubkey_s):
# def find_channel_list(db, CIDToken, CIDBox):
# def decrypt_msgD(msgD, keylist):
# def decrypt_CIDBox(CIDKey, CIDBox):
# def check_msgE(msgE, pubkey2_s, sender_verfkey_s, highest_seqnum):
# def validate_msgC(CIDKey, channel_pubkey,
#                   seqnum_from_msgE, CIDBox, CIDToken, msgD):
# def process_msgC(db, msgC):
# def build_CIDToken(CIDKey, seqnum):
#     def __init__(self, db, cid):
#     def send(self, payload):
#     def createMsgC(self, payload):
#     def createTransports(self):
#     def make_transport(self, trecord):
# class OutboundChannel:
# 
# Path: src/petmail/mailbox/retrieval.py
# class LocalRetriever(service.MultiService):
# class NotListResponseError(Exception):
# class WrongPubkeyError(Exception):
# class NotFetchResponseError(Exception):
# class WrongFetchTokenError(Exception):
# class HTTPRetriever(service.MultiService):
#     def __init__(self, descriptor, got_msgC, server):
# def encrypt_list_request(serverpubkey, RT, offset=0, now=None, tmppriv=None):
# def decrypt_list_entry(boxed, symkey, tmppub):
# def decrypt_fetch_response(symkey, fetch_token, boxed):
#     def __init__(self, descriptor, got_msgC):
#     def start_source(self):
#     def handle_SSE(self, name, data):
#         def _start_polling_again(_):
#     def fetch(self, _):
#         def _fetched(page):
#         def _delete(_):
#         def _fetch_more(_):
# ENABLE_POLLING = False
# 
# Path: src/petmail/eventual.py
# def eventually(cb, *args, **kwargs):
#     """This is the eventual-send operation, used as a plan-coordination
#     primitive. The callable will be invoked (with args and kwargs) in a later
#     reactor turn. Doing 'eventually(a); eventually(b)' guarantees that a will
#     be called before b.
# 
#     Any exceptions that occur in the callable will be logged with log.err().
#     If you really want to ignore them, be sure to provide a callable that
#     catches those exceptions.
# 
#     This function returns None. If you care to know when the callable was
#     run, be sure to provide a callable that notifies somebody.
#     """
#     _theSimpleQueue.append(cb, args, kwargs)


# Path: src/petmail/agent.py
import os.path, json, time
from twisted.application import service
from twisted.python import log
from nacl.public import PrivateKey
from nacl.signing import SigningKey, VerifyKey
from nacl.encoding import HexEncoder as Hex
from . import invitation, rrid
from .errors import CommandError, ContactNotReadyError
from .mailbox import channel, retrieval
from .eventual import eventually


    def command_invite(self, petname, maybe_code=None, reqid=None,
                       override_transports=None, offer_mailbox=False,
                       accept_mailbox_offer=False,
                       _debug_when_done=None):
        #if offer_mailbox:
        #    code = "mailbox-" + code

        if maybe_code:
            count = self.db.execute("SELECT COUNT(*) FROM addressbook"
                                    " WHERE invitation_state != ?"
                                    "  AND invitation_code=?",
                                    (invitation.INVITE_COMPLETE, maybe_code)
                                    ).fetchone()[0]
            if count:
                raise CommandError("invitation code already in use")

        my_signkey = SigningKey.generate()
        channel_key = PrivateKey.generate()
        my_CID_key = os.urandom(32)

        base_transports = self.get_transports()
        if override_transports:
            base_transports = override_transports
        transports = self.individualize_transports(base_transports)

        channel = { "channel_pubkey": channel_key.public_key.encode(Hex),
                    "CID_key": my_CID_key.encode("hex"),
                    "transports": transports.values(),
                     }

        payload = { "channel": channel }