protected Cmd ReadCommand()
        {
            lock (input) {
                Cmd c = ReadCommand0();
                if (c.Type != TorControl.Commands.Fragment &&
                    c.Type != TorControl.Commands.FragmentHeader)
                    return c;

                if (c.Type == TorControl.Commands.Fragment)
                    throw new TorControlSyntaxException("Fragment without header");

                int realType = Bytes.GetU16(c.Body, 0);
                int realLen  = Bytes.GetU32(c.Body, 2);

                Cmd outCmd = new Cmd((TorControl.Commands)realType, realLen);
                Array.Copy(c.Body, 6, outCmd.Body, 0, c.Body.Length - 6);

                int pos = c.Body.Length-6;

                while (pos < realLen) {
                    c = ReadCommand0();
                    if (c.Type != TorControl.Commands.Fragment)
                        throw new TorControlSyntaxException("Incomplete fragmented message");

                    Array.Copy(c.Body, 0, outCmd.Body, pos, c.Body.Length);
                    pos += c.Body.Length;
                }

                return outCmd;
            }
        }
        protected void HandleEvent(Cmd c)
        {
            TorControl.Event type = (TorControl.Event)Bytes.GetU16(c.Body, 0);

            switch (type) {
                case TorControl.Event.CircSatus:
                    if (this.CircuitStatus != null) {
                        CircuitStatusEventArgs args;
                        args = new CircuitStatusEventArgs(TorControl.StreamStatusNames[c.Body[2]],
                                                          Bytes.GetU32S(c.Body, 3),
                                                          Bytes.GetNulTerminatedStr(c.Body, 7));
                        CircuitStatus(this, args);
                    }
                    break;
                case TorControl.Event.StreamStatus:
                    if (this.StreamStatus != null) {
                        StreamStatusEventArgs args;
                        args = new StreamStatusEventArgs(TorControl.StreamStatusNames[c.Body[2]],
                                                         Bytes.GetU32S(c.Body, 3).ToString(),
                                                         Bytes.GetNulTerminatedStr(c.Body, 7));
                        StreamStatus(this, args);
                    }
                    break;
                case TorControl.Event.OrConnStatus:
                    if (this.OrConnStatus != null) {
                        OrConnStatusEventArgs args;
                        args = new OrConnStatusEventArgs(TorControl.ORConnStatusNames[c.Body[2]],
                                                         Bytes.GetNulTerminatedStr(c.Body, 3));
                        OrConnStatus(this, args);
                    }
                    break;
                case TorControl.Event.Bandwidth:
                    if (this.BandwidthUsed != null) {
                        BandwidthUsedEventArgs args;
                        args = new BandwidthUsedEventArgs(Bytes.GetU32(c.Body, 2),
                                                          Bytes.GetU32(c.Body, 6));
                        BandwidthUsed(this, args);
                    }
                    break;
                case TorControl.Event.NewDescriptor:
                    if (this.NewDescriptors != null) {
                        IList lst = new ArrayList();
                        Bytes.SplitStr(lst, c.Body, 2, (byte)',');
                        NewDescriptorsEventArgs args;
                        args = new NewDescriptorsEventArgs(lst);

                        NewDescriptors(this, args);
                    }
                    break;
                case TorControl.Event.MsgDebug:
                    if (this.Message != null) {
                        MessageEventArgs args;
                        args = new MessageEventArgs("DEBUG", Bytes.GetNulTerminatedStr(c.Body, 2));
                        Message(this, args);
                    }
                    break;
                case TorControl.Event.MsgInfo:
                    if (this.Message != null) {
                        MessageEventArgs args;
                        args = new MessageEventArgs("INFO", Bytes.GetNulTerminatedStr(c.Body, 2));
                        Message(this, args);
                    }
                    break;
                case TorControl.Event.MsgNotice:
                    if (this.Message != null) {
                        MessageEventArgs args;
                        args = new MessageEventArgs("NOTICE", Bytes.GetNulTerminatedStr(c.Body, 2));
                        Message(this, args);
                    }
                    break;
                case TorControl.Event.MsgWarn:
                    if (this.Message != null) {
                        MessageEventArgs args;
                        args = new MessageEventArgs("WARN", Bytes.GetNulTerminatedStr(c.Body, 2));
                        Message(this, args);
                    }
                    break;
                case TorControl.Event.MsgError:
                    if (this.Message != null) {
                        MessageEventArgs args;
                        args = new MessageEventArgs("ERR", Bytes.GetNulTerminatedStr(c.Body, 2));
                        Message(this, args);
                    }
                    break;
                default:
                    if (this.Unrecognized != null) {
                        // TODO: Check if this is practicable
                        UnrecognizedEventArgs args;
                        args = new UnrecognizedEventArgs("UNKNOWN",
                                                         Bytes.GetNulTerminatedStr(c.Body, 3));
                        Unrecognized(this, args);
                    }
                    break;
            }
        }