private string EnableCapabilities()
        {
            var line = new StringBuilder();

            if (_includeTags)
            {
                _includeTags = wantCapability(line, OPTION_INCLUDE_TAG);
            }
            if (_allowOfsDelta)
            {
                wantCapability(line, OPTION_OFS_DELTA);
            }

            if (wantCapability(line, OPTION_MULTI_ACK_DETAILED))
            {
                _multiAck = MultiAck.DETAILED;
            }
            else if (wantCapability(line, OPTION_MULTI_ACK))
            {
                _multiAck = MultiAck.CONTINUE;
            }
            else
            {
                _multiAck = MultiAck.OFF;
            }

            if (_thinPack)
            {
                _thinPack = wantCapability(line, OPTION_THIN_PACK);
            }
            if (wantCapability(line, OPTION_SIDE_BAND_64K))
            {
                _sideband = true;
            }
            else if (wantCapability(line, OPTION_SIDE_BAND))
            {
                _sideband = true;
            }
            return(line.ToString());
        }
        private void Negotiate(ProgressMonitor monitor)
        {
            var ackId = new MutableObjectId();
            int resultsPending = 0;
            int havesSent = 0;
            int havesSinceLastContinue = 0;
            bool receivedContinue = false;
            bool receivedAck = false;

            NegotiateBegin();
            for (; ; )
            {
                RevCommit c = _walk.next();
                if (c == null)
                {
                    goto END_SEND_HAVES;
                }

                pckOut.WriteString("have " + c.getId().Name + "\n");
                havesSent++;
                havesSinceLastContinue++;

                if ((31 & havesSent) != 0)
                {
                    continue;
                }

                if (monitor.IsCancelled)
                    throw new CancelledException();

                pckOut.End();
                resultsPending++;

                if (havesSent == 32)
                {
                    continue;
                }

                for (; ; )
                {
                    PacketLineIn.AckNackResult anr = pckIn.readACK(ackId);

                    switch (anr)
                    {
                        case PacketLineIn.AckNackResult.NAK:
                            // More have lines are necessary to compute the
                            // pack on the remote side. Keep doing that.

                            resultsPending--;
                            goto END_READ_RESULT;

                        case PacketLineIn.AckNackResult.ACK:
                            // The remote side is happy and knows exactly what
                            // to send us. There is no further negotiation and
                            // we can break out immediately.

                            _multiAck = MultiAck.OFF;
                            resultsPending = 0;
                            receivedAck = true;
                            goto END_SEND_HAVES;

                        case PacketLineIn.AckNackResult.ACK_CONTINUE:
                        case PacketLineIn.AckNackResult.ACK_COMMON:
                        case PacketLineIn.AckNackResult.ACK_READY:
                            // The server knows this commit (ackId). We don't
                            // need to send any further along its ancestry, but
                            // we need to continue to talk about other parts of
                            // our local history.

                            MarkCommon(_walk.parseAny(ackId));
                            receivedAck = true;
                            receivedContinue = true;
                            havesSinceLastContinue = 0;
                            break;
                    }

                    if (monitor.IsCancelled)
                        throw new CancelledException();
                }

            END_READ_RESULT:
                if (receivedContinue && havesSinceLastContinue > MAX_HAVES)
                {
                    break;
                }
            }

            END_SEND_HAVES:

            if (monitor.IsCancelled)
                throw new CancelledException();
            pckOut.WriteString("done\n");
            pckOut.Flush();

            if (!receivedAck)
            {
                _multiAck = MultiAck.OFF;
                resultsPending++;
            }

            while (resultsPending > 0 || _multiAck != MultiAck.OFF)
            {
                PacketLineIn.AckNackResult anr = pckIn.readACK(ackId);
                resultsPending--;

                switch (anr)
                {
                    case PacketLineIn.AckNackResult.NAK:
                        // A NAK is a response to an end we queued earlier
                        // we eat it and look for another ACK/NAK message.
                        //
                        break;

                    case PacketLineIn.AckNackResult.ACK:
                        // A solitary ACK at this point means the remote won't
                        // speak anymore, but is going to send us a pack now.
                        //
                        goto END_READ_RESULT_2;

                    case PacketLineIn.AckNackResult.ACK_CONTINUE:
                    case PacketLineIn.AckNackResult.ACK_COMMON:
                    case PacketLineIn.AckNackResult.ACK_READY:
                        // We will expect a normal ACK to break out of the loop.
                        //
                        _multiAck = MultiAck.CONTINUE;
                        break;
                }

                if (monitor.IsCancelled)
                    throw new CancelledException();
            }

            END_READ_RESULT_2:
            ;
        }
        private string EnableCapabilities()
        {
            var line = new StringBuilder();
            if (_includeTags)
                _includeTags = wantCapability(line, OPTION_INCLUDE_TAG);
            if (_allowOfsDelta)
                wantCapability(line, OPTION_OFS_DELTA);

            if (wantCapability(line, OPTION_MULTI_ACK_DETAILED))
                _multiAck = MultiAck.DETAILED;
            else if (wantCapability(line, OPTION_MULTI_ACK))
                _multiAck = MultiAck.CONTINUE;
            else
                _multiAck = MultiAck.OFF;

            if (_thinPack)
                _thinPack = wantCapability(line, OPTION_THIN_PACK);
            if (wantCapability(line, OPTION_SIDE_BAND_64K))
                _sideband = true;
            else if (wantCapability(line, OPTION_SIDE_BAND))
                _sideband = true;
            return line.ToString();
        }
        private void Negotiate(ProgressMonitor monitor)
        {
            var  ackId                  = new MutableObjectId();
            int  resultsPending         = 0;
            int  havesSent              = 0;
            int  havesSinceLastContinue = 0;
            bool receivedContinue       = false;
            bool receivedAck            = false;

            NegotiateBegin();
            for (; ;)
            {
                RevCommit c = _walk.next();
                if (c == null)
                {
                    goto END_SEND_HAVES;
                }

                pckOut.WriteString("have " + c.getId().Name + "\n");
                havesSent++;
                havesSinceLastContinue++;

                if ((31 & havesSent) != 0)
                {
                    // We group the have lines into blocks of 32, each marked
                    // with a flush (aka end). This one is within a block so
                    // continue with another have line.
                    //
                    continue;
                }

                if (monitor.IsCancelled)
                {
                    throw new CancelledException();
                }

                pckOut.End();
                resultsPending++; // Each end will cause a result to come back.

                if (havesSent == 32)
                {
                    // On the first block we race ahead and try to send
                    // more of the second block while waiting for the
                    // remote to respond to our first block request.
                    // This keeps us one block ahead of the peer.
                    //
                    continue;
                }

                for (; ;)
                {
                    PacketLineIn.AckNackResult anr = pckIn.readACK(ackId);

                    switch (anr)
                    {
                    case PacketLineIn.AckNackResult.NAK:
                        // More have lines are necessary to compute the
                        // pack on the remote side. Keep doing that.

                        resultsPending--;
                        goto END_READ_RESULT;

                    case PacketLineIn.AckNackResult.ACK:
                        // The remote side is happy and knows exactly what
                        // to send us. There is no further negotiation and
                        // we can break out immediately.

                        _multiAck      = MultiAck.OFF;
                        resultsPending = 0;
                        receivedAck    = true;
                        goto END_SEND_HAVES;

                    case PacketLineIn.AckNackResult.ACK_CONTINUE:
                    case PacketLineIn.AckNackResult.ACK_COMMON:
                    case PacketLineIn.AckNackResult.ACK_READY:
                        // The server knows this commit (ackId). We don't
                        // need to send any further along its ancestry, but
                        // we need to continue to talk about other parts of
                        // our local history.

                        MarkCommon(_walk.parseAny(ackId));
                        receivedAck            = true;
                        receivedContinue       = true;
                        havesSinceLastContinue = 0;
                        break;
                    }


                    if (monitor.IsCancelled)
                    {
                        throw new CancelledException();
                    }
                }

END_READ_RESULT:
                if (receivedContinue && havesSinceLastContinue > MAX_HAVES)
                {
                    // Our history must be really different from the remote's.
                    // We just sent a whole slew of have lines, and it did not
                    // recognize any of them. Avoid sending our entire history
                    // to them by giving up early.
                    //
                    break;
                }
            }

END_SEND_HAVES:

            // Tell the remote side we have run out of things to talk about.
            //
            if (monitor.IsCancelled)
            {
                throw new CancelledException();
            }
            pckOut.WriteString("done\n");
            pckOut.Flush();

            if (!receivedAck)
            {
                // Apparently if we have never received an ACK earlier
                // there is one more result expected from the done we
                // just sent to the remote.
                //
                _multiAck = MultiAck.OFF;
                resultsPending++;
            }

            while (resultsPending > 0 || _multiAck != MultiAck.OFF)
            {
                PacketLineIn.AckNackResult anr = pckIn.readACK(ackId);
                resultsPending--;

                switch (anr)
                {
                case PacketLineIn.AckNackResult.NAK:
                    // A NAK is a response to an end we queued earlier
                    // we eat it and look for another ACK/NAK message.
                    //
                    break;

                case PacketLineIn.AckNackResult.ACK:
                    // A solitary ACK at this point means the remote won't
                    // speak anymore, but is going to send us a pack now.
                    //
                    goto END_READ_RESULT_2;

                case PacketLineIn.AckNackResult.ACK_CONTINUE:
                case PacketLineIn.AckNackResult.ACK_COMMON:
                case PacketLineIn.AckNackResult.ACK_READY:
                    // We will expect a normal ACK to break out of the loop.
                    //
                    _multiAck = MultiAck.CONTINUE;
                    break;
                }

                if (monitor.IsCancelled)
                {
                    throw new CancelledException();
                }
            }

END_READ_RESULT_2:
            ;
        }