/** Helper: decode a CMD_EVENT command and dispatch it to our EventHandler (if any). */
  protected void handleEvent(ArrayList<ReplyLine> events) {
    if (handler == null) return;

    for (Iterator<ReplyLine> i = events.iterator(); i.hasNext(); ) {
      ReplyLine line = i.next();
      int idx = line.msg.indexOf(' ');
      String tp = line.msg.substring(0, idx).toUpperCase();
      String rest = line.msg.substring(idx + 1);
      if (tp.equals("CIRC")) {
        List<String> lst = Bytes.splitStr(null, rest);
        handler.circuitStatus(
            lst.get(1),
            lst.get(0),
            lst.get(1).equals("LAUNCHED") || lst.size() < 2 ? "" : lst.get(2));
      } else if (tp.equals("STREAM")) {
        List<String> lst = Bytes.splitStr(null, rest);
        handler.streamStatus(lst.get(1), lst.get(0), lst.get(3));
        // XXXX circID.
      } else if (tp.equals("ORCONN")) {
        List<String> lst = Bytes.splitStr(null, rest);
        handler.orConnStatus(lst.get(1), lst.get(0));
      } else if (tp.equals("BW")) {
        List<String> lst = Bytes.splitStr(null, rest);
        handler.bandwidthUsed(Integer.parseInt(lst.get(0)), Integer.parseInt(lst.get(1)));
      } else if (tp.equals("NEWDESC")) {
        List<String> lst = Bytes.splitStr(null, rest);
        handler.newDescriptors(lst);
      } else if (tp.equals("DEBUG")
          || tp.equals("INFO")
          || tp.equals("NOTICE")
          || tp.equals("WARN")
          || tp.equals("ERR")) {
        handler.message(tp, rest);
      } else {
        handler.unrecognized(tp, rest);
      }
    }
  }