diff --git a/public/src/sockets.js b/public/src/sockets.js
new file mode 100644
index 0000000000..461c148be7
--- /dev/null
+++ b/public/src/sockets.js
@@ -0,0 +1,127 @@
+'use strict';
+/* globals config, io, ajaxify */
+
+var app = app || {};
+var socket;
+app.isConnected = false;
+
+(function () {
+ var reconnecting = false;
+
+ var ioParams = {
+ reconnectionAttempts: config.maxReconnectionAttempts,
+ reconnectionDelay: config.reconnectionDelay,
+ transports: config.socketioTransports,
+ path: config.relative_path + '/socket.io'
+ };
+
+ socket = io(config.websocketAddress, ioParams);
+
+ socket.on('connect', onConnect);
+
+ socket.on('reconnecting', onReconnecting);
+
+ socket.on('disconnect', onDisconnect);
+
+ socket.on('reconnect_failed', function() {
+ // Wait ten times the reconnection delay and then start over
+ setTimeout(socket.connect.bind(socket), parseInt(config.reconnectionDelay, 10) * 10);
+ });
+
+ socket.on('event:banned', onEventBanned);
+
+ socket.on('event:alert', app.alert);
+
+ function onConnect() {
+ app.isConnected = true;
+
+ if (!reconnecting) {
+ app.showLoginMessage();
+ $(window).trigger('action:connected');
+ }
+
+ if (reconnecting) {
+ var reconnectEl = $('#reconnect');
+
+ reconnectEl.tooltip('destroy');
+ reconnectEl.html('');
+ reconnecting = false;
+
+ reJoinCurrentRoom();
+
+ socket.emit('meta.reconnected');
+
+ $(window).trigger('action:reconnected');
+
+ setTimeout(function() {
+ reconnectEl.removeClass('active').addClass('hide');
+ }, 3000);
+ }
+ }
+
+ function reJoinCurrentRoom() {
+ var url_parts = window.location.pathname.slice(config.relative_path.length).split('/').slice(1);
+ var room;
+
+ switch(url_parts[0]) {
+ case 'user':
+ room = 'user/' + (ajaxify.data ? ajaxify.data.theirid : 0);
+ break;
+ case 'topic':
+ room = 'topic_' + url_parts[1];
+ break;
+ case 'category':
+ room = 'category_' + url_parts[1];
+ break;
+ case 'recent':
+ room = 'recent_topics';
+ break;
+ case 'unread':
+ room = 'unread_topics';
+ break;
+ case 'popular':
+ room = 'popular_topics';
+ break;
+ case 'admin':
+ room = 'admin';
+ break;
+ case 'categories':
+ room = 'categories';
+ break;
+ }
+ app.currentRoom = '';
+ app.enterRoom(room);
+ }
+
+ function onReconnecting() {
+ reconnecting = true;
+ var reconnectEl = $('#reconnect');
+
+ if (!reconnectEl.hasClass('active')) {
+ reconnectEl.html('');
+ }
+
+ reconnectEl.addClass('active').removeClass("hide").tooltip({
+ placement: 'bottom'
+ });
+ }
+
+ function onDisconnect() {
+ $(window).trigger('action:disconnected');
+ app.isConnected = false;
+ }
+
+ function onEventBanned() {
+ app.alert({
+ title: '[[global:alert.banned]]',
+ message: '[[global:alert.banned.message]]',
+ type: 'danger',
+ timeout: 1000
+ });
+
+ setTimeout(function() {
+ window.location.href = config.relative_path + '/';
+ }, 1000);
+ }
+
+}());
\ No newline at end of file
diff --git a/src/user/invite.js b/src/user/invite.js
index f2d800e90c..ef3146b5f4 100644
--- a/src/user/invite.js
+++ b/src/user/invite.js
@@ -1,14 +1,18 @@
'use strict';
-var async = require('async');
-var nconf = require('nconf');
-
-var db = require('./../database');
-var meta = require('../meta');
-var emailer = require('../emailer');
-var translator = require('../../public/src/modules/translator');
-var utils = require('../../public/src/utils');
+var async = require('async'),
+ nconf = require('nconf'),
+ winston = require('winston'),
+ db = require('./../database'),
+
+ meta = require('../meta'),
+ emailer = require('../emailer'),
+
+ plugins = require('../plugins'),
+ translator = require('../../public/src/modules/translator'),
+ utils = require('../../public/src/utils');
+
module.exports = function(User) {