SOSCoderRef SOSCoderCreate(SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInfo, CFErrorRef *error) {        
    CFAllocatorRef allocator = CFGetAllocator(peerInfo);
    
    SOSCoderRef coder = calloc(1, sizeof(struct __OpaqueSOSCoder));
    CFErrorRef localError = NULL;

    SecOTRFullIdentityRef myRef = NULL;
    SecOTRPublicIdentityRef peerRef = NULL;
    SecKeyRef privateKey = NULL;
    SecKeyRef publicKey = NULL;

    if (myPeerInfo && peerInfo) {
        privateKey = SOSFullPeerInfoCopyDeviceKey(myPeerInfo, &localError);
        require_quiet(privateKey, errOut);

        myRef = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, &localError);
        require_quiet(myRef, errOut);
        
        CFReleaseNull(privateKey);
    
        publicKey = SOSPeerInfoCopyPubKey(peerInfo);
        
        peerRef = SecOTRPublicIdentityCreateFromSecKeyRef(allocator, publicKey, &localError);
        require_quiet(peerRef, errOut);
        
        coder->sessRef = SecOTRSessionCreateFromID(allocator, myRef, peerRef);

        require(coder->sessRef, errOut);
        
        coder->waitingForDataPacket = false;
        coder->pendingResponse = NULL;
        
        CFReleaseNull(publicKey);
        CFReleaseNull(privateKey);
        CFReleaseNull(myRef);
        CFReleaseNull(peerRef);
    } else {
        secnotice("coder", "NULL Coder requested, no transport security");
    }

    SOSCoderStart(coder, NULL);

    return coder;

errOut:
    secerror("Coder create failed: %@\n", localError ? localError : (CFTypeRef)CFSTR("No local error in SOSCoderCreate"));
    secerror("Coder create failed: %@\n", error ? *error : (CFTypeRef)CFSTR("WTF NULL?"));
    CFReleaseNull(myRef);
    CFReleaseNull(peerRef);
    CFReleaseNull(publicKey);
    CFReleaseNull(privateKey);

    free(coder);
    return NULL;
}
CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error) {
    SOSDataSourceFactoryRef ds = SecItemDataSourceFactoryGetDefault();

    SOSAccountRef privateAccount = NULL;
    SOSAccountRef publicAccount = NULL;
    CFStringRef   publicKeyString = NULL;
    SecKeyRef     privateKeyRef = NULL;
    SecKeyRef     publicKeyRef = NULL;
    SecOTRFullIdentityRef privateIdentity = NULL;
    SecOTRPublicIdentityRef publicIdentity = NULL;
    CFDataRef result = NULL;
    SecOTRSessionRef ourSession = NULL;
    
    require_quiet(ds, fail);
    require_quiet(publicPeerId, fail);
    privateAccount = (privateAccountData == NULL) ? CFRetainSafe(SOSKeychainAccountGetSharedAccount()) : SOSAccountCreateFromData(kCFAllocatorDefault, privateAccountData, ds, error);
    require_quiet(privateAccount, fail);

    privateKeyRef = SOSAccountCopyDeviceKey(privateAccount, error);
    require_quiet(privateKeyRef, fail);
    CFReleaseNull(privateAccount);

    privateIdentity = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, privateKeyRef, error);
    require_quiet(privateIdentity, fail);
    CFReleaseNull(privateKeyRef);


    publicKeyString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, publicPeerId, kCFStringEncodingUTF8);
    require_quiet(publicKeyString, fail);


    publicAccount = (publicAccountData == NULL) ? CFRetainSafe(SOSKeychainAccountGetSharedAccount()) : SOSAccountCreateFromData(kCFAllocatorDefault, publicAccountData, ds, error);
    require_quiet(publicAccount, fail);

    publicKeyRef = SOSAccountCopyPublicKeyForPeer(publicAccount, publicKeyString, error);
    require_quiet(publicKeyRef, fail);
    CFReleaseNull(publicAccount);

    publicIdentity = SecOTRPublicIdentityCreateFromSecKeyRef(kCFAllocatorDefault, publicKeyRef, error);
    require_quiet(publicIdentity, fail);
    CFReleaseNull(publicKeyRef);

    ourSession = SecOTRSessionCreateFromID(kCFAllocatorDefault, privateIdentity, publicIdentity);
    
    CFMutableDataRef exportSession = CFDataCreateMutable(kCFAllocatorDefault, 0);
    SecOTRSAppendSerialization(ourSession, exportSession);

    result = exportSession;
    exportSession = NULL;

fail:
    CFReleaseNull(ourSession);
    CFReleaseNull(publicKeyString);
    CFReleaseNull(privateAccount);
    CFReleaseNull(publicAccount);
    CFReleaseNull(privateKeyRef);
    CFReleaseNull(publicKeyRef);
    CFReleaseNull(publicIdentity);
    CFReleaseNull(privateIdentity);

    return result;
}