<commit_before>/* global $, $iq, Promise, Strophe */

var logger = require("jitsi-meet-logger").getLogger(__filename);
var XMPPEvents = require("../../service/xmpp/XMPPEvents");

var AuthenticationEvents
    = require("../../service/authentication/AuthenticationEvents");

function createExpBackoffTimer(step) {
    var count = 1;
    return function (reset) {
        // Reset call
        if (reset) {
            count = 1;
            return;
        }
        // Calculate next timeout
        var timeout = Math.pow(2, count - 1);
        count += 1;
        return timeout * step;
    };
}

function Moderator(roomName, xmpp, emitter, settings) {
    this.roomName = roomName;
    this.xmppService = xmpp;
    this.getNextTimeout = createExpBackoffTimer(1000);
    this.getNextErrorTimeout = createExpBackoffTimer(1000);
    // External authentication stuff
    this.externalAuthEnabled = false;
    this.settings = settings;
    // Sip gateway can be enabled by configuring Jigasi host in config.js or
    // it will be enabled automatically if focus detects the component through
    // service discovery.
    this.sipGatewayEnabled = this.xmppService.options.hosts &&
        this.xmppService.options.hosts.call_control !== undefined;

    this.eventEmitter = emitter;

    this.connection = this.xmppService.connection;
    this.focusUserJid;
    //FIXME:
    // Message listener that talks to POPUP window
    function listener(event) {
        if (event.data && event.data.sessionId) {
            if (event.origin !== window.location.origin) {
                logger.warn("Ignoring sessionId from different origin: " +
                    event.origin);
                return;
            }
            settings.setSessionId(event.data.sessionId);
            // After popup is closed we will authenticate
        }
    }
    // Register
    if (window.addEventListener) {
        window.addEventListener("message", listener, false);
    } else {
        window.attachEvent("onmessage", listener);
    }
}

Moderator.prototype.isExternalAuthEnabled =  function () {
    return this.externalAuthEnabled;
};

Moderator.prototype.isSipGatewayEnabled =  function () {
    return this.sipGatewayEnabled;
};


Moderator.prototype.onMucMemberLeft =  function (jid) {
    logger.info("Someone left is it focus ? " + jid);
    var resource = Strophe.getResourceFromJid(jid);
    if (resource === 'focus' && !this.xmppService.sessionTerminated) {
        logger.info(
            "Focus has left the room - leaving conference");
        this.eventEmitter.emit(XMPPEvents.FOCUS_LEFT);
    }
};


Moderator.prototype.setFocusUserJid =  function (focusJid) {
    if (!this.focusUserJid) {
        this.focusUserJid = focusJid;
        logger.info("Focus jid set to:  " + this.focusUserJid);
    }
};


Moderator.prototype.getFocusUserJid =  function () {
    return this.focusUserJid;
};

Moderator.prototype.getFocusComponent =  function () {
    // Get focus component address
    var focusComponent = this.xmppService.options.hosts.focus;
    // If not specified use default:  'focus.domain'
    if (!focusComponent) {
        focusComponent = 'focus.' + this.xmppService.options.hosts.domain;
    }
    return focusComponent;
};

Moderator.prototype.createConferenceIq =  function () {
    // Generate create conference IQ
    var elem = $iq({to: this.getFocusComponent(), type: 'set'});

    // Session Id used for authentication
    var sessionId = this.settings.getSessionId();
    var machineUID = this.settings.getUserId();
    var options = this.xmppService.options;

    logger.info(
            "Session ID: " + sessionId + " machine UID: " + machineUID);

    elem.c('conference', {
        xmlns: 'http://jitsi.org/protocol/focus',
        room: this.roomName,
        'machine-uid': machineUID
    });

    if (sessionId) {
        elem.attrs({ 'session-id': sessionId});
    }
    if (options.hosts !== undefined && options.hosts.bridge !== undefined) {
        elem.c(
            'property', {
                name: 'bridge',
                value: options.hosts.bridge
            }).up();
    }
    if (options.enforcedBridge !== undefined) {
        elem.c(
            'property', {
                name: 'enforcedBridge',
                value: options.enforcedBridge
            }).up();
    }
    // Tell the focus we have Jigasi configured
    if (options.hosts !== undefined &&
        options.hosts.call_control !== undefined) {
        elem.c(
            'property', {
                name: 'call_control',
                value: options.hosts.call_control
            }).up();
    }
    if (options.channelLastN !== undefined) {
        elem.c(
            'property', {
                name: 'channelLastN',
                value: options.channelLastN
            }).up();
    }
    if (options.adaptiveLastN !== undefined) {
        elem.c(
            'property', {
                name: 'adaptiveLastN',
                value: options.adaptiveLastN
            }).up();
    }
    if (options.disableAdaptiveSimulcast !== undefined ||
        options.disableSimulcast) {
        // disableSimulcast implies disableAdaptiveSimulcast.
        var value = options.disableSimulcast ? true :
            options.disableAdaptiveSimulcast;
        elem.c(
            'property', {
                name: 'disableAdaptiveSimulcast',
                value: value
            }).up();
    }
    // TODO: re-enable once rtx is stable
    //if (options.disableRtx !== undefined) {
        elem.c(
            'property', {
                name: 'disableRtx',
                //value: options.disableRtx
                value: true
            }).up();
    //}
    if (options.openSctp !== undefined) {
        elem.c(
            'property', {
                name: 'openSctp',
                value: options.openSctp
            }).up();
    }
    if (options.startAudioMuted !== undefined)
    {
        elem.c(
            'property', {
                name: 'startAudioMuted',
                value: options.startAudioMuted
            }).up();
    }
    if (options.startVideoMuted !== undefined)
    {
        elem.c(
            'property', {
                name: 'startVideoMuted',
                value: options.startVideoMuted
            }).up();
    }

    elem.c(
        'property', {
            name: 'simulcastMode',
            value: 'rewriting'
        }).up();
    elem.up();
    return elem;
};


Moderator.prototype.parseSessionId =  function (resultIq) {
    var sessionId = $(resultIq).find('conference').attr('session-id');
    if (sessionId) {
        logger.info('Received sessionId:  ' + sessionId);
        this.settings.setSessionId(sessionId);
    }
};

Moderator.prototype.parseConfigOptions =  function (resultIq) {

    this.setFocusUserJid(
        $(resultIq).find('conference').attr('focusjid'));

    var authenticationEnabled
        = $(resultIq).find(
            '>conference>property' +
            '[name=\'authentication\'][value=\'true\']').length > 0;

    logger.info("Authentication enabled: " + authenticationEnabled);

    this.externalAuthEnabled = $(resultIq).find(
            '>conference>property' +
            '[name=\'externalAuth\'][value=\'true\']').length > 0;

    console.info(
        'External authentication enabled: ' + this.externalAuthEnabled);

    if (!this.externalAuthEnabled) {
        // We expect to receive sessionId in 'internal' authentication mode
        this.parseSessionId(resultIq);
    }

    var authIdentity = $(resultIq).find('>conference').attr('identity');

    this.eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,
        authenticationEnabled, authIdentity);

    // Check if focus has auto-detected Jigasi component(this will be also
    // included if we have passed our host from the config)
    if ($(resultIq).find(
        '>conference>property' +
        '[name=\'sipGatewayEnabled\'][value=\'true\']').length) {
        this.sipGatewayEnabled = true;
    }

    logger.info("Sip gateway enabled:  " + this.sipGatewayEnabled);
};

// FIXME We need to show the fact that we're waiting for the focus to the user
// (or that the focus is not available)
/**
 * Allocates the conference focus.
 *
 * @param {Function} callback - the function to be called back upon the
 * successful allocation of the conference focus
 */
Moderator.prototype.allocateConferenceFocus =  function (callback) {
    // Try to use focus user JID from the config
    this.setFocusUserJid(this.xmppService.options.focusUserJid);
    // Send create conference IQ
    var self = this;
    this.connection.sendIQ(
        this.createConferenceIq(),
        function (result) {
            self._allocateConferenceFocusSuccess(result, callback);
        },
        function (error) {
            self._allocateConferenceFocusError(error);
        });
    // XXX We're pressed for time here because we're beginning a complex and/or
    // lengthy conference-establishment process which supposedly involves
    // multiple RTTs. We don't have the time to wait for Strophe to decide to
    // send our IQ.
    this.connection.flush();
};

/**
 * Invoked by {@link #allocateConferenceFocus} upon its request receiving an
 * error result.
 *
 * @param error - the error result of the request that
 * {@link #allocateConferenceFocus} sent
 * @param {Function} callback - the function to be called back upon the
 * successful allocation of the conference focus
 */<commit_msg>Fix invalid call to _allocateConferenceFocusError<commit_after>/* global $, $iq, Promise, Strophe */

var logger = require("jitsi-meet-logger").getLogger(__filename);
var XMPPEvents = require("../../service/xmpp/XMPPEvents");

var AuthenticationEvents
    = require("../../service/authentication/AuthenticationEvents");

function createExpBackoffTimer(step) {
    var count = 1;
    return function (reset) {
        // Reset call
        if (reset) {
            count = 1;
            return;
        }
        // Calculate next timeout
        var timeout = Math.pow(2, count - 1);
        count += 1;
        return timeout * step;
    };
}

function Moderator(roomName, xmpp, emitter, settings) {
    this.roomName = roomName;
    this.xmppService = xmpp;
    this.getNextTimeout = createExpBackoffTimer(1000);
    this.getNextErrorTimeout = createExpBackoffTimer(1000);
    // External authentication stuff
    this.externalAuthEnabled = false;
    this.settings = settings;
    // Sip gateway can be enabled by configuring Jigasi host in config.js or
    // it will be enabled automatically if focus detects the component through
    // service discovery.
    this.sipGatewayEnabled = this.xmppService.options.hosts &&
        this.xmppService.options.hosts.call_control !== undefined;

    this.eventEmitter = emitter;

    this.connection = this.xmppService.connection;
    this.focusUserJid;
    //FIXME:
    // Message listener that talks to POPUP window
    function listener(event) {
        if (event.data && event.data.sessionId) {
            if (event.origin !== window.location.origin) {
                logger.warn("Ignoring sessionId from different origin: " +
                    event.origin);
                return;
            }
            settings.setSessionId(event.data.sessionId);
            // After popup is closed we will authenticate
        }
    }
    // Register
    if (window.addEventListener) {
        window.addEventListener("message", listener, false);
    } else {
        window.attachEvent("onmessage", listener);
    }
}

Moderator.prototype.isExternalAuthEnabled =  function () {
    return this.externalAuthEnabled;
};

Moderator.prototype.isSipGatewayEnabled =  function () {
    return this.sipGatewayEnabled;
};


Moderator.prototype.onMucMemberLeft =  function (jid) {
    logger.info("Someone left is it focus ? " + jid);
    var resource = Strophe.getResourceFromJid(jid);
    if (resource === 'focus' && !this.xmppService.sessionTerminated) {
        logger.info(
            "Focus has left the room - leaving conference");
        this.eventEmitter.emit(XMPPEvents.FOCUS_LEFT);
    }
};


Moderator.prototype.setFocusUserJid =  function (focusJid) {
    if (!this.focusUserJid) {
        this.focusUserJid = focusJid;
        logger.info("Focus jid set to:  " + this.focusUserJid);
    }
};


Moderator.prototype.getFocusUserJid =  function () {
    return this.focusUserJid;
};

Moderator.prototype.getFocusComponent =  function () {
    // Get focus component address
    var focusComponent = this.xmppService.options.hosts.focus;
    // If not specified use default:  'focus.domain'
    if (!focusComponent) {
        focusComponent = 'focus.' + this.xmppService.options.hosts.domain;
    }
    return focusComponent;
};

Moderator.prototype.createConferenceIq =  function () {
    // Generate create conference IQ
    var elem = $iq({to: this.getFocusComponent(), type: 'set'});

    // Session Id used for authentication
    var sessionId = this.settings.getSessionId();
    var machineUID = this.settings.getUserId();
    var options = this.xmppService.options;

    logger.info(
            "Session ID: " + sessionId + " machine UID: " + machineUID);

    elem.c('conference', {
        xmlns: 'http://jitsi.org/protocol/focus',
        room: this.roomName,
        'machine-uid': machineUID
    });

    if (sessionId) {
        elem.attrs({ 'session-id': sessionId});
    }
    if (options.hosts !== undefined && options.hosts.bridge !== undefined) {
        elem.c(
            'property', {
                name: 'bridge',
                value: options.hosts.bridge
            }).up();
    }
    if (options.enforcedBridge !== undefined) {
        elem.c(
            'property', {
                name: 'enforcedBridge',
                value: options.enforcedBridge
            }).up();
    }
    // Tell the focus we have Jigasi configured
    if (options.hosts !== undefined &&
        options.hosts.call_control !== undefined) {
        elem.c(
            'property', {
                name: 'call_control',
                value: options.hosts.call_control
            }).up();
    }
    if (options.channelLastN !== undefined) {
        elem.c(
            'property', {
                name: 'channelLastN',
                value: options.channelLastN
            }).up();
    }
    if (options.adaptiveLastN !== undefined) {
        elem.c(
            'property', {
                name: 'adaptiveLastN',
                value: options.adaptiveLastN
            }).up();
    }
    if (options.disableAdaptiveSimulcast !== undefined ||
        options.disableSimulcast) {
        // disableSimulcast implies disableAdaptiveSimulcast.
        var value = options.disableSimulcast ? true :
            options.disableAdaptiveSimulcast;
        elem.c(
            'property', {
                name: 'disableAdaptiveSimulcast',
                value: value
            }).up();
    }
    // TODO: re-enable once rtx is stable
    //if (options.disableRtx !== undefined) {
        elem.c(
            'property', {
                name: 'disableRtx',
                //value: options.disableRtx
                value: true
            }).up();
    //}
    if (options.openSctp !== undefined) {
        elem.c(
            'property', {
                name: 'openSctp',
                value: options.openSctp
            }).up();
    }
    if (options.startAudioMuted !== undefined)
    {
        elem.c(
            'property', {
                name: 'startAudioMuted',
                value: options.startAudioMuted
            }).up();
    }
    if (options.startVideoMuted !== undefined)
    {
        elem.c(
            'property', {
                name: 'startVideoMuted',
                value: options.startVideoMuted
            }).up();
    }

    elem.c(
        'property', {
            name: 'simulcastMode',
            value: 'rewriting'
        }).up();
    elem.up();
    return elem;
};


Moderator.prototype.parseSessionId =  function (resultIq) {
    var sessionId = $(resultIq).find('conference').attr('session-id');
    if (sessionId) {
        logger.info('Received sessionId:  ' + sessionId);
        this.settings.setSessionId(sessionId);
    }
};

Moderator.prototype.parseConfigOptions =  function (resultIq) {

    this.setFocusUserJid(
        $(resultIq).find('conference').attr('focusjid'));

    var authenticationEnabled
        = $(resultIq).find(
            '>conference>property' +
            '[name=\'authentication\'][value=\'true\']').length > 0;

    logger.info("Authentication enabled: " + authenticationEnabled);

    this.externalAuthEnabled = $(resultIq).find(
            '>conference>property' +
            '[name=\'externalAuth\'][value=\'true\']').length > 0;

    console.info(
        'External authentication enabled: ' + this.externalAuthEnabled);

    if (!this.externalAuthEnabled) {
        // We expect to receive sessionId in 'internal' authentication mode
        this.parseSessionId(resultIq);
    }

    var authIdentity = $(resultIq).find('>conference').attr('identity');

    this.eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,
        authenticationEnabled, authIdentity);

    // Check if focus has auto-detected Jigasi component(this will be also
    // included if we have passed our host from the config)
    if ($(resultIq).find(
        '>conference>property' +
        '[name=\'sipGatewayEnabled\'][value=\'true\']').length) {
        this.sipGatewayEnabled = true;
    }

    logger.info("Sip gateway enabled:  " + this.sipGatewayEnabled);
};

// FIXME We need to show the fact that we're waiting for the focus to the user
// (or that the focus is not available)
/**
 * Allocates the conference focus.
 *
 * @param {Function} callback - the function to be called back upon the
 * successful allocation of the conference focus
 */
Moderator.prototype.allocateConferenceFocus =  function (callback) {
    // Try to use focus user JID from the config
    this.setFocusUserJid(this.xmppService.options.focusUserJid);
    // Send create conference IQ
    var self = this;
    this.connection.sendIQ(
        this.createConferenceIq(),
        function (result) {
            self._allocateConferenceFocusSuccess(result, callback);
        },
        function (error) {
            self._allocateConferenceFocusError(error, callback);
        });
    // XXX We're pressed for time here because we're beginning a complex and/or
    // lengthy conference-establishment process which supposedly involves
    // multiple RTTs. We don't have the time to wait for Strophe to decide to
    // send our IQ.
    this.connection.flush();
};

/**
 * Invoked by {@link #allocateConferenceFocus} upon its request receiving an
 * error result.
 *
 * @param error - the error result of the request that
 * {@link #allocateConferenceFocus} sent
 * @param {Function} callback - the function to be called back upon the
 * successful allocation of the conference focus
 */
{'fraction_non_alphanumeric': 0.11928586475668844, 'fraction_numerical': 0.0015799452285654098, 'mean_word_length': 2.2672057811424637, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7556695', 'n_tokens_mistral': 5467, 'n_tokens_neox': 5265, 'n_words': 1251}