private void handleMuteIq(MuteIq muteIq) {
    Boolean doMute = muteIq.getMute();
    String jid = muteIq.getJid();

    if (doMute == null || StringUtils.isNullOrEmpty(jid)) return;

    String from = muteIq.getFrom();
    JitsiMeetConference conference = getConferenceForMucJid(from);
    if (conference == null) {
      logger.debug("Mute error: room not found for JID: " + from);
      return;
    }

    IQ result;

    if (conference.handleMuteRequest(muteIq.getFrom(), jid, doMute)) {
      result = IQ.createResultIQ(muteIq);

      if (!muteIq.getFrom().equals(jid)) {
        MuteIq muteStatusUpdate = new MuteIq();
        muteStatusUpdate.setType(IQ.Type.SET);
        muteStatusUpdate.setTo(jid);

        muteStatusUpdate.setMute(doMute);

        smackXmpp.getXmppConnection().sendPacket(muteStatusUpdate);
      }
    } else {
      result =
          IQ.createErrorResponse(muteIq, new XMPPError(XMPPError.Condition.interna_server_error));
    }

    smackXmpp.getXmppConnection().sendPacket(result);
  }
  private void handleRayoIQ(RayoIqProvider.DialIq dialIq) {
    String from = dialIq.getFrom();

    JitsiMeetConference conference = getConferenceForMucJid(from);

    if (conference == null) {
      logger.debug("Mute error: room not found for JID: " + from);
      return;
    }

    ChatRoomMemberRole role = conference.getRoleForMucJid(from);

    if (role == null) {
      // Only room members are allowed to send requests
      IQ error = createErrorResponse(dialIq, new XMPPError(XMPPError.Condition.forbidden));

      smackXmpp.getXmppConnection().sendPacket(error);

      return;
    }

    if (ChatRoomMemberRole.MODERATOR.compareTo(role) < 0) {
      // Moderator permission is required
      IQ error = createErrorResponse(dialIq, new XMPPError(XMPPError.Condition.not_allowed));

      smackXmpp.getXmppConnection().sendPacket(error);

      return;
    }

    // Check if Jigasi is available
    String jigasiJid = conference.getServices().getSipGateway();

    if (StringUtils.isNullOrEmpty(jigasiJid)) {
      // Not available
      IQ error =
          createErrorResponse(dialIq, new XMPPError(XMPPError.Condition.service_unavailable));

      smackXmpp.getXmppConnection().sendPacket(error);

      return;
    }

    // Redirect original request to Jigasi component
    String originalPacketId = dialIq.getPacketID();

    dialIq.setFrom(null);
    dialIq.setTo(jigasiJid);
    dialIq.setPacketID(IQ.nextID());

    IQ reply = (IQ) smackXmpp.getXmppConnection().sendPacketAndGetReply(dialIq);

    // Send Jigasi response back to the client
    reply.setFrom(null);
    reply.setTo(from);
    reply.setPacketID(originalPacketId);

    smackXmpp.getXmppConnection().sendPacket(reply);
  }
  private void handleColibriIq(ColibriConferenceIQ colibriIQ) {
    ColibriConferenceIQ.Recording recording = colibriIQ.getRecording();
    String from = colibriIQ.getFrom();
    JitsiMeetConference conference = getConferenceForMucJid(colibriIQ.getFrom());
    if (conference == null) {
      logger.debug("Room not found for JID: " + from);
      return;
    }

    JitsiMeetRecording recordingHandler = conference.getRecording();
    if (recordingHandler == null) {
      logger.error("JitsiMeetRecording is null for iq: " + colibriIQ.toXML());

      // Internal server error
      smackXmpp
          .getXmppConnection()
          .sendPacket(
              IQ.createErrorResponse(
                  colibriIQ, new XMPPError(XMPPError.Condition.interna_server_error)));
      return;
    }

    State recordingState =
        recordingHandler.modifyRecordingState(
            colibriIQ.getFrom(),
            recording.getToken(),
            recording.getState(),
            recording.getDirectory(),
            colibriIQ.getTo());

    ColibriConferenceIQ response = new ColibriConferenceIQ();

    response.setType(IQ.Type.RESULT);
    response.setPacketID(colibriIQ.getPacketID());
    response.setTo(colibriIQ.getFrom());
    response.setFrom(colibriIQ.getTo());
    response.setName(colibriIQ.getName());

    response.setRecording(new ColibriConferenceIQ.Recording(recordingState));

    smackXmpp.getXmppConnection().sendPacket(response);
  }
  /**
   * FIXME: replace with IQ.createErrorResponse Prosody does not allow to include request body in
   * error response. Replace this method with IQ.createErrorResponse once fixed.
   */
  private IQ createErrorResponse(IQ request, XMPPError error) {
    IQ.Type requestType = request.getType();
    if (!(requestType == IQ.Type.GET || requestType == IQ.Type.SET)) {
      throw new IllegalArgumentException(
          "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
    }

    final IQ result =
        new IQ() {
          @Override
          public String getChildElementXML() {
            return "";
          }
        };
    result.setType(IQ.Type.ERROR);
    result.setPacketID(request.getPacketID());
    result.setFrom(request.getTo());
    result.setTo(request.getFrom());
    result.setError(error);
    return result;
  }