aboutsummaryrefslogtreecommitdiffstats
path: root/library/ajaxchat/chat/lib/class
diff options
context:
space:
mode:
authorfriendica <info@friendica.com>2014-01-18 23:49:39 -0800
committerfriendica <info@friendica.com>2014-01-18 23:49:39 -0800
commit724ad4505628d493b43b4f585512d67dc0b4ee76 (patch)
tree4fb920a79e3dff961a6301ec56ec9f40e91f6af3 /library/ajaxchat/chat/lib/class
parent3f7032e542e3c451507fc9266ab3536155c8190f (diff)
downloadvolse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.tar.gz
volse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.tar.bz2
volse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.zip
add ajaxchat library - needs a lot of integration work to handle decentralisation (e.g. chatroom@website) and zotid w/permissions (e.g. ACL controlled chatrooms); we can also rip out a lot of stuff we don't need.
Diffstat (limited to 'library/ajaxchat/chat/lib/class')
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChat.php3326
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatDataBase.php81
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatEncoding.php138
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatFileSystem.php22
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatHTTPHeader.php56
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatLanguage.php102
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatMySQLDataBase.php92
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatMySQLQuery.php89
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatMySQLiDataBase.php91
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatMySQLiQuery.php81
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatString.php37
-rw-r--r--library/ajaxchat/chat/lib/class/AJAXChatTemplate.php329
-rw-r--r--library/ajaxchat/chat/lib/class/CustomAJAXChat.php124
-rw-r--r--library/ajaxchat/chat/lib/class/CustomAJAXChatInterface.php21
-rw-r--r--library/ajaxchat/chat/lib/class/CustomAJAXChatShoutBox.php25
15 files changed, 4614 insertions, 0 deletions
diff --git a/library/ajaxchat/chat/lib/class/AJAXChat.php b/library/ajaxchat/chat/lib/class/AJAXChat.php
new file mode 100644
index 000000000..2cf7aa11f
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChat.php
@@ -0,0 +1,3326 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat backend logic:
+class AJAXChat {
+
+ var $db;
+ var $_config;
+ var $_requestVars;
+ var $_infoMessages;
+ var $_channels;
+ var $_allChannels;
+ var $_view;
+ var $_lang;
+ var $_invitations;
+ var $_customVars;
+ var $_sessionNew;
+ var $_onlineUsersData;
+ var $_bannedUsersData;
+
+ function __construct() {
+ $this->initialize();
+ }
+
+ function initialize() {
+ // Initialize configuration settings:
+ $this->initConfig();
+
+ // Initialize the DataBase connection:
+ $this->initDataBaseConnection();
+
+ // Initialize request variables:
+ $this->initRequestVars();
+
+ // Initialize the chat session:
+ $this->initSession();
+
+ // Handle the browser request and send the response content:
+ $this->handleRequest();
+ }
+
+ function initConfig() {
+ $config = null;
+ if (!include(AJAX_CHAT_PATH.'lib/config.php')) {
+ echo('<strong>Error:</strong> Could not find a config.php file in "'.AJAX_CHAT_PATH.'"lib/". Check to make sure the file exists.');
+ die();
+ }
+ $this->_config = &$config;
+
+ // Initialize custom configuration settings:
+ $this->initCustomConfig();
+ }
+
+ function initRequestVars() {
+ $this->_requestVars = array();
+ $this->_requestVars['ajax'] = isset($_REQUEST['ajax']) ? true : false;
+ $this->_requestVars['userID'] = isset($_REQUEST['userID']) ? (int)$_REQUEST['userID'] : null;
+ $this->_requestVars['userName'] = isset($_REQUEST['userName']) ? $_REQUEST['userName'] : null;
+ $this->_requestVars['channelID'] = isset($_REQUEST['channelID']) ? (int)$_REQUEST['channelID'] : null;
+ $this->_requestVars['channelName'] = isset($_REQUEST['channelName']) ? $_REQUEST['channelName'] : null;
+ $this->_requestVars['text'] = isset($_POST['text']) ? $_POST['text'] : null;
+ $this->_requestVars['lastID'] = isset($_REQUEST['lastID']) ? (int)$_REQUEST['lastID'] : 0;
+ $this->_requestVars['login'] = isset($_REQUEST['login']) ? true : false;
+ $this->_requestVars['logout'] = isset($_REQUEST['logout']) ? true : false;
+ $this->_requestVars['password'] = isset($_REQUEST['password']) ? $_REQUEST['password'] : null;
+ $this->_requestVars['view'] = isset($_REQUEST['view']) ? $_REQUEST['view'] : null;
+ $this->_requestVars['year'] = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null;
+ $this->_requestVars['month'] = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null;
+ $this->_requestVars['day'] = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null;
+ $this->_requestVars['hour'] = isset($_REQUEST['hour']) ? (int)$_REQUEST['hour'] : null;
+ $this->_requestVars['search'] = isset($_REQUEST['search']) ? $_REQUEST['search'] : null;
+ $this->_requestVars['shoutbox'] = isset($_REQUEST['shoutbox']) ? true : false;
+ $this->_requestVars['getInfos'] = isset($_REQUEST['getInfos']) ? $_REQUEST['getInfos'] : null;
+ $this->_requestVars['lang'] = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : null;
+ $this->_requestVars['delete'] = isset($_REQUEST['delete']) ? (int)$_REQUEST['delete'] : null;
+
+ // Initialize custom request variables:
+ $this->initCustomRequestVars();
+
+ // Remove slashes which have been added to user input strings if magic_quotes_gpc is On:
+ if(get_magic_quotes_gpc()) {
+ // It is safe to remove the slashes as we escape user data ourself
+ array_walk(
+ $this->_requestVars,
+ create_function(
+ '&$value, $key',
+ 'if(is_string($value)) $value = stripslashes($value);'
+ )
+ );
+ }
+ }
+
+ function initDataBaseConnection() {
+ // Create a new database object:
+ $this->db = new AJAXChatDataBase(
+ $this->_config['dbConnection']
+ );
+ // Use a new database connection if no existing is given:
+ if(!$this->_config['dbConnection']['link']) {
+ // Connect to the database server:
+ $this->db->connect($this->_config['dbConnection']);
+ if($this->db->error()) {
+ echo $this->db->getError();
+ die();
+ }
+ // Select the database:
+ $this->db->select($this->_config['dbConnection']['name']);
+ if($this->db->error()) {
+ echo $this->db->getError();
+ die();
+ }
+ }
+ // Unset the dbConnection array for safety purposes:
+ unset($this->_config['dbConnection']);
+ }
+
+ function getDataBaseTable($table) {
+ return ($this->db->getName() ? '`'.$this->db->getName().'`.'.$this->getConfig('dbTableNames',$table) : $this->getConfig('dbTableNames',$table));
+ }
+
+ function initSession() {
+ // Start the PHP session (if not already started):
+ $this->startSession();
+
+ if($this->isLoggedIn()) {
+ // Logout if we receive a logout request, the chat has been closed or the userID could not be revalidated:
+ if($this->getRequestVar('logout') || !$this->isChatOpen() || !$this->revalidateUserID()) {
+ $this->logout();
+ return;
+ }
+ // Logout if the Session IP is not the same when logged in and ipCheck is enabled:
+ if($this->getConfig('ipCheck') && ($this->getSessionIP() === null || $this->getSessionIP() != $_SERVER['REMOTE_ADDR'])) {
+ $this->logout('IP');
+ return;
+ }
+ } else if(
+ // Login if auto-login enabled or a login, userName or shoutbox parameter is given:
+ $this->getConfig('forceAutoLogin') ||
+ $this->getRequestVar('login') ||
+ $this->getRequestVar('userName') ||
+ $this->getRequestVar('shoutbox')
+ ) {
+ $this->login();
+ }
+
+ // Initialize the view:
+ $this->initView();
+
+ if($this->getView() == 'chat') {
+ $this->initChatViewSession();
+ } else if($this->getView() == 'logs') {
+ $this->initLogsViewSession();
+ }
+
+ if(!$this->getRequestVar('ajax') && !headers_sent()) {
+ // Set style cookie:
+ $this->setStyle();
+ // Set langCode cookie:
+ $this->setLangCodeCookie();
+ }
+
+ $this->initCustomSession();
+ }
+
+ function initLogsViewSession() {
+ if($this->getConfig('socketServerEnabled')) {
+ if(!$this->getSessionVar('logsViewSocketAuthenticated')) {
+ $this->updateLogsViewSocketAuthentication();
+ $this->setSessionVar('logsViewSocketAuthenticated', true);
+ }
+ }
+ }
+
+ function updateLogsViewSocketAuthentication() {
+ if($this->getUserRole() != AJAX_CHAT_ADMIN) {
+ $channels = array();
+ foreach($this->getChannels() as $channel) {
+ if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
+ continue;
+ }
+ array_push($channels, $channel);
+ }
+ array_push($channels, $this->getPrivateMessageID());
+ array_push($channels, $this->getPrivateChannelID());
+ } else {
+ // The channelID "ALL" authenticates for all channels:
+ $channels = array('ALL');
+ }
+ $this->updateSocketAuthentication(
+ $this->getUserID(),
+ $this->getSocketRegistrationID(),
+ $channels
+ );
+ }
+
+ function initChatViewSession() {
+ // If channel is not null we are logged in to the chat view:
+ if($this->getChannel() !== null) {
+ // Check if the current user has been logged out due to inactivity:
+ if(!$this->isUserOnline()) {
+ $this->logout();
+ return;
+ }
+ if($this->getRequestVar('ajax')) {
+ $this->initChannel();
+ $this->updateOnlineStatus();
+ $this->checkAndRemoveInactive();
+ }
+ } else {
+ if($this->getRequestVar('ajax')) {
+ // Set channel, insert login messages and add to online list on first ajax request in chat view:
+ $this->chatViewLogin();
+ }
+ }
+ }
+
+ function isChatOpen() {
+ if($this->getUserRole() == AJAX_CHAT_ADMIN)
+ return true;
+ if($this->getConfig('chatClosed'))
+ return false;
+ $time = time();
+ if($this->getConfig('timeZoneOffset') !== null) {
+ // Subtract the server timezone offset and add the config timezone offset:
+ $time -= date('Z', $time);
+ $time += $this->getConfig('timeZoneOffset');
+ }
+ // Check the opening hours:
+ if($this->getConfig('openingHour') < $this->getConfig('closingHour'))
+ {
+ if(($this->getConfig('openingHour') > date('G', $time)) || ($this->getConfig('closingHour') <= date('G', $time)))
+ return false;
+ }
+ else
+ {
+ if(($this->getConfig('openingHour') > date('G', $time)) && ($this->getConfig('closingHour') <= date('G', $time)))
+ return false;
+ }
+ // Check the opening weekdays:
+ if(!in_array(date('w', $time), $this->getConfig('openingWeekDays')))
+ return false;
+ return true;
+ }
+
+ function handleRequest() {
+ if($this->getRequestVar('ajax')) {
+ if($this->isLoggedIn()) {
+ // Parse info requests (for current userName, etc.):
+ $this->parseInfoRequests();
+
+ // Parse command requests (e.g. message deletion):
+ $this->parseCommandRequests();
+
+ // Parse message requests:
+ $this->initMessageHandling();
+ }
+ // Send chat messages and online user list in XML format:
+ $this->sendXMLMessages();
+ } else {
+ // Display XHTML content for non-ajax requests:
+ $this->sendXHTMLContent();
+ }
+ }
+
+ function parseCommandRequests() {
+ if($this->getRequestVar('delete') !== null) {
+ $this->deleteMessage($this->getRequestVar('delete'));
+ }
+ }
+
+ function parseInfoRequests() {
+ if($this->getRequestVar('getInfos')) {
+ $infoRequests = explode(',', $this->getRequestVar('getInfos'));
+ foreach($infoRequests as $infoRequest) {
+ $this->parseInfoRequest($infoRequest);
+ }
+ }
+ }
+
+ function parseInfoRequest($infoRequest) {
+ switch($infoRequest) {
+ case 'userID':
+ $this->addInfoMessage($this->getUserID(), 'userID');
+ break;
+ case 'userName':
+ $this->addInfoMessage($this->getUserName(), 'userName');
+ break;
+ case 'userRole':
+ $this->addInfoMessage($this->getUserRole(), 'userRole');
+ break;
+ case 'channelID':
+ $this->addInfoMessage($this->getChannel(), 'channelID');
+ break;
+ case 'channelName':
+ $this->addInfoMessage($this->getChannelName(), 'channelName');
+ break;
+ case 'socketRegistrationID':
+ $this->addInfoMessage($this->getSocketRegistrationID(), 'socketRegistrationID');
+ break;
+ default:
+ $this->parseCustomInfoRequest($infoRequest);
+ }
+ }
+
+ function sendXHTMLContent() {
+ $httpHeader = new AJAXChatHTTPHeader($this->getConfig('contentEncoding'), $this->getConfig('contentType'));
+
+ $template = new AJAXChatTemplate($this, $this->getTemplateFileName(), $httpHeader->getContentType());
+
+ // Send HTTP header:
+ $httpHeader->send();
+
+ // Send parsed template content:
+ echo $template->getParsedContent();
+ }
+
+ function getTemplateFileName() {
+ switch($this->getView()) {
+ case 'chat':
+ return AJAX_CHAT_PATH.'lib/template/loggedIn.html';
+ case 'logs':
+ return AJAX_CHAT_PATH.'lib/template/logs.html';
+ default:
+ return AJAX_CHAT_PATH.'lib/template/loggedOut.html';
+ }
+ }
+
+ function initView() {
+ $this->_view = null;
+ // "chat" is the default view:
+ $view = ($this->getRequestVar('view') === null) ? 'chat' : $this->getRequestVar('view');
+ if($this->hasAccessTo($view)) {
+ $this->_view = $view;
+ }
+ }
+
+ function getView() {
+ return $this->_view;
+ }
+
+ function hasAccessTo($view) {
+ switch($view) {
+ case 'chat':
+ case 'teaser':
+ if($this->isLoggedIn()) {
+ return true;
+ }
+ return false;
+ case 'logs':
+ if($this->isLoggedIn() && ($this->getUserRole() == AJAX_CHAT_ADMIN ||
+ ($this->getConfig('logsUserAccess') &&
+ ($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_USER))
+ )) {
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ function login() {
+ // Retrieve valid login user data (from request variables or session data):
+ $userData = $this->getValidLoginUserData();
+
+ if(!$userData) {
+ $this->addInfoMessage('errorInvalidUser');
+ return false;
+ }
+
+ // If the chat is closed, only the admin may login:
+ if(!$this->isChatOpen() && $userData['userRole'] != AJAX_CHAT_ADMIN) {
+ $this->addInfoMessage('errorChatClosed');
+ return false;
+ }
+
+ if(!$this->getConfig('allowGuestLogins') && $userData['userRole'] == AJAX_CHAT_GUEST) {
+ return false;
+ }
+
+ // Check if userID or userName are already listed online:
+ if($this->isUserOnline($userData['userID']) || $this->isUserNameInUse($userData['userName'])) {
+ if($userData['userRole'] == AJAX_CHAT_USER || $userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) {
+ // Set the registered user inactive and remove the inactive users so the user can be logged in again:
+ $this->setInactive($userData['userID'], $userData['userName']);
+ $this->removeInactive();
+ } else {
+ $this->addInfoMessage('errorUserInUse');
+ return false;
+ }
+ }
+
+ // Check if user is banned:
+ if($userData['userRole'] != AJAX_CHAT_ADMIN && $this->isUserBanned($userData['userName'], $userData['userID'], $_SERVER['REMOTE_ADDR'])) {
+ $this->addInfoMessage('errorBanned');
+ return false;
+ }
+
+ // Check if the max number of users is logged in (not affecting moderators or admins):
+ if(!($userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) && $this->isMaxUsersLoggedIn()) {
+ $this->addInfoMessage('errorMaxUsersLoggedIn');
+ return false;
+ }
+
+ // Use a new session id (if session has been started by the chat):
+ $this->regenerateSessionID();
+
+ // Log in:
+ $this->setUserID($userData['userID']);
+ $this->setUserName($userData['userName']);
+ $this->setLoginUserName($userData['userName']);
+ $this->setUserRole($userData['userRole']);
+ $this->setLoggedIn(true);
+ $this->setLoginTimeStamp(time());
+
+ // IP Security check variable:
+ $this->setSessionIP($_SERVER['REMOTE_ADDR']);
+
+ // The client authenticates to the socket server using a socketRegistrationID:
+ if($this->getConfig('socketServerEnabled')) {
+ $this->setSocketRegistrationID(
+ md5(uniqid(rand(), true))
+ );
+ }
+
+ // Add userID, userName and userRole to info messages:
+ $this->addInfoMessage($this->getUserID(), 'userID');
+ $this->addInfoMessage($this->getUserName(), 'userName');
+ $this->addInfoMessage($this->getUserRole(), 'userRole');
+
+ // Purge logs:
+ if($this->getConfig('logsPurgeLogs')) {
+ $this->purgeLogs();
+ }
+
+ return true;
+ }
+
+ function chatViewLogin() {
+ $this->setChannel($this->getValidRequestChannelID());
+ $this->addToOnlineList();
+
+ // Add channelID and channelName to info messages:
+ $this->addInfoMessage($this->getChannel(), 'channelID');
+ $this->addInfoMessage($this->getChannelName(), 'channelName');
+
+ // Login message:
+ $text = '/login '.$this->getUserName();
+ $this->insertChatBotMessage(
+ $this->getChannel(),
+ $text,
+ null,
+ 1
+ );
+ }
+
+ function getValidRequestChannelID() {
+ $channelID = $this->getRequestVar('channelID');
+ $channelName = $this->getRequestVar('channelName');
+ // Check the given channelID, or get channelID from channelName:
+ if($channelID === null) {
+ if($channelName !== null) {
+ $channelID = $this->getChannelIDFromChannelName($channelName);
+ // channelName might need encoding conversion:
+ if($channelID === null) {
+ $channelID = $this->getChannelIDFromChannelName(
+ $this->trimChannelName($channelName, $this->getConfig('contentEncoding'))
+ );
+ }
+ }
+ }
+ // Validate the resulting channelID:
+ if(!$this->validateChannel($channelID)) {
+ if($this->getChannel() !== null) {
+ return $this->getChannel();
+ }
+ return $this->getConfig('defaultChannelID');
+ }
+ return $channelID;
+ }
+
+ function initChannel() {
+ $channelID = $this->getRequestVar('channelID');
+ $channelName = $this->getRequestVar('channelName');
+ if($channelID !== null) {
+ $this->switchChannel($this->getChannelNameFromChannelID($channelID));
+ } else if($channelName !== null) {
+ if($this->getChannelIDFromChannelName($channelName) === null) {
+ // channelName might need encoding conversion:
+ $channelName = $this->trimChannelName($channelName, $this->getConfig('contentEncoding'));
+ }
+ $this->switchChannel($channelName);
+ }
+ }
+
+ function logout($type=null) {
+ // Update the socket server authentication for the user:
+ if($this->getConfig('socketServerEnabled')) {
+ $this->updateSocketAuthentication($this->getUserID());
+ }
+ if($this->isUserOnline()) {
+ $this->chatViewLogout($type);
+ }
+ $this->setLoggedIn(false);
+ $this->destroySession();
+
+ // Re-initialize the view:
+ $this->initView();
+ }
+
+ function chatViewLogout($type) {
+ $this->removeFromOnlineList();
+ if($type !== null) {
+ $type = ' '.$type;
+ }
+ // Logout message
+ $text = '/logout '.$this->getUserName().$type;
+ $this->insertChatBotMessage(
+ $this->getChannel(),
+ $text,
+ null,
+ 1
+ );
+ }
+
+ function switchChannel($channelName) {
+ $channelID = $this->getChannelIDFromChannelName($channelName);
+
+ if($channelID !== null && $this->getChannel() == $channelID) {
+ // User is already in the given channel, return:
+ return;
+ }
+
+ // Check if we have a valid channel:
+ if(!$this->validateChannel($channelID)) {
+ // Invalid channel:
+ $text = '/error InvalidChannelName '.$channelName;
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ $text
+ );
+ return;
+ }
+
+ $oldChannel = $this->getChannel();
+
+ $this->setChannel($channelID);
+ $this->updateOnlineList();
+
+ // Channel leave message
+ $text = '/channelLeave '.$this->getUserName();
+ $this->insertChatBotMessage(
+ $oldChannel,
+ $text,
+ null,
+ 1
+ );
+
+ // Channel enter message
+ $text = '/channelEnter '.$this->getUserName();
+ $this->insertChatBotMessage(
+ $this->getChannel(),
+ $text,
+ null,
+ 1
+ );
+
+ $this->addInfoMessage($channelName, 'channelSwitch');
+ $this->addInfoMessage($channelID, 'channelID');
+ $this->_requestVars['lastID'] = 0;
+ }
+
+ function addToOnlineList() {
+ $sql = 'INSERT INTO '.$this->getDataBaseTable('online').'(
+ userID,
+ userName,
+ userRole,
+ channel,
+ dateTime,
+ ip
+ )
+ VALUES (
+ '.$this->db->makeSafe($this->getUserID()).',
+ '.$this->db->makeSafe($this->getUserName()).',
+ '.$this->db->makeSafe($this->getUserRole()).',
+ '.$this->db->makeSafe($this->getChannel()).',
+ NOW(),
+ '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
+ );';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $this->resetOnlineUsersData();
+ }
+
+ function removeFromOnlineList() {
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('online').'
+ WHERE
+ userID = '.$this->db->makeSafe($this->getUserID()).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $this->removeUserFromOnlineUsersData();
+ }
+
+ function updateOnlineList() {
+ $sql = 'UPDATE
+ '.$this->getDataBaseTable('online').'
+ SET
+ userName = '.$this->db->makeSafe($this->getUserName()).',
+ channel = '.$this->db->makeSafe($this->getChannel()).',
+ dateTime = NOW(),
+ ip = '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
+ WHERE
+ userID = '.$this->db->makeSafe($this->getUserID()).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $this->resetOnlineUsersData();
+ }
+
+ function initMessageHandling() {
+ // Don't handle messages if we are not in chat view:
+ if($this->getView() != 'chat') {
+ return;
+ }
+
+ // Check if we have been uninvited from a private or restricted channel:
+ if(!$this->validateChannel($this->getChannel())) {
+ // Switch to the default channel:
+ $this->switchChannel($this->getChannelNameFromChannelID($this->getConfig('defaultChannelID')));
+ return;
+ }
+
+ if($this->getRequestVar('text') !== null) {
+ $this->insertMessage($this->getRequestVar('text'));
+ }
+ }
+
+ function insertParsedMessage($text) {
+
+ // If a queryUserName is set, sent all messages as private messages to this userName:
+ if($this->getQueryUserName() !== null && strpos($text, '/') !== 0) {
+ $text = '/msg '.$this->getQueryUserName().' '.$text;
+ }
+
+ // Parse IRC-style commands:
+ if(strpos($text, '/') === 0) {
+ $textParts = explode(' ', $text);
+
+ switch($textParts[0]) {
+
+ // Channel switch:
+ case '/join':
+ $this->insertParsedMessageJoin($textParts);
+ break;
+
+ // Logout:
+ case '/quit':
+ $this->logout();
+ break;
+
+ // Private message:
+ case '/msg':
+ case '/describe':
+ $this->insertParsedMessagePrivMsg($textParts);
+ break;
+
+ // Invitation:
+ case '/invite':
+ $this->insertParsedMessageInvite($textParts);
+ break;
+
+ // Uninvitation:
+ case '/uninvite':
+ $this->insertParsedMessageUninvite($textParts);
+ break;
+
+ // Private messaging:
+ case '/query':
+ $this->insertParsedMessageQuery($textParts);
+ break;
+
+ // Kicking offending users from the chat:
+ case '/kick':
+ $this->insertParsedMessageKick($textParts);
+ break;
+
+ // Listing banned users:
+ case '/bans':
+ $this->insertParsedMessageBans($textParts);
+ break;
+
+ // Unban user (remove from ban list):
+ case '/unban':
+ $this->insertParsedMessageUnban($textParts);
+ break;
+
+ // Describing actions:
+ case '/me':
+ case '/action':
+ $this->insertParsedMessageAction($textParts);
+ break;
+
+
+ // Listing online Users:
+ case '/who':
+ $this->insertParsedMessageWho($textParts);
+ break;
+
+ // Listing available channels:
+ case '/list':
+ $this->insertParsedMessageList($textParts);
+ break;
+
+ // Retrieving the channel of a User:
+ case '/whereis':
+ $this->insertParsedMessageWhereis($textParts);
+ break;
+
+ // Listing information about a User:
+ case '/whois':
+ $this->insertParsedMessageWhois($textParts);
+ break;
+
+ // Rolling dice:
+ case '/roll':
+ $this->insertParsedMessageRoll($textParts);
+ break;
+
+ // Switching userName:
+ case '/nick':
+ $this->insertParsedMessageNick($textParts);
+ break;
+
+ // Custom or unknown command:
+ default:
+ if(!$this->parseCustomCommands($text, $textParts)) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UnknownCommand '.$textParts[0]
+ );
+ }
+ }
+
+ } else {
+ // No command found, just insert the plain message:
+ $this->insertCustomMessage(
+ $this->getUserID(),
+ $this->getUserName(),
+ $this->getUserRole(),
+ $this->getChannel(),
+ $text
+ );
+ }
+ }
+
+ function insertParsedMessageJoin($textParts) {
+ if(count($textParts) == 1) {
+ // join with no arguments is the own private channel, if allowed:
+ if($this->isAllowedToCreatePrivateChannel()) {
+ // Private channels are identified by square brackets:
+ $this->switchChannel($this->getChannelNameFromChannelID($this->getPrivateChannelID()));
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingChannelName'
+ );
+ }
+ } else {
+ $this->switchChannel($textParts[1]);
+ }
+ }
+
+ function insertParsedMessagePrivMsg($textParts) {
+ if($this->isAllowedToSendPrivateMessage()) {
+ if(count($textParts) < 3) {
+ if(count($textParts) == 2) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingText'
+ );
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ }
+ } else {
+ // Get UserID from UserName:
+ $toUserID = $this->getIDFromName($textParts[1]);
+ if($toUserID === null) {
+ if($this->getQueryUserName() !== null) {
+ // Close the current query:
+ $this->insertMessage('/query');
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ }
+ } else {
+ // Insert /privaction command if /describe is used:
+ $command = ($textParts[0] == '/describe') ? '/privaction' : '/privmsg';
+ // Copy of private message to current User:
+ $this->insertCustomMessage(
+ $this->getUserID(),
+ $this->getUserName(),
+ $this->getUserRole(),
+ $this->getPrivateMessageID(),
+ $command.'to '.$textParts[1].' '.implode(' ', array_slice($textParts, 2))
+ );
+ // Private message to requested User:
+ $this->insertCustomMessage(
+ $this->getUserID(),
+ $this->getUserName(),
+ $this->getUserRole(),
+ $this->getPrivateMessageID($toUserID),
+ $command.' '.implode(' ', array_slice($textParts, 2))
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error PrivateMessageNotAllowed'
+ );
+ }
+ }
+
+ function insertParsedMessageInvite($textParts) {
+ if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ $toUserID = $this->getIDFromName($textParts[1]);
+ if($toUserID === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // Add the invitation to the database:
+ $this->addInvitation($toUserID);
+ $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
+ // Copy of invitation to current User:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/inviteto '.$textParts[1].' '.$invitationChannelName
+ );
+ // Invitation to requested User:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID($toUserID),
+ '/invite '.$this->getUserName().' '.$invitationChannelName
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error InviteNotAllowed'
+ );
+ }
+ }
+
+ function insertParsedMessageUninvite($textParts) {
+ if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ $toUserID = $this->getIDFromName($textParts[1]);
+ if($toUserID === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // Remove the invitation from the database:
+ $this->removeInvitation($toUserID);
+ $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
+ // Copy of uninvitation to current User:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/uninviteto '.$textParts[1].' '.$invitationChannelName
+ );
+ // Uninvitation to requested User:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID($toUserID),
+ '/uninvite '.$this->getUserName().' '.$invitationChannelName
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UninviteNotAllowed'
+ );
+ }
+ }
+
+ function insertParsedMessageQuery($textParts) {
+ if($this->isAllowedToSendPrivateMessage()) {
+ if(count($textParts) == 1) {
+ if($this->getQueryUserName() !== null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/queryClose '.$this->getQueryUserName()
+ );
+ // Close the current query:
+ $this->setQueryUserName(null);
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error NoOpenQuery'
+ );
+ }
+ } else {
+ if($this->getIDFromName($textParts[1]) === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ if($this->getQueryUserName() !== null) {
+ // Close the current query:
+ $this->insertMessage('/query');
+ }
+ // Open a query to the requested user:
+ $this->setQueryUserName($textParts[1]);
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/queryOpen '.$textParts[1]
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error PrivateMessageNotAllowed'
+ );
+ }
+ }
+
+ function insertParsedMessageKick($textParts) {
+ // Only moderators/admins may kick users:
+ if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ // Get UserID from UserName:
+ $kickUserID = $this->getIDFromName($textParts[1]);
+ if($kickUserID === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // Check the role of the user to kick:
+ $kickUserRole = $this->getRoleFromID($kickUserID);
+ if($kickUserRole == AJAX_CHAT_ADMIN || ($kickUserRole == AJAX_CHAT_MODERATOR && $this->getUserRole() != AJAX_CHAT_ADMIN)) {
+ // Admins and moderators may not be kicked:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error KickNotAllowed '.$textParts[1]
+ );
+ } else {
+ // Kick user and insert message:
+ $channel = $this->getChannelFromID($kickUserID);
+ $banMinutes = (count($textParts) > 2) ? $textParts[2] : null;
+ $this->kickUser($textParts[1], $banMinutes, $kickUserID);
+ // If no channel found, user logged out before he could be kicked
+ if($channel !== null) {
+ $this->insertChatBotMessage(
+ $channel,
+ '/kick '.$textParts[1],
+ null,
+ 1
+ );
+ // Send a copy of the message to the current user, if not in the channel:
+ if($channel != $this->getChannel()) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/kick '.$textParts[1],
+ null,
+ 1
+ );
+ }
+ }
+ }
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error CommandNotAllowed '.$textParts[0]
+ );
+ }
+ }
+
+ function insertParsedMessageBans($textParts) {
+ // Only moderators/admins may see the list of banned users:
+ if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ $this->removeExpiredBans();
+ $bannedUsers = $this->getBannedUsers();
+ if(count($bannedUsers) > 0) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/bans '.implode(' ', $bannedUsers)
+ );
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/bansEmpty -'
+ );
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error CommandNotAllowed '.$textParts[0]
+ );
+ }
+ }
+
+ function insertParsedMessageUnban($textParts) {
+ // Only moderators/admins may unban users:
+ if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ $this->removeExpiredBans();
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ if(!in_array($textParts[1], $this->getBannedUsers())) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // Unban user and insert message:
+ $this->unbanUser($textParts[1]);
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/unban '.$textParts[1]
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error CommandNotAllowed '.$textParts[0]
+ );
+ }
+ }
+
+ function insertParsedMessageAction($textParts) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingText'
+ );
+ } else {
+ if($this->getQueryUserName() !== null) {
+ // If we are in query mode, sent the action to the query user:
+ $this->insertMessage('/describe '.$this->getQueryUserName().' '.implode(' ', array_slice($textParts, 1)));
+ } else {
+ $this->insertCustomMessage(
+ $this->getUserID(),
+ $this->getUserName(),
+ $this->getUserRole(),
+ $this->getChannel(),
+ implode(' ', $textParts)
+ );
+ }
+ }
+ }
+
+ function insertParsedMessageWho($textParts) {
+ if(count($textParts) == 1) {
+ if($this->isAllowedToListHiddenUsers()) {
+ // List online users from any channel:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/who '.implode(' ', $this->getOnlineUsers())
+ );
+ } else {
+ // Get online users for all accessible channels:
+ $channels = $this->getChannels();
+ // Add the own private channel if allowed:
+ if($this->isAllowedToCreatePrivateChannel()) {
+ array_push($channels, $this->getPrivateChannelID());
+ }
+ // Add the invitation channels:
+ foreach($this->getInvitations() as $channelID) {
+ if(!in_array($channelID, $channels)) {
+ array_push($channels, $channelID);
+ }
+ }
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/who '.implode(' ', $this->getOnlineUsers($channels))
+ );
+ }
+ } else {
+ $channelName = $textParts[1];
+ $channelID = $this->getChannelIDFromChannelName($channelName);
+ if(!$this->validateChannel($channelID)) {
+ // Invalid channel:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error InvalidChannelName '.$channelName
+ );
+ } else {
+ // Get online users for the given channel:
+ $onlineUsers = $this->getOnlineUsers(array($channelID));
+ if(count($onlineUsers) > 0) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/whoChannel '.$channelName.' '.implode(' ', $onlineUsers)
+ );
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/whoEmpty -'
+ );
+ }
+ }
+ }
+ }
+
+ function insertParsedMessageList($textParts) {
+ // Get the names of all accessible channels:
+ $channelNames = $this->getChannelNames();
+ // Add the own private channel, if allowed:
+ if($this->isAllowedToCreatePrivateChannel()) {
+ array_push($channelNames, $this->getPrivateChannelName());
+ }
+ // Add the invitation channels:
+ foreach($this->getInvitations() as $channelID) {
+ $channelName = $this->getChannelNameFromChannelID($channelID);
+ if($channelName !== null && !in_array($channelName, $channelNames)) {
+ array_push($channelNames, $channelName);
+ }
+ }
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/list '.implode(' ', $channelNames)
+ );
+ }
+
+ function insertParsedMessageWhereis($textParts) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ // Get UserID from UserName:
+ $whereisUserID = $this->getIDFromName($textParts[1]);
+ if($whereisUserID === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ $channelID = $this->getChannelFromID($whereisUserID);
+ if($this->validateChannel($channelID)) {
+ $channelName = $this->getChannelNameFromChannelID($channelID);
+ } else {
+ $channelName = null;
+ }
+ if($channelName === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // List user information:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/whereis '.$textParts[1].' '.$channelName
+ );
+ }
+ }
+ }
+ }
+
+ function insertParsedMessageWhois($textParts) {
+ // Only moderators/admins:
+ if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ // Get UserID from UserName:
+ $whoisUserID = $this->getIDFromName($textParts[1]);
+ if($whoisUserID === null) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameNotFound '.$textParts[1]
+ );
+ } else {
+ // List user information:
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/whois '.$textParts[1].' '.$this->getIPFromID($whoisUserID)
+ );
+ }
+ }
+ } else {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error CommandNotAllowed '.$textParts[0]
+ );
+ }
+ }
+
+ function insertParsedMessageRoll($textParts) {
+ if(count($textParts) == 1) {
+ // default is one d6:
+ $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
+ } else {
+ $diceParts = explode('d', $textParts[1]);
+ if(count($diceParts) == 2) {
+ $number = (int)$diceParts[0];
+ $sides = (int)$diceParts[1];
+
+ // Dice number must be an integer between 1 and 100, else roll only one:
+ $number = ($number > 0 && $number <= 100) ? $number : 1;
+
+ // Sides must be an integer between 1 and 100, else take 6:
+ $sides = ($sides > 0 && $sides <= 100) ? $sides : 6;
+
+ $text = '/roll '.$this->getUserName().' '.$number.'d'.$sides.' ';
+ for($i=0; $i<$number; $i++) {
+ if($i != 0)
+ $text .= ',';
+ $text .= $this->rollDice($sides);
+ }
+ } else {
+ // if dice syntax is invalid, roll one d6:
+ $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
+ }
+ }
+ $this->insertChatBotMessage(
+ $this->getChannel(),
+ $text
+ );
+ }
+
+ function insertParsedMessageNick($textParts) {
+ if(!$this->getConfig('allowNickChange') ||
+ (!$this->getConfig('allowGuestUserName') && $this->getUserRole() == AJAX_CHAT_GUEST)) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error CommandNotAllowed '.$textParts[0]
+ );
+ } else if(count($textParts) == 1) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MissingUserName'
+ );
+ } else {
+ $newUserName = implode(' ', array_slice($textParts, 1));
+ if($newUserName == $this->getLoginUserName()) {
+ // Allow the user to regain the original login userName:
+ $prefix = '';
+ $suffix = '';
+ } else if($this->getUserRole() == AJAX_CHAT_GUEST) {
+ $prefix = $this->getConfig('guestUserPrefix');
+ $suffix = $this->getConfig('guestUserSuffix');
+ } else {
+ $prefix = $this->getConfig('changedNickPrefix');
+ $suffix = $this->getConfig('changedNickSuffix');
+ }
+ $maxLength = $this->getConfig('userNameMaxLength')
+ - $this->stringLength($prefix)
+ - $this->stringLength($suffix);
+ $newUserName = $this->trimString($newUserName, 'UTF-8', $maxLength, true);
+ if(!$newUserName) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error InvalidUserName'
+ );
+ } else {
+ $newUserName = $prefix.$newUserName.$suffix;
+ if($this->isUserNameInUse($newUserName)) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error UserNameInUse'
+ );
+ } else {
+ $oldUserName = $this->getUserName();
+ $this->setUserName($newUserName);
+ $this->updateOnlineList();
+ // Add info message to update the client-side stored userName:
+ $this->addInfoMessage($this->getUserName(), 'userName');
+ $this->insertChatBotMessage(
+ $this->getChannel(),
+ '/nick '.$oldUserName.' '.$newUserName,
+ null,
+ 2
+ );
+ }
+ }
+ }
+ }
+
+ function insertMessage($text) {
+ if(!$this->isAllowedToWriteMessage())
+ return;
+
+ if(!$this->floodControl())
+ return;
+
+ $text = $this->trimMessageText($text);
+ if($text == '')
+ return;
+
+ if(!$this->onNewMessage($text))
+ return;
+
+ $text = $this->replaceCustomText($text);
+
+ $this->insertParsedMessage($text);
+ }
+
+ function deleteMessage($messageID) {
+ // Retrieve the channel of the given message:
+ $sql = 'SELECT
+ channel
+ FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ id='.$this->db->makeSafe($messageID).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $row = $result->fetch();
+
+ if($row['channel'] !== null) {
+ $channel = $row['channel'];
+
+ if($this->getUserRole() == AJAX_CHAT_ADMIN) {
+ $condition = '';
+ } else if($this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ $condition = ' AND
+ NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
+ AND
+ NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')';
+ } else if($this->getUserRole() == AJAX_CHAT_USER && $this->getConfig('allowUserMessageDelete')) {
+ $condition = 'AND
+ (
+ userID='.$this->db->makeSafe($this->getUserID()).'
+ OR
+ (
+ channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
+ OR
+ channel = '.$this->db->makeSafe($this->getPrivateChannelID()).'
+ )
+ AND
+ NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
+ AND
+ NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')
+ )';
+ } else {
+ return false;
+ }
+
+ // Remove given message from the database:
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ id='.$this->db->makeSafe($messageID).'
+ '.$condition.';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ if($result->affectedRows() == 1) {
+ // Insert a deletion command to remove the message from the clients chatlists:
+ $this->insertChatBotMessage($channel, '/delete '.$messageID);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function floodControl() {
+ // Moderators and Admins need no flood control:
+ if($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_ADMIN) {
+ return true;
+ }
+ $time = time();
+ // Check the time of the last inserted message:
+ if($this->getInsertedMessagesRateTimeStamp()+60 < $time) {
+ $this->setInsertedMessagesRateTimeStamp($time);
+ $this->setInsertedMessagesRate(1);
+ } else {
+ // Increase the inserted messages rate:
+ $rate = $this->getInsertedMessagesRate()+1;
+ $this->setInsertedMessagesRate($rate);
+ // Check if message rate is too high:
+ if($rate > $this->getConfig('maxMessageRate')) {
+ $this->insertChatBotMessage(
+ $this->getPrivateMessageID(),
+ '/error MaxMessageRate'
+ );
+ // Return false so the message is not inserted:
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function isAllowedToWriteMessage() {
+ if($this->getUserRole() != AJAX_CHAT_GUEST)
+ return true;
+ if($this->getConfig('allowGuestWrite'))
+ return true;
+ return false;
+ }
+
+ function insertChatBotMessage($channelID, $messageText, $ip=null, $mode=0) {
+ $this->insertCustomMessage(
+ $this->getConfig('chatBotID'),
+ $this->getConfig('chatBotName'),
+ AJAX_CHAT_CHATBOT,
+ $channelID,
+ $messageText,
+ $ip,
+ $mode
+ );
+ }
+
+ function insertCustomMessage($userID, $userName, $userRole, $channelID, $text, $ip=null, $mode=0) {
+ // The $mode parameter is used for socket updates:
+ // 0 = normal messages
+ // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
+ // 2 = messages with online user updates (nick)
+
+ $ip = $ip ? $ip : $_SERVER['REMOTE_ADDR'];
+
+ $sql = 'INSERT INTO '.$this->getDataBaseTable('messages').'(
+ userID,
+ userName,
+ userRole,
+ channel,
+ dateTime,
+ ip,
+ text
+ )
+ VALUES (
+ '.$this->db->makeSafe($userID).',
+ '.$this->db->makeSafe($userName).',
+ '.$this->db->makeSafe($userRole).',
+ '.$this->db->makeSafe($channelID).',
+ NOW(),
+ '.$this->db->makeSafe($this->ipToStorageFormat($ip)).',
+ '.$this->db->makeSafe($text).'
+ );';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ if($this->getConfig('socketServerEnabled')) {
+ $this->sendSocketMessage(
+ $this->getSocketBroadcastMessage(
+ $this->db->getLastInsertedID(),
+ time(),
+ $userID,
+ $userName,
+ $userRole,
+ $channelID,
+ $text,
+ $mode
+ )
+ );
+ }
+ }
+
+ function getSocketBroadcastMessage(
+ $messageID,
+ $timeStamp,
+ $userID,
+ $userName,
+ $userRole,
+ $channelID,
+ $text,
+ $mode
+ ) {
+ // The $mode parameter:
+ // 0 = normal messages
+ // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
+ // 2 = messages with online user updates (nick)
+
+ // Get the message XML content:
+ $xml = '<root chatID="'.$this->getConfig('socketServerChatID').'" channelID="'.$channelID.'" mode="'.$mode.'">';
+ if($mode) {
+ // Add the list of online users if the user list has been updated ($mode > 0):
+ $xml .= $this->getChatViewOnlineUsersXML(array($channelID));
+ }
+ if($mode != 1 || $this->getConfig('showChannelMessages')) {
+ $xml .= '<messages>';
+ $xml .= $this->getChatViewMessageXML(
+ $messageID,
+ $timeStamp,
+ $userID,
+ $userName,
+ $userRole,
+ $channelID,
+ $text
+ );
+ $xml .= '</messages>';
+ }
+ $xml .= '</root>';
+ return $xml;
+ }
+
+ function sendSocketMessage($message) {
+ // Open a TCP socket connection to the socket server:
+ if($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
+ if(@socket_connect($socket, $this->getConfig('socketServerIP'), $this->getConfig('socketServerPort'))) {
+ // Append a null-byte to the string as EOL (End Of Line) character
+ // which is required by Flash XML socket communication:
+ $message .= "\0";
+ @socket_write(
+ $socket,
+ $message,
+ strlen($message) // Using strlen to count the bytes instead of the number of UTF-8 characters
+ );
+ }
+ @socket_close($socket);
+ }
+ }
+
+ function updateSocketAuthentication($userID, $socketRegistrationID=null, $channels=null) {
+ // If no $socketRegistrationID or no $channels are given the authentication is removed for the given user:
+ $authentication = '<authenticate chatID="'.$this->getConfig('socketServerChatID').'" userID="'.$userID.'" regID="'.$socketRegistrationID.'">';
+ if($channels) {
+ foreach($channels as $channelID) {
+ $authentication .= '<channel id="'.$channelID.'"/>';
+ }
+ }
+ $authentication .= '</authenticate>';
+ $this->sendSocketMessage($authentication);
+ }
+
+ function setSocketRegistrationID($value) {
+ $this->setSessionVar('SocketRegistrationID', $value);
+ }
+
+ function getSocketRegistrationID() {
+ return $this->getSessionVar('SocketRegistrationID');
+ }
+
+ function rollDice($sides) {
+ // seed with microseconds since last "whole" second:
+ mt_srand((double)microtime()*1000000);
+
+ return mt_rand(1, $sides);
+ }
+
+ function kickUser($userName, $banMinutes=null, $userID=null) {
+ if($userID === null) {
+ $userID = $this->getIDFromName($userName);
+ }
+ if($userID === null) {
+ return;
+ }
+
+ $banMinutes = $banMinutes ? $banMinutes : $this->getConfig('defaultBanTime');
+
+ if($banMinutes) {
+ // Ban User for the given time in minutes:
+ $this->banUser($userName, $banMinutes, $userID);
+ }
+
+ // Remove given User from online list:
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('online').'
+ WHERE
+ userID = '.$this->db->makeSafe($userID).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ // Update the socket server authentication for the kicked user:
+ if($this->getConfig('socketServerEnabled')) {
+ $this->updateSocketAuthentication($userID);
+ }
+
+ $this->removeUserFromOnlineUsersData($userID);
+ }
+
+ function getBannedUsersData($key=null, $value=null) {
+ if($this->_bannedUsersData === null) {
+ $this->_bannedUsersData = array();
+
+ $sql = 'SELECT
+ userID,
+ userName,
+ ip
+ FROM
+ '.$this->getDataBaseTable('bans').'
+ WHERE
+ NOW() < dateTime;';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ while($row = $result->fetch()) {
+ $row['ip'] = $this->ipFromStorageFormat($row['ip']);
+ array_push($this->_bannedUsersData, $row);
+ }
+
+ $result->free();
+ }
+
+ if($key) {
+ $bannedUsersData = array();
+ foreach($this->_bannedUsersData as $bannedUserData) {
+ if(!isset($bannedUserData[$key])) {
+ return $bannedUsersData;
+ }
+ if($value) {
+ if($bannedUserData[$key] == $value) {
+ array_push($bannedUsersData, $bannedUserData);
+ } else {
+ continue;
+ }
+ } else {
+ array_push($bannedUsersData, $bannedUserData[$key]);
+ }
+ }
+ return $bannedUsersData;
+ }
+
+ return $this->_bannedUsersData;
+ }
+
+ function getBannedUsers() {
+ return $this->getBannedUsersData('userName');
+ }
+
+ function banUser($userName, $banMinutes=null, $userID=null) {
+ if($userID === null) {
+ $userID = $this->getIDFromName($userName);
+ }
+ $ip = $this->getIPFromID($userID);
+ if(!$ip || $userID === null) {
+ return;
+ }
+
+ // Remove expired bans:
+ $this->removeExpiredBans();
+
+ $banMinutes = (int)$banMinutes;
+ if(!$banMinutes) {
+ // If banMinutes is not a valid integer, use the defaultBanTime:
+ $banMinutes = $this->getConfig('defaultBanTime');
+ }
+
+ $sql = 'INSERT INTO '.$this->getDataBaseTable('bans').'(
+ userID,
+ userName,
+ dateTime,
+ ip
+ )
+ VALUES (
+ '.$this->db->makeSafe($userID).',
+ '.$this->db->makeSafe($userName).',
+ DATE_ADD(NOW(), interval '.$this->db->makeSafe($banMinutes).' MINUTE),
+ '.$this->db->makeSafe($this->ipToStorageFormat($ip)).'
+ );';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function unbanUser($userName) {
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('bans').'
+ WHERE
+ userName = '.$this->db->makeSafe($userName).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function removeExpiredBans() {
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('bans').'
+ WHERE
+ dateTime < NOW();';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function setInactive($userID, $userName=null) {
+ $condition = 'userID='.$this->db->makeSafe($userID);
+ if($userName !== null) {
+ $condition .= ' OR userName='.$this->db->makeSafe($userName);
+ }
+ $sql = 'UPDATE
+ '.$this->getDataBaseTable('online').'
+ SET
+ dateTime = DATE_SUB(NOW(), interval '.(intval($this->getConfig('inactiveTimeout'))+1).' MINUTE)
+ WHERE
+ '.$condition.';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $this->resetOnlineUsersData();
+ }
+
+ function removeInactive() {
+ $sql = 'SELECT
+ userID,
+ userName,
+ channel
+ FROM
+ '.$this->getDataBaseTable('online').'
+ WHERE
+ NOW() > DATE_ADD(dateTime, interval '.$this->getConfig('inactiveTimeout').' MINUTE);';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ if($result->numRows() > 0) {
+ $condition = '';
+ while($row = $result->fetch()) {
+ if(!empty($condition))
+ $condition .= ' OR ';
+ // Add userID to condition for removal:
+ $condition .= 'userID='.$this->db->makeSafe($row['userID']);
+
+ // Update the socket server authentication for the kicked user:
+ if($this->getConfig('socketServerEnabled')) {
+ $this->updateSocketAuthentication($row['userID']);
+ }
+
+ $this->removeUserFromOnlineUsersData($row['userID']);
+
+ // Insert logout timeout message:
+ $text = '/logout '.$row['userName'].' Timeout';
+ $this->insertChatBotMessage(
+ $row['channel'],
+ $text,
+ null,
+ 1
+ );
+ }
+
+ $result->free();
+
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('online').'
+ WHERE
+ '.$condition.';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+ }
+
+ function updateOnlineStatus() {
+ // Update online status every 50 seconds (this allows update requests to be in time):
+ if(!$this->getStatusUpdateTimeStamp() || ((time() - $this->getStatusUpdateTimeStamp()) > 50)) {
+ $this->updateOnlineList();
+ $this->setStatusUpdateTimeStamp(time());
+ }
+ }
+
+ function checkAndRemoveInactive() {
+ // Remove inactive users every inactiveCheckInterval:
+ if(!$this->getInactiveCheckTimeStamp() || ((time() - $this->getInactiveCheckTimeStamp()) > $this->getConfig('inactiveCheckInterval')*60)) {
+ $this->removeInactive();
+ $this->setInactiveCheckTimeStamp(time());
+ }
+ }
+
+ function sendXMLMessages() {
+ $httpHeader = new AJAXChatHTTPHeader('UTF-8', 'text/xml');
+
+ // Send HTTP header:
+ $httpHeader->send();
+
+ // Output XML messages:
+ echo $this->getXMLMessages();
+ }
+
+ function getXMLMessages() {
+ switch($this->getView()) {
+ case 'chat':
+ return $this->getChatViewXMLMessages();
+ case 'teaser':
+ return $this->getTeaserViewXMLMessages();
+ case 'logs':
+ return $this->getLogsViewXMLMessages();
+ default:
+ return $this->getLogoutXMLMessage();
+ }
+ }
+
+ function getMessageCondition() {
+ $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')).'
+ AND (
+ channel = '.$this->db->makeSafe($this->getChannel()).'
+ OR
+ channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
+ )
+ AND
+ ';
+ if($this->getConfig('requestMessagesPriorChannelEnter') ||
+ ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($this->getChannel(), $this->getConfig('requestMessagesPriorChannelEnterList')))) {
+ $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
+ } else {
+ $condition .= 'dateTime >= FROM_UNIXTIME(' . $this->getChannelEnterTimeStamp() . ')';
+ }
+ return $condition;
+ }
+
+ function getMessageFilter() {
+ $filterChannelMessages = '';
+ if(!$this->getConfig('showChannelMessages') || $this->getRequestVar('shoutbox')) {
+ $filterChannelMessages = ' AND NOT (
+ text LIKE (\'/login%\')
+ OR
+ text LIKE (\'/logout%\')
+ OR
+ text LIKE (\'/channelEnter%\')
+ OR
+ text LIKE (\'/channelLeave%\')
+ OR
+ text LIKE (\'/kick%\')
+ )';
+ }
+ return $filterChannelMessages;
+ }
+
+ function getInfoMessagesXML() {
+ $xml = '<infos>';
+ // Go through the info messages:
+ foreach($this->getInfoMessages() as $type=>$infoArray) {
+ foreach($infoArray as $info) {
+ $xml .= '<info type="'.$type.'">';
+ $xml .= '<![CDATA['.$this->encodeSpecialChars($info).']]>';
+ $xml .= '</info>';
+ }
+ }
+ $xml .= '</infos>';
+ return $xml;
+ }
+
+ function getChatViewOnlineUsersXML($channelIDs) {
+ // Get the online users for the given channels:
+ $onlineUsersData = $this->getOnlineUsersData($channelIDs);
+ $xml = '<users>';
+ foreach($onlineUsersData as $onlineUserData) {
+ $xml .= '<user';
+ $xml .= ' userID="'.$onlineUserData['userID'].'"';
+ $xml .= ' userRole="'.$onlineUserData['userRole'].'"';
+ $xml .= ' channelID="'.$onlineUserData['channel'].'"';
+ $xml .= '>';
+ $xml .= '<![CDATA['.$this->encodeSpecialChars($onlineUserData['userName']).']]>';
+ $xml .= '</user>';
+ }
+ $xml .= '</users>';
+ return $xml;
+ }
+
+ function getLogoutXMLMessage() {
+ $xml = '<?xml version="1.0" encoding="UTF-8"?>';
+ $xml .= '<root>';
+ $xml .= '<infos>';
+ $xml .= '<info type="logout">';
+ $xml .= '<![CDATA['.$this->encodeSpecialChars($this->getConfig('logoutData')).']]>';
+ $xml .= '</info>';
+ $xml .= '</infos>';
+ $xml .= '</root>';
+ return $xml;
+ }
+
+ function getChatViewMessageXML(
+ $messageID,
+ $timeStamp,
+ $userID,
+ $userName,
+ $userRole,
+ $channelID,
+ $text
+ ) {
+ $message = '<message';
+ $message .= ' id="'.$messageID.'"';
+ $message .= ' dateTime="'.date('r', $timeStamp).'"';
+ $message .= ' userID="'.$userID.'"';
+ $message .= ' userRole="'.$userRole.'"';
+ $message .= ' channelID="'.$channelID.'"';
+ $message .= '>';
+ $message .= '<username><![CDATA['.$this->encodeSpecialChars($userName).']]></username>';
+ $message .= '<text><![CDATA['.$this->encodeSpecialChars($text).']]></text>';
+ $message .= '</message>';
+ return $message;
+ }
+
+ function getChatViewMessagesXML() {
+ // Get the last messages in descending order (this optimises the LIMIT usage):
+ $sql = 'SELECT
+ id,
+ userID,
+ userName,
+ userRole,
+ channel AS channelID,
+ UNIX_TIMESTAMP(dateTime) AS timeStamp,
+ text
+ FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ '.$this->getMessageCondition().'
+ '.$this->getMessageFilter().'
+ ORDER BY
+ id
+ DESC
+ LIMIT '.$this->getConfig('requestMessagesLimit').';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $messages = '';
+
+ // Add the messages in reverse order so it is ascending again:
+ while($row = $result->fetch()) {
+ $message = $this->getChatViewMessageXML(
+ $row['id'],
+ $row['timeStamp'],
+ $row['userID'],
+ $row['userName'],
+ $row['userRole'],
+ $row['channelID'],
+ $row['text']
+ );
+ $messages = $message.$messages;
+ }
+ $result->free();
+
+ $messages = '<messages>'.$messages.'</messages>';
+ return $messages;
+ }
+
+ function getChatViewXMLMessages() {
+ $xml = '<?xml version="1.0" encoding="UTF-8"?>';
+ $xml .= '<root>';
+ $xml .= $this->getInfoMessagesXML();
+ $xml .= $this->getChatViewOnlineUsersXML(array($this->getChannel()));
+ $xml .= $this->getChatViewMessagesXML();
+ $xml .= '</root>';
+ return $xml;
+ }
+
+ function getTeaserMessageCondition() {
+ $channelID = $this->getValidRequestChannelID();
+ $condition = 'channel = '.$this->db->makeSafe($channelID).'
+ AND
+ ';
+ if($this->getConfig('requestMessagesPriorChannelEnter') ||
+ ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($channelID, $this->getConfig('requestMessagesPriorChannelEnterList')))) {
+ $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
+ } else {
+ // Teaser content may not be shown for this channel:
+ $condition .= '0 = 1';
+ }
+ return $condition;
+ }
+
+ function getTeaserViewMessagesXML() {
+ // Get the last messages in descending order (this optimises the LIMIT usage):
+ $sql = 'SELECT
+ id,
+ userID,
+ userName,
+ userRole,
+ channel AS channelID,
+ UNIX_TIMESTAMP(dateTime) AS timeStamp,
+ text
+ FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ '.$this->getTeaserMessageCondition().'
+ '.$this->getMessageFilter().'
+ ORDER BY
+ id
+ DESC
+ LIMIT '.$this->getConfig('requestMessagesLimit').';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $messages = '';
+
+ // Add the messages in reverse order so it is ascending again:
+ while($row = $result->fetch()) {
+ $message = '';
+ $message .= '<message';
+ $message .= ' id="'.$row['id'].'"';
+ $message .= ' dateTime="'.date('r', $row['timeStamp']).'"';
+ $message .= ' userID="'.$row['userID'].'"';
+ $message .= ' userRole="'.$row['userRole'].'"';
+ $message .= ' channelID="'.$row['channelID'].'"';
+ $message .= '>';
+ $message .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
+ $message .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
+ $message .= '</message>';
+ $messages = $message.$messages;
+ }
+ $result->free();
+
+ $messages = '<messages>'.$messages.'</messages>';
+ return $messages;
+ }
+
+ function getTeaserViewXMLMessages() {
+ $xml = '<?xml version="1.0" encoding="UTF-8"?>';
+ $xml .= '<root>';
+ $xml .= $this->getInfoMessagesXML();
+ $xml .= $this->getTeaserViewMessagesXML();
+ $xml .= '</root>';
+ return $xml;
+ }
+
+ function getLogsViewCondition() {
+ $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID'));
+
+ // Check the channel condition:
+ switch($this->getRequestVar('channelID')) {
+ case '-3':
+ // Just display messages from all accessible channels
+ if($this->getUserRole() != AJAX_CHAT_ADMIN) {
+ $condition .= ' AND (channel = '.$this->db->makeSafe($this->getPrivateMessageID());
+ $condition .= ' OR channel = '.$this->db->makeSafe($this->getPrivateChannelID());
+ foreach($this->getChannels() as $channel) {
+ if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
+ continue;
+ }
+ $condition .= ' OR channel = '.$this->db->makeSafe($channel);
+ }
+ $condition .= ')';
+ }
+ break;
+ case '-2':
+ if($this->getUserRole() != AJAX_CHAT_ADMIN) {
+ $condition .= ' AND channel = '.($this->getPrivateMessageID());
+ } else {
+ $condition .= ' AND channel > '.($this->getConfig('privateMessageDiff')-1);
+ }
+ break;
+ case '-1':
+ if($this->getUserRole() != AJAX_CHAT_ADMIN) {
+ $condition .= ' AND channel = '.($this->getPrivateChannelID());
+ } else {
+ $condition .= ' AND (channel > '.($this->getConfig('privateChannelDiff')-1).' AND channel < '.($this->getConfig('privateMessageDiff')).')';
+ }
+ break;
+ default:
+ if(($this->getUserRole() == AJAX_CHAT_ADMIN || !$this->getConfig('logsUserAccessChannelList') || in_array($this->getRequestVar('channelID'), $this->getConfig('logsUserAccessChannelList')))
+ && $this->validateChannel($this->getRequestVar('channelID'))) {
+ $condition .= ' AND channel = '.$this->db->makeSafe($this->getRequestVar('channelID'));
+ } else {
+ // No valid channel:
+ $condition .= ' AND 0 = 1';
+ }
+ }
+
+ // Check the period condition:
+ $hour = ($this->getRequestVar('hour') === null || $this->getRequestVar('hour') > 23 || $this->getRequestVar('hour') < 0) ? null : $this->getRequestVar('hour');
+ $day = ($this->getRequestVar('day') === null || $this->getRequestVar('day') > 31 || $this->getRequestVar('day') < 1) ? null : $this->getRequestVar('day');
+ $month = ($this->getRequestVar('month') === null || $this->getRequestVar('month') > 12 || $this->getRequestVar('month') < 1) ? null : $this->getRequestVar('month');
+ $year = ($this->getRequestVar('year') === null || $this->getRequestVar('year') > date('Y') || $this->getRequestVar('year') < $this->getConfig('logsFirstYear')) ? null : $this->getRequestVar('year');
+
+ // If a time (hour) is given but no date (year, month, day), use the current date:
+ if($hour !== null) {
+ if($day === null)
+ $day = date('j');
+ if($month === null)
+ $month = date('n');
+ if($year === null)
+ $year = date('Y');
+ }
+
+ if($year === null) {
+ // No year given, so no period condition
+ } else if($month === null) {
+ // Define the given year as period:
+ $periodStart = mktime(0, 0, 0, 1, 1, $year);
+ // The last day in a month can be expressed by using 0 for the day of the next month:
+ $periodEnd = mktime(23, 59, 59, 13, 0, $year);
+ } else if($day === null) {
+ // Define the given month as period:
+ $periodStart = mktime(0, 0, 0, $month, 1, $year);
+ // The last day in a month can be expressed by using 0 for the day of the next month:
+ $periodEnd = mktime(23, 59, 59, $month+1, 0, $year);
+ } else if($hour === null){
+ // Define the given day as period:
+ $periodStart = mktime(0, 0, 0, $month, $day, $year);
+ $periodEnd = mktime(23, 59, 59, $month, $day, $year);
+ } else {
+ // Define the given hour as period:
+ $periodStart = mktime($hour, 0, 0, $month, $day, $year);
+ $periodEnd = mktime($hour, 59, 59, $month, $day, $year);
+ }
+
+ if(isset($periodStart))
+ $condition .= ' AND dateTime > \''.date('Y-m-d H:i:s', $periodStart).'\' AND dateTime <= \''.date('Y-m-d H:i:s', $periodEnd).'\'';
+
+ // Check the search condition:
+ if($this->getRequestVar('search')) {
+ if(($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) && strpos($this->getRequestVar('search'), 'ip=') === 0) {
+ // Search for messages with the given IP:
+ $ip = substr($this->getRequestVar('search'), 3);
+ $condition .= ' AND (ip = '.$this->db->makeSafe($this->ipToStorageFormat($ip)).')';
+ } else if(strpos($this->getRequestVar('search'), 'userID=') === 0) {
+ // Search for messages with the given userID:
+ $userID = substr($this->getRequestVar('search'), 7);
+ $condition .= ' AND (userID = '.$this->db->makeSafe($userID).')';
+ } else {
+ // Use the search value as regular expression on message text and username:
+ $condition .= ' AND (userName REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).' OR text REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).')';
+ }
+ }
+
+ // If no period or search condition is given, just monitor the last messages on the given channel:
+ if(!isset($periodStart) && !$this->getRequestVar('search')) {
+ $condition .= ' AND NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('logsRequestMessagesTimeDiff').' HOUR)';
+ }
+
+ return $condition;
+ }
+
+ function getLogsViewMessagesXML() {
+ $sql = 'SELECT
+ id,
+ userID,
+ userName,
+ userRole,
+ channel AS channelID,
+ UNIX_TIMESTAMP(dateTime) AS timeStamp,
+ ip,
+ text
+ FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ '.$this->getLogsViewCondition().'
+ ORDER BY
+ id
+ LIMIT '.$this->getConfig('logsRequestMessagesLimit').';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ $xml = '<messages>';
+ while($row = $result->fetch()) {
+ $xml .= '<message';
+ $xml .= ' id="'.$row['id'].'"';
+ $xml .= ' dateTime="'.date('r', $row['timeStamp']).'"';
+ $xml .= ' userID="'.$row['userID'].'"';
+ $xml .= ' userRole="'.$row['userRole'].'"';
+ $xml .= ' channelID="'.$row['channelID'].'"';
+ if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
+ $xml .= ' ip="'.$this->ipFromStorageFormat($row['ip']).'"';
+ }
+ $xml .= '>';
+ $xml .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
+ $xml .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
+ $xml .= '</message>';
+ }
+ $result->free();
+
+ $xml .= '</messages>';
+
+ return $xml;
+ }
+
+ function getLogsViewXMLMessages() {
+ $xml = '<?xml version="1.0" encoding="UTF-8"?>';
+ $xml .= '<root>';
+ $xml .= $this->getInfoMessagesXML();
+ $xml .= $this->getLogsViewMessagesXML();
+ $xml .= '</root>';
+ return $xml;
+ }
+
+ function purgeLogs() {
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('messages').'
+ WHERE
+ dateTime < DATE_SUB(NOW(), interval '.$this->getConfig('logsPurgeTimeDiff').' DAY);';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function getInfoMessages($type=null) {
+ if(!isset($this->_infoMessages)) {
+ $this->_infoMessages = array();
+ }
+ if($type) {
+ if(!isset($this->_infoMessages[$type])) {
+ $this->_infoMessages[$type] = array();
+ }
+ return $this->_infoMessages[$type];
+ } else {
+ return $this->_infoMessages;
+ }
+ }
+
+ function addInfoMessage($info, $type='error') {
+ if(!isset($this->_infoMessages)) {
+ $this->_infoMessages = array();
+ }
+ if(!isset($this->_infoMessages[$type])) {
+ $this->_infoMessages[$type] = array();
+ }
+ if(!in_array($info, $this->_infoMessages[$type])) {
+ array_push($this->_infoMessages[$type], $info);
+ }
+ }
+
+ function getRequestVars() {
+ return $this->_requestVars;
+ }
+
+ function getRequestVar($key) {
+ if($this->_requestVars && isset($this->_requestVars[$key])) {
+ return $this->_requestVars[$key];
+ }
+ return null;
+ }
+
+ function setRequestVar($key, $value) {
+ if(!$this->_requestVars) {
+ $this->_requestVars = array();
+ }
+ $this->_requestVars[$key] = $value;
+ }
+
+ function getOnlineUsersData($channelIDs=null, $key=null, $value=null) {
+ if($this->_onlineUsersData === null) {
+ $this->_onlineUsersData = array();
+
+ $sql = 'SELECT
+ userID,
+ userName,
+ userRole,
+ channel,
+ UNIX_TIMESTAMP(dateTime) AS timeStamp,
+ ip
+ FROM
+ '.$this->getDataBaseTable('online').'
+ ORDER BY
+ userName;';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ while($row = $result->fetch()) {
+ $row['ip'] = $this->ipFromStorageFormat($row['ip']);
+ array_push($this->_onlineUsersData, $row);
+ }
+
+ $result->free();
+ }
+
+ if($channelIDs || $key) {
+ $onlineUsersData = array();
+ foreach($this->_onlineUsersData as $userData) {
+ if($channelIDs && !in_array($userData['channel'], $channelIDs)) {
+ continue;
+ }
+ if($key) {
+ if(!isset($userData[$key])) {
+ return $onlineUsersData;
+ }
+ if($value !== null) {
+ if($userData[$key] == $value) {
+ array_push($onlineUsersData, $userData);
+ } else {
+ continue;
+ }
+ } else {
+ array_push($onlineUsersData, $userData[$key]);
+ }
+ } else {
+ array_push($onlineUsersData, $userData);
+ }
+ }
+ return $onlineUsersData;
+ }
+
+ return $this->_onlineUsersData;
+ }
+
+ function removeUserFromOnlineUsersData($userID=null) {
+ if(!$this->_onlineUsersData) {
+ return;
+ }
+ $userID = ($userID === null) ? $this->getUserID() : $userID;
+ for($i=0; $i<count($this->_onlineUsersData); $i++) {
+ if($this->_onlineUsersData[$i]['userID'] == $userID) {
+ array_splice($this->_onlineUsersData, $i, 1);
+ break;
+ }
+ }
+ }
+
+ function resetOnlineUsersData() {
+ $this->_onlineUsersData = null;
+ }
+
+ function getOnlineUsers($channelIDs=null) {
+ return $this->getOnlineUsersData($channelIDs, 'userName');
+ }
+
+ function getOnlineUserIDs($channelIDs=null) {
+ return $this->getOnlineUsersData($channelIDs, 'userID');
+ }
+
+ function startSession() {
+ if(!session_id()) {
+ // Set the session name:
+ session_name($this->getConfig('sessionName'));
+
+ // Set session cookie parameters:
+ session_set_cookie_params(
+ 0, // The session is destroyed on logout anyway, so no use to set this
+ $this->getConfig('sessionCookiePath'),
+ $this->getConfig('sessionCookieDomain'),
+ $this->getConfig('sessionCookieSecure')
+ );
+
+ // Start the session:
+ session_start();
+
+ // We started a new session:
+ $this->_sessionNew = true;
+ }
+ }
+
+ function destroySession() {
+ if($this->_sessionNew) {
+ // Delete all session variables:
+ $_SESSION = array();
+
+ // Delete the session cookie:
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(
+ session_name(),
+ '',
+ time()-42000,
+ $this->getConfig('sessionCookiePath'),
+ $this->getConfig('sessionCookieDomain'),
+ $this->getConfig('sessionCookieSecure')
+ );
+ }
+
+ // Destroy the session:
+ session_destroy();
+ } else {
+ // Unset all session variables starting with the sessionKeyPrefix:
+ foreach($_SESSION as $key=>$value) {
+ if(strpos($key, $this->getConfig('sessionKeyPrefix')) === 0) {
+ unset($_SESSION[$key]);
+ }
+ }
+ }
+ }
+
+ function regenerateSessionID() {
+ if($this->_sessionNew) {
+ // Regenerate session id:
+ @session_regenerate_id(true);
+ }
+ }
+
+ function getSessionVar($key, $prefix=null) {
+ if($prefix === null)
+ $prefix = $this->getConfig('sessionKeyPrefix');
+
+ // Return the session value if existing:
+ if(isset($_SESSION[$prefix.$key]))
+ return $_SESSION[$prefix.$key];
+ else
+ return null;
+ }
+
+ function setSessionVar($key, $value, $prefix=null) {
+ if($prefix === null)
+ $prefix = $this->getConfig('sessionKeyPrefix');
+
+ // Set the session value:
+ $_SESSION[$prefix.$key] = $value;
+ }
+
+ function getSessionIP() {
+ return $this->getSessionVar('IP');
+ }
+
+ function setSessionIP($ip) {
+ $this->setSessionVar('IP', $ip);
+ }
+
+ function getQueryUserName() {
+ return $this->getSessionVar('QueryUserName');
+ }
+
+ function setQueryUserName($userName) {
+ $this->setSessionVar('QueryUserName', $userName);
+ }
+
+ function getInvitations() {
+ if($this->_invitations === null) {
+ $this->_invitations = array();
+
+ $sql = 'SELECT
+ channel
+ FROM
+ '.$this->getDataBaseTable('invitations').'
+ WHERE
+ userID='.$this->db->makeSafe($this->getUserID()).'
+ AND
+ DATE_SUB(NOW(), interval 1 DAY) < dateTime;';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+
+ while($row = $result->fetch()) {
+ array_push($this->_invitations, $row['channel']);
+ }
+
+ $result->free();
+ }
+ return $this->_invitations;
+ }
+
+ function removeExpiredInvitations() {
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('invitations').'
+ WHERE
+ DATE_SUB(NOW(), interval 1 DAY) > dateTime;';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function addInvitation($userID, $channelID=null) {
+ $this->removeExpiredInvitations();
+
+ $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
+
+ $sql = 'INSERT INTO '.$this->getDataBaseTable('invitations').'(
+ userID,
+ channel,
+ dateTime
+ )
+ VALUES (
+ '.$this->db->makeSafe($userID).',
+ '.$this->db->makeSafe($channelID).',
+ NOW()
+ );';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function removeInvitation($userID, $channelID=null) {
+ $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
+
+ $sql = 'DELETE FROM
+ '.$this->getDataBaseTable('invitations').'
+ WHERE
+ userID='.$this->db->makeSafe($userID).'
+ AND
+ channel='.$this->db->makeSafe($channelID).';';
+
+ // Create a new SQL query:
+ $result = $this->db->sqlQuery($sql);
+
+ // Stop if an error occurs:
+ if($result->error()) {
+ echo $result->getError();
+ die();
+ }
+ }
+
+ function getUserID() {
+ return $this->getSessionVar('UserID');
+ }
+
+ function setUserID($id) {
+ $this->setSessionVar('UserID', $id);
+ }
+
+ function getUserName() {
+ return $this->getSessionVar('UserName');
+ }
+
+ function setUserName($name) {
+ $this->setSessionVar('UserName', $name);
+ }
+
+ function getLoginUserName() {
+ return $this->getSessionVar('LoginUserName');
+ }
+
+ function setLoginUserName($name) {
+ $this->setSessionVar('LoginUserName', $name);
+ }
+
+ function getUserRole() {
+ $userRole = $this->getSessionVar('UserRole');
+ if($userRole === null)
+ return AJAX_CHAT_GUEST;
+ return $userRole;
+ }
+
+ function setUserRole($role) {
+ $this->setSessionVar('UserRole', $role);
+ }
+
+ function getChannel() {
+ return $this->getSessionVar('Channel');
+ }
+
+ function setChannel($channel) {
+ $this->setSessionVar('Channel', $channel);
+
+ // Save the channel enter timestamp:
+ $this->setChannelEnterTimeStamp(time());
+
+ // Update the channel authentication for the socket server:
+ if($this->getConfig('socketServerEnabled')) {
+ $this->updateSocketAuthentication(
+ $this->getUserID(),
+ $this->getSocketRegistrationID(),
+ array($channel,$this->getPrivateMessageID())
+ );
+ }
+
+ // Reset the logs view socket authentication session var:
+ if($this->getSessionVar('logsViewSocketAuthenticated')) {
+ $this->setSessionVar('logsViewSocketAuthenticated', false);
+ }
+ }
+
+ function isLoggedIn() {
+ return (bool)$this->getSessionVar('LoggedIn');
+ }
+
+ function setLoggedIn($bool) {
+ $this->setSessionVar('LoggedIn', $bool);
+ }
+
+ function getLoginTimeStamp() {
+ return $this->getSessionVar('LoginTimeStamp');
+ }
+
+ function setLoginTimeStamp($time) {
+ $this->setSessionVar('LoginTimeStamp', $time);
+ }
+
+ function getChannelEnterTimeStamp() {
+ return $this->getSessionVar('ChannelEnterTimeStamp');
+ }
+
+ function setChannelEnterTimeStamp($time) {
+ $this->setSessionVar('ChannelEnterTimeStamp', $time);
+ }
+
+ function getStatusUpdateTimeStamp() {
+ return $this->getSessionVar('StatusUpdateTimeStamp');
+ }
+
+ function setStatusUpdateTimeStamp($time) {
+ $this->setSessionVar('StatusUpdateTimeStamp', $time);
+ }
+
+ function getInactiveCheckTimeStamp() {
+ return $this->getSessionVar('InactiveCheckTimeStamp');
+ }
+
+ function setInactiveCheckTimeStamp($time) {
+ $this->setSessionVar('InactiveCheckTimeStamp', $time);
+ }
+
+ function getInsertedMessagesRate() {
+ return $this->getSessionVar('InsertedMessagesRate');
+ }
+
+ function setInsertedMessagesRate($rate) {
+ $this->setSessionVar('InsertedMessagesRate', $rate);
+ }
+
+ function getInsertedMessagesRateTimeStamp() {
+ return $this->getSessionVar('InsertedMessagesRateTimeStamp');
+ }
+
+ function setInsertedMessagesRateTimeStamp($time) {
+ $this->setSessionVar('InsertedMessagesRateTimeStamp', $time);
+ }
+
+ function getLangCode() {
+ // Get the langCode from request or cookie:
+ $langCodeCookie = isset($_COOKIE[$this->getConfig('sessionName').'_lang']) ? $_COOKIE[$this->getConfig('sessionName').'_lang'] : null;
+ $langCode = $this->getRequestVar('lang') ? $this->getRequestVar('lang') : $langCodeCookie;
+ // Check if the langCode is valid:
+ if(!in_array($langCode, $this->getConfig('langAvailable'))) {
+ // Determine the user language:
+ $language = new AJAXChatLanguage($this->getConfig('langAvailable'), $this->getConfig('langDefault'));
+ $langCode = $language->getLangCode();
+ }
+ return $langCode;
+ }
+
+ function setLangCodeCookie() {
+ setcookie(
+ $this->getConfig('sessionName').'_lang',
+ $this->getLangCode(),
+ time()+60*60*24*$this->getConfig('sessionCookieLifeTime'),
+ $this->getConfig('sessionCookiePath'),
+ $this->getConfig('sessionCookieDomain'),
+ $this->getConfig('sessionCookieSecure')
+ );
+ }
+
+ function removeUnsafeCharacters($str) {
+ // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127:
+ return AJAXChatEncoding::removeUnsafeCharacters($str);
+ }
+
+ function subString($str, $start=0, $length=null, $encoding='UTF-8') {
+ return AJAXChatString::subString($str, $start, $length, $encoding);
+ }
+
+ function stringLength($str, $encoding='UTF-8') {
+ return AJAXChatString::stringLength($str, $encoding);
+ }
+
+ function trimMessageText($text) {
+ return $this->trimString($text, 'UTF-8', $this->getConfig('messageTextMaxLength'));
+ }
+
+ function trimUserName($userName) {
+ return $this->trimString($userName, null, $this->getConfig('userNameMaxLength'), true, true);
+ }
+
+ function trimChannelName($channelName) {
+ return $this->trimString($channelName, null, null, true, true);
+ }
+
+ function trimString($str, $sourceEncoding=null, $maxLength=null, $replaceWhitespace=false, $decodeEntities=false, $htmlEntitiesMap=null) {
+ // Make sure the string contains valid unicode:
+ $str = $this->convertToUnicode($str, $sourceEncoding);
+
+ // Make sure the string contains no unsafe characters:
+ $str = $this->removeUnsafeCharacters($str);
+
+ // Strip whitespace from the beginning and end of the string:
+ $str = trim($str);
+
+ if($replaceWhitespace) {
+ // Replace any whitespace in the userName with the underscore "_":
+ $str = preg_replace('/\s/u', '_', $str);
+ }
+
+ if($decodeEntities) {
+ // Decode entities:
+ $str = $this->decodeEntities($str, 'UTF-8', $htmlEntitiesMap);
+ }
+
+ if($maxLength) {
+ // Cut the string to the allowed length:
+ $str = $this->subString($str, 0, $maxLength);
+ }
+
+ return $str;
+ }
+
+ function convertToUnicode($str, $sourceEncoding=null) {
+ if($sourceEncoding === null) {
+ $sourceEncoding = $this->getConfig('sourceEncoding');
+ }
+ return $this->convertEncoding($str, $sourceEncoding, 'UTF-8');
+ }
+
+ function convertFromUnicode($str, $contentEncoding=null) {
+ if($contentEncoding === null) {
+ $contentEncoding = $this->getConfig('contentEncoding');
+ }
+ return $this->convertEncoding($str, 'UTF-8', $contentEncoding);
+ }
+
+ function convertEncoding($str, $charsetFrom, $charsetTo) {
+ return AJAXChatEncoding::convertEncoding($str, $charsetFrom, $charsetTo);
+ }
+
+ function encodeEntities($str, $encoding='UTF-8', $convmap=null) {
+ return AJAXChatEncoding::encodeEntities($str, $encoding, $convmap);
+ }
+
+ function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) {
+ return AJAXChatEncoding::decodeEntities($str, $encoding, $htmlEntitiesMap);
+ }
+
+ function htmlEncode($str) {
+ return AJAXChatEncoding::htmlEncode($str, $this->getConfig('contentEncoding'));
+ }
+
+ function encodeSpecialChars($str) {
+ return AJAXChatEncoding::encodeSpecialChars($str);
+ }
+
+ function decodeSpecialChars($str) {
+ return AJAXChatEncoding::decodeSpecialChars($str);
+ }
+
+ function ipToStorageFormat($ip) {
+ if(function_exists('inet_pton')) {
+ // ipv4 & ipv6:
+ return @inet_pton($ip);
+ }
+ // Only ipv4:
+ return @pack('N',@ip2long($ip));
+ }
+
+ function ipFromStorageFormat($ip) {
+ if(function_exists('inet_ntop')) {
+ // ipv4 & ipv6:
+ return @inet_ntop($ip);
+ }
+ // Only ipv4:
+ $unpacked = @unpack('Nlong',$ip);
+ if(isset($unpacked['long'])) {
+ return @long2ip($unpacked['long']);
+ }
+ return null;
+ }
+
+ function getConfig($key, $subkey=null) {
+ if($subkey)
+ return $this->_config[$key][$subkey];
+ else
+ return $this->_config[$key];
+ }
+
+ function setConfig($key, $subkey, $value) {
+ if($subkey) {
+ if(!isset($this->_config[$key])) {
+ $this->_config[$key] = array();
+ }
+ $this->_config[$key][$subkey] = $value;
+ } else {
+ $this->_config[$key] = $value;
+ }
+ }
+
+ function getLang($key=null) {
+ if(!$this->_lang) {
+ // Include the language file:
+ $lang = null;
+ require(AJAX_CHAT_PATH.'lib/lang/'.$this->getLangCode().'.php');
+ $this->_lang = &$lang;
+ }
+ if($key === null)
+ return $this->_lang;
+ if(isset($this->_lang[$key]))
+ return $this->_lang[$key];
+ return null;
+ }
+
+ function getChatURL() {
+ if(defined('AJAX_CHAT_URL')) {
+ return AJAX_CHAT_URL;
+ }
+
+ return
+ (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').
+ (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
+ (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
+ (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443 || $_SERVER['SERVER_PORT'] == 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
+ substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')+1);
+ }
+
+ function getIDFromName($userName) {
+ $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
+ if($userDataArray && isset($userDataArray[0])) {
+ return $userDataArray[0]['userID'];
+ }
+ return null;
+ }
+
+ function getNameFromID($userID) {
+ $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
+ if($userDataArray && isset($userDataArray[0])) {
+ return $userDataArray[0]['userName'];
+ }
+ return null;
+ }
+
+ function getChannelFromID($userID) {
+ $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
+ if($userDataArray && isset($userDataArray[0])) {
+ return $userDataArray[0]['channel'];
+ }
+ return null;
+ }
+
+ function getIPFromID($userID) {
+ $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
+ if($userDataArray && isset($userDataArray[0])) {
+ return $userDataArray[0]['ip'];
+ }
+ return null;
+ }
+
+ function getRoleFromID($userID) {
+ $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
+ if($userDataArray && isset($userDataArray[0])) {
+ return $userDataArray[0]['userRole'];
+ }
+ return null;
+ }
+
+ function getChannelNames() {
+ return array_flip($this->getChannels());
+ }
+
+ function getChannelIDFromChannelName($channelName) {
+ if(!$channelName)
+ return null;
+ $channels = $this->getAllChannels();
+ if(array_key_exists($channelName,$channels)) {
+ return $channels[$channelName];
+ }
+ $channelID = null;
+ // Check if the requested channel is the own private channel:
+ if($channelName == $this->getPrivateChannelName()) {
+ return $this->getPrivateChannelID();
+ }
+ // Try to retrieve a private room ID:
+ $strlenChannelName = $this->stringLength($channelName);
+ $strlenPrefix = $this->stringLength($this->getConfig('privateChannelPrefix'));
+ $strlenSuffix = $this->stringLength($this->getConfig('privateChannelSuffix'));
+ if($this->subString($channelName,0,$strlenPrefix) == $this->getConfig('privateChannelPrefix')
+ && $this->subString($channelName,$strlenChannelName-$strlenSuffix) == $this->getConfig('privateChannelSuffix')) {
+ $userName = $this->subString(
+ $channelName,
+ $strlenPrefix,
+ $strlenChannelName-($strlenPrefix+$strlenSuffix)
+ );
+ $userID = $this->getIDFromName($userName);
+ if($userID !== null) {
+ $channelID = $this->getPrivateChannelID($userID);
+ }
+ }
+ return $channelID;
+ }
+
+ function getChannelNameFromChannelID($channelID) {
+ foreach($this->getAllChannels() as $key=>$value) {
+ if($value == $channelID) {
+ return $key;
+ }
+ }
+ // Try to retrieve a private room name:
+ if($channelID == $this->getPrivateChannelID()) {
+ return $this->getPrivateChannelName();
+ }
+ $userName = $this->getNameFromID($channelID-$this->getConfig('privateChannelDiff'));
+ if($userName === null) {
+ return null;
+ }
+ return $this->getPrivateChannelName($userName);
+ }
+
+ function getChannelName() {
+ return $this->getChannelNameFromChannelID($this->getChannel());
+ }
+
+ function getPrivateChannelName($userName=null) {
+ if($userName === null) {
+ $userName = $this->getUserName();
+ }
+ return $this->getConfig('privateChannelPrefix').$userName.$this->getConfig('privateChannelSuffix');
+ }
+
+ function getPrivateChannelID($userID=null) {
+ if($userID === null) {
+ $userID = $this->getUserID();
+ }
+ return $userID + $this->getConfig('privateChannelDiff');
+ }
+
+ function getPrivateMessageID($userID=null) {
+ if($userID === null) {
+ $userID = $this->getUserID();
+ }
+ return $userID + $this->getConfig('privateMessageDiff');
+ }
+
+ function isAllowedToSendPrivateMessage() {
+ if($this->getConfig('allowPrivateMessages') || $this->getUserRole() == AJAX_CHAT_ADMIN) {
+ return true;
+ }
+ return false;
+ }
+
+ function isAllowedToCreatePrivateChannel() {
+ if($this->getConfig('allowPrivateChannels')) {
+ switch($this->getUserRole()) {
+ case AJAX_CHAT_USER:
+ return true;
+ case AJAX_CHAT_MODERATOR:
+ return true;
+ case AJAX_CHAT_ADMIN:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ }
+
+ function isAllowedToListHiddenUsers() {
+ // Hidden users are users within private or restricted channels:
+ switch($this->getUserRole()) {
+ case AJAX_CHAT_MODERATOR:
+ return true;
+ case AJAX_CHAT_ADMIN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function isUserOnline($userID=null) {
+ $userID = ($userID === null) ? $this->getUserID() : $userID;
+ $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
+ if($userDataArray && count($userDataArray) > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ function isUserNameInUse($userName=null) {
+ $userName = ($userName === null) ? $this->getUserName() : $userName;
+ $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
+ if($userDataArray && count($userDataArray) > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ function isUserBanned($userName, $userID=null, $ip=null) {
+ if($userID !== null) {
+ $bannedUserDataArray = $this->getBannedUsersData('userID',$userID);
+ if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
+ return true;
+ }
+ }
+ if($ip !== null) {
+ $bannedUserDataArray = $this->getBannedUsersData('ip',$ip);
+ if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
+ return true;
+ }
+ }
+ $bannedUserDataArray = $this->getBannedUsersData('userName',$userName);
+ if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
+ return true;
+ }
+ return false;
+ }
+
+ function isMaxUsersLoggedIn() {
+ if(count($this->getOnlineUsersData()) >= $this->getConfig('maxUsersLoggedIn')) {
+ return true;
+ }
+ return false;
+ }
+
+ function validateChannel($channelID) {
+ if($channelID === null) {
+ return false;
+ }
+ // Return true for normal channels the user has acces to:
+ if(in_array($channelID, $this->getChannels())) {
+ return true;
+ }
+ // Return true if the user is allowed to join his own private channel:
+ if($channelID == $this->getPrivateChannelID() && $this->isAllowedToCreatePrivateChannel()) {
+ return true;
+ }
+ // Return true if the user has been invited to a restricted or private channel:
+ if(in_array($channelID, $this->getInvitations())) {
+ return true;
+ }
+ // No valid channel, return false:
+ return false;
+ }
+
+ function createGuestUserName() {
+ $maxLength = $this->getConfig('userNameMaxLength')
+ - $this->stringLength($this->getConfig('guestUserPrefix'))
+ - $this->stringLength($this->getConfig('guestUserSuffix'));
+
+ // seed with microseconds since last "whole" second:
+ mt_srand((double)microtime()*1000000);
+
+ // Create a random userName using numbers between 100000 and 999999:
+ $userName = substr(mt_rand(100000, 999999), 0, $maxLength);
+
+ return $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
+ }
+
+ // Guest userIDs must not interfere with existing userIDs and must be lower than privateChannelDiff:
+ function createGuestUserID() {
+ // seed with microseconds since last "whole" second:
+ mt_srand((double)microtime()*1000000);
+
+ return mt_rand($this->getConfig('minGuestUserID'), $this->getConfig('privateChannelDiff')-1);
+ }
+
+ function getGuestUser() {
+ if(!$this->getConfig('allowGuestLogins'))
+ return null;
+
+ if($this->getConfig('allowGuestUserName')) {
+ $maxLength = $this->getConfig('userNameMaxLength')
+ - $this->stringLength($this->getConfig('guestUserPrefix'))
+ - $this->stringLength($this->getConfig('guestUserSuffix'));
+
+ // Trim guest userName:
+ $userName = $this->trimString($this->getRequestVar('userName'), null, $maxLength, true, true);
+
+ // If given userName is invalid, create one:
+ if(!$userName) {
+ $userName = $this->createGuestUserName();
+ } else {
+ // Add the guest users prefix and suffix to the given userName:
+ $userName = $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
+ }
+ } else {
+ $userName = $this->createGuestUserName();
+ }
+
+ $userData = array();
+ $userData['userID'] = $this->createGuestUserID();
+ $userData['userName'] = $userName;
+ $userData['userRole'] = AJAX_CHAT_GUEST;
+ return $userData;
+ }
+
+ function getCustomVar($key) {
+ if(!isset($this->_customVars))
+ $this->_customVars = array();
+ if(!isset($this->_customVars[$key]))
+ return null;
+ return $this->_customVars[$key];
+ }
+
+ function setCustomVar($key, $value) {
+ if(!isset($this->_customVars))
+ $this->_customVars = array();
+ $this->_customVars[$key] = $value;
+ }
+
+ // Override to replace custom template tags:
+ // Return the replacement for the given tag (and given tagContent)
+ function replaceCustomTemplateTags($tag, $tagContent) {
+ return null;
+ }
+
+ // Override to initialize custom configuration settings:
+ function initCustomConfig() {
+ }
+
+ // Override to add custom request variables:
+ // Add values to the request variables array: $this->_requestVars['customVariable'] = null;
+ function initCustomRequestVars() {
+ }
+
+ // Override to add custom session code right after the session has been started:
+ function initCustomSession() {
+ }
+
+ // Override, to parse custom info requests:
+ // $infoRequest contains the current info request
+ // Add info responses using the method addInfoMessage($info, $type)
+ function parseCustomInfoRequest($infoRequest) {
+ }
+
+ // Override to replace custom text:
+ // Return replaced text
+ // $text contains the whole message
+ function replaceCustomText(&$text) {
+ return $text;
+ }
+
+ // Override to add custom commands:
+ // Return true if a custom command has been successfully parsed, else false
+ // $text contains the whole message, $textParts the message split up as words array
+ function parseCustomCommands($text, $textParts) {
+ return false;
+ }
+
+ // Override to perform custom actions on new messages:
+ // Return true if message may be inserted, else false
+ // $text contains the whole message
+ function onNewMessage($text) {
+ return true;
+ }
+
+ // Override to perform custom actions on new messages:
+ // Method to set the style cookie depending on user data
+ function setStyle() {
+ }
+
+ // Override:
+ // Returns true if the userID of the logged in user is identical to the userID of the authentication system
+ // or the user is authenticated as guest in the chat and the authentication system
+ function revalidateUserID() {
+ return true;
+ }
+
+ // Override:
+ // Returns an associative array containing userName, userID and userRole
+ // Returns null if login is invalid
+ function getValidLoginUserData() {
+ // Check if we have a valid registered user:
+ if(false) {
+ // Here is the place to check user authentication
+ } else {
+ // Guest users:
+ return $this->getGuestUser();
+ }
+ }
+
+ // Override:
+ // Store the channels the current user has access to
+ // Make sure channel names don't contain any whitespace
+ function &getChannels() {
+ if($this->_channels === null) {
+ $this->_channels = $this->getAllChannels();
+ }
+ return $this->_channels;
+ }
+
+ // Override:
+ // Store all existing channels
+ // Make sure channel names don't contain any whitespace
+ function &getAllChannels() {
+ if($this->_allChannels === null) {
+ $this->_allChannels = array();
+
+ // Default channel, public to everyone:
+ $this->_allChannels[$this->trimChannelName($this->getConfig('defaultChannelName'))] = $this->getConfig('defaultChannelID');
+ }
+ return $this->_allChannels;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatDataBase.php b/library/ajaxchat/chat/lib/class/AJAXChatDataBase.php
new file mode 100644
index 000000000..2143c5aa0
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatDataBase.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to initialize the DataBase connection:
+class AJAXChatDataBase {
+
+ var $_db;
+
+ function __construct(&$dbConnectionConfig) {
+ switch($dbConnectionConfig['type']) {
+ case 'mysqli':
+ $this->_db = new AJAXChatDatabaseMySQLi($dbConnectionConfig);
+ break;
+ case 'mysql':
+ $this->_db = new AJAXChatDatabaseMySQL($dbConnectionConfig);
+ break;
+ default:
+ // Use MySQLi if available, else MySQL (and check the type of a given database connection object):
+ if(function_exists('mysqli_connect') && (!$dbConnectionConfig['link'] || is_object($dbConnectionConfig['link']))) {
+ $this->_db = new AJAXChatDatabaseMySQLi($dbConnectionConfig);
+ } else {
+ $this->_db = new AJAXChatDatabaseMySQL($dbConnectionConfig);
+ }
+ }
+ }
+
+ // Method to connect to the DataBase server:
+ function connect(&$dbConnectionConfig) {
+ return $this->_db->connect($dbConnectionConfig);
+ }
+
+ // Method to select the DataBase:
+ function select($dbName) {
+ return $this->_db->select($dbName);
+ }
+
+ // Method to determine if an error has occured:
+ function error() {
+ return $this->_db->error();
+ }
+
+ // Method to return the error report:
+ function getError() {
+ return $this->_db->getError();
+ }
+
+ // Method to return the connection identifier:
+ function &getConnectionID() {
+ return $this->_db->getConnectionID();
+ }
+
+ // Method to prevent SQL injections:
+ function makeSafe($value) {
+ return $this->_db->makeSafe($value);
+ }
+
+ // Method to perform SQL queries:
+ function sqlQuery($sql) {
+ return $this->_db->sqlQuery($sql);
+ }
+
+ // Method to retrieve the current DataBase name:
+ function getName() {
+ return $this->_db->getName();
+ //If your database has hyphens ( - ) in it, try using this instead:
+ //return '`'.$this->_db->getName().'`';
+ }
+
+ // Method to retrieve the last inserted ID:
+ function getLastInsertedID() {
+ return $this->_db->getLastInsertedID();
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatEncoding.php b/library/ajaxchat/chat/lib/class/AJAXChatEncoding.php
new file mode 100644
index 000000000..96b2482c7
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatEncoding.php
@@ -0,0 +1,138 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to provide static encoding methods
+class AJAXChatEncoding {
+
+ // Helper function to store special chars as we cannot use static class members in PHP4:
+ public static function getSpecialChars() {
+ static $specialChars;
+ if(!$specialChars) {
+ // As &apos; is not supported by IE, we use &#39; as replacement for "'":
+ $specialChars = array('&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', "'"=>'&#39;', '"'=>'&quot;');
+ }
+ return $specialChars;
+ }
+
+ // Helper function to store Regular expression for NO-WS-CTL as we cannot use static class members in PHP4:
+ public static function getRegExp_NO_WS_CTL() {
+ static $regExp_NO_WS_CTL;
+ if(!$regExp_NO_WS_CTL) {
+ // Regular expression for NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127:
+ $regExp_NO_WS_CTL = '/[\x0\x1\x2\x3\x4\x5\x6\x7\x8\xB\xC\xE\xF\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F]/';
+ }
+ return $regExp_NO_WS_CTL;
+ }
+
+ public static function convertEncoding($str, $charsetFrom, $charsetTo) {
+ if(function_exists('mb_convert_encoding')) {
+ return mb_convert_encoding($str, $charsetTo, $charsetFrom);
+ }
+ if(function_exists('iconv')) {
+ return iconv($charsetFrom, $charsetTo, $str);
+ }
+ if(($charsetFrom == 'UTF-8') && ($charsetTo == 'ISO-8859-1')) {
+ return utf8_decode($str);
+ }
+ if(($charsetFrom == 'ISO-8859-1') && ($charsetTo == 'UTF-8')) {
+ return utf8_encode($str);
+ }
+ return $str;
+ }
+
+ public static function htmlEncode($str, $contentCharset='UTF-8') {
+ switch($contentCharset) {
+ case 'UTF-8':
+ // Encode only special chars (&, <, >, ', ") as entities:
+ return AJAXChatEncoding::encodeSpecialChars($str);
+ break;
+ case 'ISO-8859-1':
+ case 'ISO-8859-15':
+ // Encode special chars and all extended characters above ISO-8859-1 charset as entities, then convert to content charset:
+ return AJAXChatEncoding::convertEncoding(AJAXChatEncoding::encodeEntities($str, 'UTF-8', array(
+ 0x26, 0x26, 0, 0xFFFF, // &
+ 0x3C, 0x3C, 0, 0xFFFF, // <
+ 0x3E, 0x3E, 0, 0xFFFF, // >
+ 0x27, 0x27, 0, 0xFFFF, // '
+ 0x22, 0x22, 0, 0xFFFF, // "
+ 0x100, 0x2FFFF, 0, 0xFFFF // above ISO-8859-1
+ )), 'UTF-8', $contentCharset);
+ break;
+ default:
+ // Encode special chars and all characters above ASCII charset as entities, then convert to content charset:
+ return AJAXChatEncoding::convertEncoding(AJAXChatEncoding::encodeEntities($str, 'UTF-8', array(
+ 0x26, 0x26, 0, 0xFFFF, // &
+ 0x3C, 0x3C, 0, 0xFFFF, // <
+ 0x3E, 0x3E, 0, 0xFFFF, // >
+ 0x27, 0x27, 0, 0xFFFF, // '
+ 0x22, 0x22, 0, 0xFFFF, // "
+ 0x80, 0x2FFFF, 0, 0xFFFF // above ASCII
+ )), 'UTF-8', $contentCharset);
+ }
+ }
+
+ public static function encodeSpecialChars($str) {
+ return strtr($str, AJAXChatEncoding::getSpecialChars());
+ }
+
+ public static function decodeSpecialChars($str) {
+ return strtr($str, array_flip(AJAXChatEncoding::getSpecialChars()));
+ }
+
+ public static function encodeEntities($str, $encoding='UTF-8', $convmap=null) {
+ if($convmap && function_exists('mb_encode_numericentity')) {
+ return mb_encode_numericentity($str, $convmap, $encoding);
+ }
+ return htmlentities($str, ENT_QUOTES, $encoding);
+ }
+
+ public static function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) {
+ // Due to PHP bug #25670, html_entity_decode does not work with UTF-8 for PHP versions < 5:
+ if(function_exists('html_entity_decode') && version_compare(phpversion(), 5, '>=')) {
+ // Replace numeric and literal entities:
+ $str = html_entity_decode($str, ENT_QUOTES, $encoding);
+ // Replace additional literal HTML entities if an HTML entities map is given:
+ if($htmlEntitiesMap) {
+ $str = strtr($str, $htmlEntitiesMap);
+ }
+ } else {
+ // Replace numeric entities:
+ $str = preg_replace('~&#([0-9]+);~e', 'AJAXChatEncoding::unicodeChar("\\1")', $str);
+ $str = preg_replace('~&#x([0-9a-f]+);~ei', 'AJAXChatEncoding::unicodeChar(hexdec("\\1"))', $str);
+ // Replace literal entities:
+ $htmlEntitiesMap = $htmlEntitiesMap ? $htmlEntitiesMap : array_flip(get_html_translation_table(HTML_ENTITIES, ENT_QUOTES));
+ $str = strtr($str, $htmlEntitiesMap);
+ }
+ return $str;
+ }
+
+ public static function unicodeChar($c) {
+ if($c <= 0x7F) {
+ return chr($c);
+ } else if($c <= 0x7FF) {
+ return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F);
+ } else if($c <= 0xFFFF) {
+ return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F)
+ . chr(0x80 | $c & 0x3F);
+ } else if($c <= 0x10FFFF) {
+ return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F)
+ . chr(0x80 | $c >> 6 & 0x3F)
+ . chr(0x80 | $c & 0x3F);
+ } else {
+ return null;
+ }
+ }
+
+ public static function removeUnsafeCharacters($str) {
+ // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127:
+ return preg_replace(AJAXChatEncoding::getRegExp_NO_WS_CTL(), '', $str);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatFileSystem.php b/library/ajaxchat/chat/lib/class/AJAXChatFileSystem.php
new file mode 100644
index 000000000..c9626c36a
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatFileSystem.php
@@ -0,0 +1,22 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to provide methods for file system access:
+class AJAXChatFileSystem {
+
+ public static function getFileContents($file) {
+ if(function_exists('file_get_contents')) {
+ return file_get_contents($file);
+ } else {
+ return(implode('', file($file)));
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatHTTPHeader.php b/library/ajaxchat/chat/lib/class/AJAXChatHTTPHeader.php
new file mode 100644
index 000000000..7340bfcf0
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatHTTPHeader.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to manage HTTP header
+class AJAXChatHTTPHeader {
+
+ var $_contentType;
+ var $_constant;
+ var $_noCache;
+
+ function __construct($encoding='UTF-8', $contentType=null, $noCache=true) {
+ if($contentType) {
+ $this->_contentType = $contentType.'; charset='.$encoding;
+ $this->_constant = true;
+ } else {
+ if(isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml') !== false)) {
+ $this->_contentType = 'application/xhtml+xml; charset='.$encoding;
+ } else {
+ $this->_contentType = 'text/html; charset='.$encoding;
+ }
+ $this->_constant = false;
+ }
+ $this->_noCache = $noCache;
+ }
+
+ // Method to send the HTTP header:
+ function send() {
+ // Prevent caching:
+ if($this->_noCache) {
+ header('Cache-Control: no-cache, must-revalidate');
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+ }
+
+ // Send the content-type-header:
+ header('Content-Type: '.$this->_contentType);
+
+ // Send vary header if content-type varies (important for proxy-caches):
+ if(!$this->_constant) {
+ header('Vary: Accept');
+ }
+ }
+
+ // Method to return the content-type string:
+ function getContentType() {
+ // Return the content-type string:
+ return $this->_contentType;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatLanguage.php b/library/ajaxchat/chat/lib/class/AJAXChatLanguage.php
new file mode 100644
index 000000000..b19724710
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatLanguage.php
@@ -0,0 +1,102 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+class AJAXChatLanguage {
+
+ var $_regExpAcceptLangCode;
+ var $_availableLangCodes;
+ var $_defaultLangCode;
+ var $_strictMode;
+ var $_langCode;
+
+ function __construct($availableLangCodes, $defaultLangCode, $langCode=null, $strictMode=false) {
+ $this->_regExpAcceptLangCode = '/^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i';
+ $this->_availableLangCodes = $availableLangCodes;
+ $this->_defaultLangCode = $defaultLangCode;
+ if($langCode && in_array($langCode, $availableLangCodes)) {
+ $this->_langCode = $langCode;
+ }
+ $this->_strictMode = $strictMode;
+ }
+
+ // Method to detect the language code from the HTTP_ACCEPT_LANGUAGE header:
+ function detectLangCode() {
+ // If HTTP_ACCEPT_LANGUAGE is empty use defaultLangCode:
+ if(empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $this->_langCode = $this->_defaultLangCode;
+ return;
+ }
+
+ // Split up the HTTP_ACCEPT_LANGUAGE header:
+ $acceptedLanguages = preg_split('/,\s*/', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
+
+ $currentLangCode = $this->_defaultLangCode;
+ $currentLangQuality = 0.0;
+
+ foreach($acceptedLanguages as $acceptedLanguage) {
+ // Parse the language string:
+ $match = preg_match($this->_regExpAcceptLangCode, $acceptedLanguage, $matches);
+ // Check if the syntax is valid:
+ if(!$match) {
+ continue;
+ }
+
+ // Get and split the language code:
+ $langCodeParts = explode ('-', $matches[1]);
+
+ // Get the language quality given as float value:
+ if(isset($matches[2])) {
+ $langQuality = (float)$matches[2];
+ } else {
+ // Missing language quality value is maximum quality:
+ $langQuality = 1.0;
+ }
+
+ // Go through it until the language code is empty:
+ while(count($langCodeParts)) {
+ // Join the current langCodeParts:
+ $langCode = strtolower(join('-', $langCodeParts));
+ // Check if the langCode is in the available list:
+ if(in_array($langCode, $this->_availableLangCodes)) {
+ // Check the quality setting:
+ if ($langQuality > $currentLangQuality) {
+ $currentLangCode = $langCode;
+ $currentLangQuality = $langQuality;
+ break;
+ }
+ }
+ // If strict mode is set, don't minimalize the language code:
+ if($this->_strictMode) {
+ break;
+ }
+ // else chop off the right part:
+ array_pop($langCodeParts);
+ }
+ }
+
+ $this->_langCode = $currentLangCode;
+ }
+
+ function getLangCode() {
+ if(!$this->_langCode) {
+ $this->detectLangCode();
+ }
+ return $this->_langCode;
+ }
+
+ function setLangCode($langCode) {
+ $this->_langCode = $langCode;
+ }
+
+ function getLangCodes() {
+ return $this->_availableLangCodes;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatMySQLDataBase.php b/library/ajaxchat/chat/lib/class/AJAXChatMySQLDataBase.php
new file mode 100644
index 000000000..6dca348d1
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatMySQLDataBase.php
@@ -0,0 +1,92 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to initialize the MySQL DataBase connection:
+class AJAXChatDataBaseMySQL {
+
+ var $_connectionID;
+ var $_errno = 0;
+ var $_error = '';
+ var $_dbName;
+
+ function __construct(&$dbConnectionConfig) {
+ $this->_connectionID = $dbConnectionConfig['link'];
+ $this->_dbName = $dbConnectionConfig['name'];
+ }
+
+ // Method to connect to the DataBase server:
+ function connect(&$dbConnectionConfig) {
+ $this->_connectionID = @mysql_connect(
+ $dbConnectionConfig['host'],
+ $dbConnectionConfig['user'],
+ $dbConnectionConfig['pass'],
+ true
+ );
+ if(!$this->_connectionID) {
+ $this->_errno = null;
+ $this->_error = 'Database connection failed.';
+ return false;
+ }
+ return true;
+ }
+
+ // Method to select the DataBase:
+ function select($dbName) {
+ if(!@mysql_select_db($dbName, $this->_connectionID)) {
+ $this->_errno = mysql_errno($this->_connectionID);
+ $this->_error = mysql_error($this->_connectionID);
+ return false;
+ }
+ $this->_dbName = $dbName;
+ return true;
+ }
+
+ // Method to determine if an error has occured:
+ function error() {
+ return (bool)$this->_error;
+ }
+
+ // Method to return the error report:
+ function getError() {
+ if($this->error()) {
+ $str = 'Error-Report: ' .$this->_error."\n";
+ $str .= 'Error-Code: '.$this->_errno."\n";
+ } else {
+ $str = 'No errors.'."\n";
+ }
+ return $str;
+ }
+
+ // Method to return the connection identifier:
+ function &getConnectionID() {
+ return $this->_connectionID;
+ }
+
+ // Method to prevent SQL injections:
+ function makeSafe($value) {
+ return "'".mysql_real_escape_string($value, $this->_connectionID)."'";
+ }
+
+ // Method to perform SQL queries:
+ function sqlQuery($sql) {
+ return new AJAXChatMySQLQuery($sql, $this->_connectionID);
+ }
+
+ // Method to retrieve the current DataBase name:
+ function getName() {
+ return $this->_dbName;
+ }
+
+ // Method to retrieve the last inserted ID:
+ function getLastInsertedID() {
+ return mysql_insert_id($this->_connectionID);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatMySQLQuery.php b/library/ajaxchat/chat/lib/class/AJAXChatMySQLQuery.php
new file mode 100644
index 000000000..f2f3fd466
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatMySQLQuery.php
@@ -0,0 +1,89 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to perform SQL (MySQL) queries:
+class AJAXChatMySQLQuery {
+
+ var $_connectionID;
+ var $_sql = '';
+ var $_result = 0;
+ var $_errno = 0;
+ var $_error = '';
+
+ // Constructor:
+ function __construct($sql, $connectionID = null) {
+ $this->_sql = trim($sql);
+ $this->_connectionID = $connectionID;
+ if($this->_connectionID) {
+ $this->_result = mysql_query($this->_sql, $this->_connectionID);
+ if(!$this->_result) {
+ $this->_errno = mysql_errno($this->_connectionID);
+ $this->_error = mysql_error($this->_connectionID);
+ }
+ } else {
+ $this->_result = mysql_query($this->_sql);
+ if(!$this->_result) {
+ $this->_errno = mysql_errno();
+ $this->_error = mysql_error();
+ }
+ }
+ }
+
+ // Returns true if an error occured:
+ function error() {
+ // Returns true if the Result-ID is valid:
+ return !(bool)($this->_result);
+ }
+
+ // Returns an Error-String:
+ function getError() {
+ if($this->error()) {
+ $str = 'Query: ' .$this->_sql ."\n";
+ $str .= 'Error-Report: ' .$this->_error."\n";
+ $str .= 'Error-Code: '.$this->_errno;
+ } else {
+ $str = "No errors.";
+ }
+ return $str;
+ }
+
+ // Returns the content:
+ function fetch() {
+ if($this->error()) {
+ return null;
+ } else {
+ return mysql_fetch_assoc($this->_result);
+ }
+ }
+
+ // Returns the number of rows (SELECT or SHOW):
+ function numRows() {
+ if($this->error()) {
+ return null;
+ } else {
+ return mysql_num_rows($this->_result);
+ }
+ }
+
+ // Returns the number of affected rows (INSERT, UPDATE, REPLACE or DELETE):
+ function affectedRows() {
+ if($this->error()) {
+ return null;
+ } else {
+ return mysql_affected_rows($this->_connectionID);
+ }
+ }
+
+ // Frees the memory:
+ function free() {
+ @mysql_free_result($this->_result);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatMySQLiDataBase.php b/library/ajaxchat/chat/lib/class/AJAXChatMySQLiDataBase.php
new file mode 100644
index 000000000..9bc611e2d
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatMySQLiDataBase.php
@@ -0,0 +1,91 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to initialize the MySQL DataBase connection:
+class AJAXChatDataBaseMySQLi {
+
+ var $_connectionID;
+ var $_errno = 0;
+ var $_error = '';
+ var $_dbName;
+
+ function __construct(&$dbConnectionConfig) {
+ $this->_connectionID = $dbConnectionConfig['link'];
+ $this->_dbName = $dbConnectionConfig['name'];
+ }
+
+ // Method to connect to the DataBase server:
+ function connect(&$dbConnectionConfig) {
+ @$this->_connectionID = new mysqli(
+ $dbConnectionConfig['host'],
+ $dbConnectionConfig['user'],
+ $dbConnectionConfig['pass']
+ );
+ if($this->_connectionID->connect_errno) {
+ $this->_errno = mysqli_connect_errno();
+ $this->_error = mysqli_connect_error();
+ return false;
+ }
+ return true;
+ }
+
+ // Method to select the DataBase:
+ function select($dbName) {
+ if(!$this->_connectionID->select_db($dbName)) {
+ $this->_errno = $this->_connectionID->errno;
+ $this->_error = $this->_connectionID->error;
+ return false;
+ }
+ $this->_dbName = $dbName;
+ return true;
+ }
+
+ // Method to determine if an error has occured:
+ function error() {
+ return (bool)$this->_error;
+ }
+
+ // Method to return the error report:
+ function getError() {
+ if($this->error()) {
+ $str = 'Error-Report: ' .$this->_error."\n";
+ $str .= 'Error-Code: '.$this->_errno."\n";
+ } else {
+ $str = 'No errors.'."\n";
+ }
+ return $str;
+ }
+
+ // Method to return the connection identifier:
+ function &getConnectionID() {
+ return $this->_connectionID;
+ }
+
+ // Method to prevent SQL injections:
+ function makeSafe($value) {
+ return "'".$this->_connectionID->escape_string($value)."'";
+ }
+
+ // Method to perform SQL queries:
+ function sqlQuery($sql) {
+ return new AJAXChatMySQLiQuery($sql, $this->_connectionID);
+ }
+
+ // Method to retrieve the current DataBase name:
+ function getName() {
+ return $this->_dbName;
+ }
+
+ // Method to retrieve the last inserted ID:
+ function getLastInsertedID() {
+ return $this->_connectionID->insert_id;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatMySQLiQuery.php b/library/ajaxchat/chat/lib/class/AJAXChatMySQLiQuery.php
new file mode 100644
index 000000000..f81afd886
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatMySQLiQuery.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to perform SQL (MySQLi) queries:
+class AJAXChatMySQLiQuery {
+
+ var $_connectionID;
+ var $_sql = '';
+ var $_result = 0;
+ var $_errno = 0;
+ var $_error = '';
+
+ // Constructor:
+ function __construct($sql, $connectionID) {
+ $this->_sql = trim($sql);
+ $this->_connectionID = $connectionID;
+ $this->_result = $this->_connectionID->query($this->_sql);
+ if(!$this->_result) {
+ $this->_errno = $this->_connectionID->errno;
+ $this->_error = $this->_connectionID->error;
+ }
+ }
+
+ // Returns true if an error occured:
+ function error() {
+ // Returns true if the Result-ID is valid:
+ return !(bool)($this->_result);
+ }
+
+ // Returns an Error-String:
+ function getError() {
+ if($this->error()) {
+ $str = 'Query: ' .$this->_sql ."\n";
+ $str .= 'Error-Report: ' .$this->_error."\n";
+ $str .= 'Error-Code: '.$this->_errno;
+ } else {
+ $str = "No errors.";
+ }
+ return $str;
+ }
+
+ // Returns the content:
+ function fetch() {
+ if($this->error()) {
+ return null;
+ } else {
+ return $this->_result->fetch_assoc();
+ }
+ }
+
+ // Returns the number of rows (SELECT or SHOW):
+ function numRows() {
+ if($this->error()) {
+ return null;
+ } else {
+ return $this->_result->num_rows;
+ }
+ }
+
+ // Returns the number of affected rows (INSERT, UPDATE, REPLACE or DELETE):
+ function affectedRows() {
+ if($this->error()) {
+ return null;
+ } else {
+ return $this->_connectionID->affected_rows;
+ }
+ }
+
+ // Frees the memory:
+ function free() {
+ $this->_result->free();
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatString.php b/library/ajaxchat/chat/lib/class/AJAXChatString.php
new file mode 100644
index 000000000..8997da5ea
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatString.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to provide multibyte enabled string methods
+class AJAXChatString {
+
+ public static function subString($str, $start=0, $length=null, $encoding='UTF-8') {
+ if($length === null) {
+ $length = AJAXChatString::stringLength($str);
+ }
+ if(function_exists('mb_substr')) {
+ return mb_substr($str, $start, $length, $encoding);
+ } else if(function_exists('iconv_substr')) {
+ return iconv_substr($str, $start, $length, $encoding);
+ } else {
+ return substr($str, $start, $length);
+ }
+ }
+
+ public static function stringLength($str, $encoding='UTF-8') {
+ if(function_exists('mb_strlen')) {
+ return mb_strlen($str, $encoding);
+ } else if(function_exists('iconv_strlen')) {
+ return iconv_strlen($str, $encoding);
+ } else {
+ return strlen($str);
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/AJAXChatTemplate.php b/library/ajaxchat/chat/lib/class/AJAXChatTemplate.php
new file mode 100644
index 000000000..16e53a7e6
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/AJAXChatTemplate.php
@@ -0,0 +1,329 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Class to handle HTML templates
+class AJAXChatTemplate {
+
+ var $ajaxChat;
+ var $_regExpTemplateTags;
+ var $_templateFile;
+ var $_contentType;
+ var $_content;
+ var $_parsedContent;
+
+ // Constructor:
+ function __construct(&$ajaxChat, $templateFile, $contentType=null) {
+ $this->ajaxChat = $ajaxChat;
+ $this->_regExpTemplateTags = '/\[(\w+?)(?:(?:\/)|(?:\](.+?)\[\/\1))\]/s';
+ $this->_templateFile = $templateFile;
+ $this->_contentType = $contentType;
+ }
+
+ function getParsedContent() {
+ if(!$this->_parsedContent) {
+ $this->parseContent();
+ }
+ return $this->_parsedContent;
+ }
+
+ function getContent() {
+ if(!$this->_content) {
+ $this->_content = AJAXChatFileSystem::getFileContents($this->_templateFile);
+ }
+ return $this->_content;
+ }
+
+ function parseContent() {
+ $this->_parsedContent = $this->getContent();
+
+ // Remove the XML declaration if the content-type is not xml:
+ if($this->_contentType && (strpos($this->_contentType,'xml') === false)) {
+ $doctypeStart = strpos($this->_parsedContent, '<!DOCTYPE ');
+ if($doctypeStart !== false) {
+ // Removing the XML declaration (in front of the document type) prevents IE<7 to go into "Quirks mode":
+ $this->_parsedContent = substr($this->_parsedContent, $doctypeStart);
+ }
+ }
+
+ // Replace template tags ([TAG/] and [TAG]content[/TAG]) and return parsed template content:
+ $this->_parsedContent = preg_replace_callback($this->_regExpTemplateTags, array($this, 'replaceTemplateTags'), $this->_parsedContent);
+ }
+
+ function replaceTemplateTags($tagData) {
+ switch($tagData[1]) {
+ case 'AJAX_CHAT_URL':
+ return $this->ajaxChat->htmlEncode($this->ajaxChat->getChatURL());
+
+ case 'LANG':
+ return $this->ajaxChat->htmlEncode($this->ajaxChat->getLang((isset($tagData[2]) ? $tagData[2] : null)));
+ case 'LANG_CODE':
+ return $this->ajaxChat->getLangCode();
+
+ case 'BASE_DIRECTION':
+ return $this->getBaseDirectionAttribute();
+
+ case 'CONTENT_ENCODING':
+ return $this->ajaxChat->getConfig('contentEncoding');
+
+ case 'CONTENT_TYPE':
+ return $this->_contentType;
+
+ case 'LOGIN_URL':
+ return ($this->ajaxChat->getRequestVar('view') == 'logs') ? './?view=logs' : './';
+
+ case 'USER_NAME_MAX_LENGTH':
+ return $this->ajaxChat->getConfig('userNameMaxLength');
+ case 'MESSAGE_TEXT_MAX_LENGTH':
+ return $this->ajaxChat->getConfig('messageTextMaxLength');
+
+ case 'LOGIN_CHANNEL_ID':
+ return $this->ajaxChat->getValidRequestChannelID();
+
+ case 'SESSION_NAME':
+ return $this->ajaxChat->getConfig('sessionName');
+
+ case 'COOKIE_EXPIRATION':
+ return $this->ajaxChat->getConfig('sessionCookieLifeTime');
+ case 'COOKIE_PATH':
+ return $this->ajaxChat->getConfig('sessionCookiePath');
+ case 'COOKIE_DOMAIN':
+ return $this->ajaxChat->getConfig('sessionCookieDomain');
+ case 'COOKIE_SECURE':
+ return $this->ajaxChat->getConfig('sessionCookieSecure');
+
+ case 'CHAT_BOT_NAME':
+ return rawurlencode($this->ajaxChat->getConfig('chatBotName'));
+ case 'CHAT_BOT_ID':
+ return $this->ajaxChat->getConfig('chatBotID');
+
+ case 'ALLOW_USER_MESSAGE_DELETE':
+ if($this->ajaxChat->getConfig('allowUserMessageDelete'))
+ return 1;
+ else
+ return 0;
+
+ case 'INACTIVE_TIMEOUT':
+ return $this->ajaxChat->getConfig('inactiveTimeout');
+
+ case 'PRIVATE_CHANNEL_DIFF':
+ return $this->ajaxChat->getConfig('privateChannelDiff');
+ case 'PRIVATE_MESSAGE_DIFF':
+ return $this->ajaxChat->getConfig('privateMessageDiff');
+
+ case 'SHOW_CHANNEL_MESSAGES':
+ if($this->ajaxChat->getConfig('showChannelMessages'))
+ return 1;
+ else
+ return 0;
+
+ case 'SOCKET_SERVER_ENABLED':
+ if($this->ajaxChat->getConfig('socketServerEnabled'))
+ return 1;
+ else
+ return 0;
+
+ case 'SOCKET_SERVER_HOST':
+ if($this->ajaxChat->getConfig('socketServerHost')) {
+ $socketServerHost = $this->ajaxChat->getConfig('socketServerHost');
+ } else {
+ $socketServerHost = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']);
+ }
+ return rawurlencode($socketServerHost);
+
+ case 'SOCKET_SERVER_PORT':
+ return $this->ajaxChat->getConfig('socketServerPort');
+
+ case 'SOCKET_SERVER_CHAT_ID':
+ return $this->ajaxChat->getConfig('socketServerChatID');
+
+ case 'STYLE_SHEETS':
+ return $this->getStyleSheetLinkTags();
+
+ case 'CHANNEL_OPTIONS':
+ return $this->getChannelOptionTags();
+ case 'STYLE_OPTIONS':
+ return $this->getStyleOptionTags();
+ case 'LANGUAGE_OPTIONS':
+ return $this->getLanguageOptionTags();
+
+ case 'ERROR_MESSAGES':
+ return $this->getErrorMessageTags();
+
+ case 'LOGS_CHANNEL_OPTIONS':
+ return $this->getLogsChannelOptionTags();
+ case 'LOGS_YEAR_OPTIONS':
+ return $this->getLogsYearOptionTags();
+ case 'LOGS_MONTH_OPTIONS':
+ return $this->getLogsMonthOptionTags();
+ case 'LOGS_DAY_OPTIONS':
+ return $this->getLogsDayOptionTags();
+ case 'LOGS_HOUR_OPTIONS':
+ return $this->getLogsHourOptionTags();
+ case 'CLASS_WRITEABLE':
+ $userdata = $this->ajaxChat->getValidLoginUserData();
+ $guestwrite = $this->ajaxChat->getConfig('allowGuestWrite');
+ if ($userdata['userRole'] === AJAX_CHAT_GUEST && $guestwrite === false)
+ return 'write_forbidden';
+ else
+ return 'write_allowed';
+
+ default:
+ return $this->ajaxChat->replaceCustomTemplateTags($tagData[1], (isset($tagData[2]) ? $tagData[2] : null));
+ }
+ }
+
+ // Function to display alternating table row colors:
+ function alternateRow($rowOdd='rowOdd', $rowEven='rowEven') {
+ static $i;
+ $i += 1;
+ if($i % 2 == 0) {
+ return $rowEven;
+ } else {
+ return $rowOdd;
+ }
+ }
+
+ function getBaseDirectionAttribute() {
+ $langCodeParts = explode('-', $this->ajaxChat->getLangCode());
+ switch($langCodeParts[0]) {
+ case 'ar':
+ case 'fa':
+ case 'he':
+ return 'rtl';
+ default:
+ return 'ltr';
+ }
+ }
+
+ function getStyleSheetLinkTags() {
+ $styleSheets = '';
+ foreach($this->ajaxChat->getConfig('styleAvailable') as $style) {
+ $alternate = ($style == $this->ajaxChat->getConfig('styleDefault')) ? '' : 'alternate ';
+ $styleSheets .= '<link rel="'.$alternate.'stylesheet" type="text/css" href="css/'.rawurlencode($style).'.css" title="'.$this->ajaxChat->htmlEncode($style).'"/>';
+ }
+ return $styleSheets;
+ }
+
+ function getChannelOptionTags() {
+ $channelOptions = '';
+ $channelSelected = false;
+ foreach($this->ajaxChat->getChannels() as $name=>$id) {
+ if($this->ajaxChat->isLoggedIn() && $this->ajaxChat->getChannel()) {
+ $selected = ($id == $this->ajaxChat->getChannel()) ? ' selected="selected"' : '';
+ } else {
+ $selected = ($id == $this->ajaxChat->getConfig('defaultChannelID')) ? ' selected="selected"' : '';
+ }
+ if($selected) {
+ $channelSelected = true;
+ }
+ $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($name).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($name).'</option>';
+ }
+ if($this->ajaxChat->isLoggedIn() && $this->ajaxChat->isAllowedToCreatePrivateChannel()) {
+ // Add the private channel of the user to the options list:
+ if(!$channelSelected && $this->ajaxChat->getPrivateChannelID() == $this->ajaxChat->getChannel()) {
+ $selected = ' selected="selected"';
+ $channelSelected = true;
+ } else {
+ $selected = '';
+ }
+ $privateChannelName = $this->ajaxChat->getPrivateChannelName();
+ $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($privateChannelName).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($privateChannelName).'</option>';
+ }
+ // If current channel is not in the list, try to retrieve the channelName:
+ if(!$channelSelected) {
+ $channelName = $this->ajaxChat->getChannelName();
+ if($channelName !== null) {
+ $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($channelName).'" selected="selected">'.$this->ajaxChat->htmlEncode($channelName).'</option>';
+ } else {
+ // Show an empty selection:
+ $channelOptions .= '<option value="" selected="selected">---</option>';
+ }
+ }
+ return $channelOptions;
+ }
+
+ function getStyleOptionTags() {
+ $styleOptions = '';
+ foreach($this->ajaxChat->getConfig('styleAvailable') as $style) {
+ $selected = ($style == $this->ajaxChat->getConfig('styleDefault')) ? ' selected="selected"' : '';
+ $styleOptions .= '<option value="'.$this->ajaxChat->htmlEncode($style).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($style).'</option>';
+ }
+ return $styleOptions;
+ }
+
+ function getLanguageOptionTags() {
+ $languageOptions = '';
+ $languageNames = $this->ajaxChat->getConfig('langNames');
+ foreach($this->ajaxChat->getConfig('langAvailable') as $langCode) {
+ $selected = ($langCode == $this->ajaxChat->getLangCode()) ? ' selected="selected"' : '';
+ $languageOptions .= '<option value="'.$this->ajaxChat->htmlEncode($langCode).'"'.$selected.'>'.$languageNames[$langCode].'</option>';
+ }
+ return $languageOptions;
+ }
+
+ function getErrorMessageTags() {
+ $errorMessages = '';
+ foreach($this->ajaxChat->getInfoMessages('error') as $error) {
+ $errorMessages .= '<div>'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang($error)).'</div>';
+ }
+ return $errorMessages;
+ }
+
+ function getLogsChannelOptionTags() {
+ $channelOptions = '';
+ $channelOptions .= '<option value="-3">------</option>';
+ foreach($this->ajaxChat->getChannels() as $key=>$value) {
+ if($this->ajaxChat->getUserRole() != AJAX_CHAT_ADMIN && $this->ajaxChat->getConfig('logsUserAccessChannelList') && !in_array($value, $this->ajaxChat->getConfig('logsUserAccessChannelList'))) {
+ continue;
+ }
+ $channelOptions .= '<option value="'.$value.'">'.$this->ajaxChat->htmlEncode($key).'</option>';
+ }
+ $channelOptions .= '<option value="-1">'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang('logsPrivateChannels')).'</option>';
+ $channelOptions .= '<option value="-2">'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang('logsPrivateMessages')).'</option>';
+ return $channelOptions;
+ }
+
+ function getLogsYearOptionTags() {
+ $yearOptions = '';
+ $yearOptions .= '<option value="-1">----</option>';
+ for($year=date('Y'); $year>=$this->ajaxChat->getConfig('logsFirstYear'); $year--) {
+ $yearOptions .= '<option value="'.$year.'">'.$year.'</option>';
+ }
+ return $yearOptions;
+ }
+
+ function getLogsMonthOptionTags() {
+ $monthOptions = '';
+ $monthOptions .= '<option value="-1">--</option>';
+ for($month=1; $month<=12; $month++) {
+ $monthOptions .= '<option value="'.$month.'">'.sprintf("%02d", $month).'</option>';
+ }
+ return $monthOptions;
+ }
+
+ function getLogsDayOptionTags() {
+ $dayOptions = '';
+ $dayOptions .= '<option value="-1">--</option>';
+ for($day=1; $day<=31; $day++) {
+ $dayOptions .= '<option value="'.$day.'">'.sprintf("%02d", $day).'</option>';
+ }
+ return $dayOptions;
+ }
+
+ function getLogsHourOptionTags() {
+ $hourOptions = '';
+ $hourOptions .= '<option value="-1">-----</option>';
+ for($hour=0; $hour<=23; $hour++) {
+ $hourOptions .= '<option value="'.$hour.'">'.sprintf("%02d", $hour).':00</option>';
+ }
+ return $hourOptions;
+ }
+
+}
+?>
diff --git a/library/ajaxchat/chat/lib/class/CustomAJAXChat.php b/library/ajaxchat/chat/lib/class/CustomAJAXChat.php
new file mode 100644
index 000000000..a18e64069
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/CustomAJAXChat.php
@@ -0,0 +1,124 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+class CustomAJAXChat extends AJAXChat {
+
+ // Returns an associative array containing userName, userID and userRole
+ // Returns null if login is invalid
+ function getValidLoginUserData() {
+
+ $customUsers = $this->getCustomUsers();
+
+ if($this->getRequestVar('password')) {
+ // Check if we have a valid registered user:
+
+ $userName = $this->getRequestVar('userName');
+ $userName = $this->convertEncoding($userName, $this->getConfig('contentEncoding'), $this->getConfig('sourceEncoding'));
+
+ $password = $this->getRequestVar('password');
+ $password = $this->convertEncoding($password, $this->getConfig('contentEncoding'), $this->getConfig('sourceEncoding'));
+
+ foreach($customUsers as $key=>$value) {
+ if(($value['userName'] == $userName) && ($value['password'] == $password)) {
+ $userData = array();
+ $userData['userID'] = $key;
+ $userData['userName'] = $this->trimUserName($value['userName']);
+ $userData['userRole'] = $value['userRole'];
+ return $userData;
+ }
+ }
+
+ return null;
+ } else {
+ // Guest users:
+ return $this->getGuestUser();
+ }
+ }
+
+ // Store the channels the current user has access to
+ // Make sure channel names don't contain any whitespace
+ function &getChannels() {
+ if($this->_channels === null) {
+ $this->_channels = array();
+
+ $customUsers = $this->getCustomUsers();
+
+ // Get the channels, the user has access to:
+ if($this->getUserRole() == AJAX_CHAT_GUEST) {
+ $validChannels = $customUsers[0]['channels'];
+ } else {
+ $validChannels = $customUsers[$this->getUserID()]['channels'];
+ }
+
+ // Add the valid channels to the channel list (the defaultChannelID is always valid):
+ foreach($this->getAllChannels() as $key=>$value) {
+ if ($value == $this->getConfig('defaultChannelID')) {
+ $this->_channels[$key] = $value;
+ continue;
+ }
+ // Check if we have to limit the available channels:
+ if($this->getConfig('limitChannelList') && !in_array($value, $this->getConfig('limitChannelList'))) {
+ continue;
+ }
+ if(in_array($value, $validChannels)) {
+ $this->_channels[$key] = $value;
+ }
+ }
+ }
+ return $this->_channels;
+ }
+
+ // Store all existing channels
+ // Make sure channel names don't contain any whitespace
+ function &getAllChannels() {
+ if($this->_allChannels === null) {
+ // Get all existing channels:
+ $customChannels = $this->getCustomChannels();
+
+ $defaultChannelFound = false;
+
+ foreach($customChannels as $name=>$id) {
+ $this->_allChannels[$this->trimChannelName($name)] = $id;
+ if($id == $this->getConfig('defaultChannelID')) {
+ $defaultChannelFound = true;
+ }
+ }
+
+ if(!$defaultChannelFound) {
+ // Add the default channel as first array element to the channel list
+ // First remove it in case it appeard under a different ID
+ unset($this->_allChannels[$this->getConfig('defaultChannelName')]);
+ $this->_allChannels = array_merge(
+ array(
+ $this->trimChannelName($this->getConfig('defaultChannelName'))=>$this->getConfig('defaultChannelID')
+ ),
+ $this->_allChannels
+ );
+ }
+ }
+ return $this->_allChannels;
+ }
+
+ function &getCustomUsers() {
+ // List containing the registered chat users:
+ $users = null;
+ require(AJAX_CHAT_PATH.'lib/data/users.php');
+ return $users;
+ }
+
+ function getCustomChannels() {
+ // List containing the custom channels:
+ $channels = null;
+ require(AJAX_CHAT_PATH.'lib/data/channels.php');
+ // Channel array structure should be:
+ // ChannelName => ChannelID
+ return array_flip($channels);
+ }
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/CustomAJAXChatInterface.php b/library/ajaxchat/chat/lib/class/CustomAJAXChatInterface.php
new file mode 100644
index 000000000..a950739c5
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/CustomAJAXChatInterface.php
@@ -0,0 +1,21 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+class CustomAJAXChatInterface extends CustomAJAXChat {
+
+ function initialize() {
+ // Initialize configuration settings:
+ $this->initConfig();
+
+ // Initialize the DataBase connection:
+ $this->initDataBaseConnection();
+ }
+
+}
+?> \ No newline at end of file
diff --git a/library/ajaxchat/chat/lib/class/CustomAJAXChatShoutBox.php b/library/ajaxchat/chat/lib/class/CustomAJAXChatShoutBox.php
new file mode 100644
index 000000000..c014d639e
--- /dev/null
+++ b/library/ajaxchat/chat/lib/class/CustomAJAXChatShoutBox.php
@@ -0,0 +1,25 @@
+<?php
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+class CustomAJAXChatShoutBox extends CustomAJAXChat {
+
+ function initialize() {
+ // Initialize configuration settings:
+ $this->initConfig();
+ }
+
+ function getShoutBoxContent() {
+ $template = new AJAXChatTemplate($this, AJAX_CHAT_PATH.'lib/template/shoutbox.html');
+
+ // Return parsed template content:
+ return $template->getParsedContent();
+ }
+
+}
+?> \ No newline at end of file