PageRenderTime 68ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/chat/lib/class/AJAXChat.php

https://bitbucket.org/VolCh/2moons
PHP | 3326 lines | 2597 code | 404 blank | 325 comment | 522 complexity | 77ee1f287493c2e592c1e962da1ec648 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, GPL-3.0, GPL-2.0, Apache-2.0, AGPL-3.0
  1. <?php
  2. /*
  3. * @package AJAX_Chat
  4. * @author Sebastian Tschan
  5. * @copyright (c) Sebastian Tschan
  6. * @license GNU Affero General Public License
  7. * @link https://blueimp.net/ajax/
  8. */
  9. // Ajax Chat backend logic:
  10. class AJAXChat {
  11. var $db;
  12. var $_config;
  13. var $_requestVars;
  14. var $_infoMessages;
  15. var $_channels;
  16. var $_allChannels;
  17. var $_view;
  18. var $_lang;
  19. var $_invitations;
  20. var $_customVars;
  21. var $_sessionNew;
  22. var $_onlineUsersData;
  23. var $_bannedUsersData;
  24. function AJAXChat() {
  25. $this->initialize();
  26. }
  27. function initialize() {
  28. // Initialize configuration settings:
  29. $this->initConfig();
  30. // Initialize the DataBase connection:
  31. $this->initDataBaseConnection();
  32. // Initialize request variables:
  33. $this->initRequestVars();
  34. // Initialize the chat session:
  35. $this->initSession();
  36. // Handle the browser request and send the response content:
  37. $this->handleRequest();
  38. }
  39. function initConfig() {
  40. $config = null;
  41. if (!include(AJAX_CHAT_PATH.'lib/config.php')) {
  42. echo('<strong>Error:</strong> Could not find a config.php file in "'.AJAX_CHAT_PATH.'"lib/". Check to make sure the file exists.');
  43. die();
  44. }
  45. $this->_config = &$config;
  46. // Initialize custom configuration settings:
  47. $this->initCustomConfig();
  48. }
  49. function initRequestVars() {
  50. $this->_requestVars = array();
  51. $this->_requestVars['ajax'] = isset($_REQUEST['ajax']) ? true : false;
  52. $this->_requestVars['userID'] = isset($_REQUEST['userID']) ? (int)$_REQUEST['userID'] : null;
  53. $this->_requestVars['userName'] = isset($_REQUEST['userName']) ? $_REQUEST['userName'] : null;
  54. $this->_requestVars['channelID'] = isset($_REQUEST['channelID']) ? (int)$_REQUEST['channelID'] : null;
  55. $this->_requestVars['channelName'] = isset($_REQUEST['channelName']) ? $_REQUEST['channelName'] : null;
  56. $this->_requestVars['text'] = isset($_POST['text']) ? $_POST['text'] : null;
  57. $this->_requestVars['lastID'] = isset($_REQUEST['lastID']) ? (int)$_REQUEST['lastID'] : 0;
  58. $this->_requestVars['login'] = isset($_REQUEST['login']) ? true : false;
  59. $this->_requestVars['logout'] = isset($_POST['logout']) ? true : false;
  60. $this->_requestVars['password'] = isset($_REQUEST['password']) ? $_REQUEST['password'] : null;
  61. $this->_requestVars['view'] = isset($_REQUEST['view']) ? $_REQUEST['view'] : null;
  62. $this->_requestVars['year'] = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null;
  63. $this->_requestVars['month'] = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null;
  64. $this->_requestVars['day'] = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null;
  65. $this->_requestVars['hour'] = isset($_REQUEST['hour']) ? (int)$_REQUEST['hour'] : null;
  66. $this->_requestVars['search'] = isset($_REQUEST['search']) ? $_REQUEST['search'] : null;
  67. $this->_requestVars['shoutbox'] = isset($_REQUEST['shoutbox']) ? true : false;
  68. $this->_requestVars['getInfos'] = isset($_REQUEST['getInfos']) ? $_REQUEST['getInfos'] : null;
  69. $this->_requestVars['lang'] = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : null;
  70. $this->_requestVars['delete'] = isset($_REQUEST['delete']) ? (int)$_REQUEST['delete'] : null;
  71. // Initialize custom request variables:
  72. $this->initCustomRequestVars();
  73. // Remove slashes which have been added to user input strings if magic_quotes_gpc is On:
  74. if(get_magic_quotes_gpc()) {
  75. // It is safe to remove the slashes as we escape user data ourself
  76. array_walk(
  77. $this->_requestVars,
  78. create_function(
  79. '&$value, $key',
  80. 'if(is_string($value)) $value = stripslashes($value);'
  81. )
  82. );
  83. }
  84. }
  85. function initDataBaseConnection() {
  86. // Create a new database object:
  87. $this->db = new AJAXChatDataBase(
  88. $this->_config['dbConnection']
  89. );
  90. // Use a new database connection if no existing is given:
  91. if(!$this->_config['dbConnection']['link']) {
  92. // Connect to the database server:
  93. $this->db->connect($this->_config['dbConnection']);
  94. if($this->db->error()) {
  95. echo $this->db->getError();
  96. die();
  97. }
  98. // Select the database:
  99. $this->db->select($this->_config['dbConnection']['name']);
  100. if($this->db->error()) {
  101. echo $this->db->getError();
  102. die();
  103. }
  104. }
  105. // Unset the dbConnection array for safety purposes:
  106. unset($this->_config['dbConnection']);
  107. }
  108. function getDataBaseTable($table) {
  109. return ($this->db->getName() ? '`'.$this->db->getName().'`.'.$this->getConfig('dbTableNames',$table) : $this->getConfig('dbTableNames',$table));
  110. }
  111. function initSession() {
  112. // Start the PHP session (if not already started):
  113. $this->startSession();
  114. if($this->isLoggedIn()) {
  115. // Logout if we receive a logout request, the chat has been closed or the userID could not be revalidated:
  116. if($this->getRequestVar('logout') || !$this->isChatOpen() || !$this->revalidateUserID()) {
  117. $this->logout();
  118. return;
  119. }
  120. // Logout if the Session IP is not the same when logged in and ipCheck is enabled:
  121. if($this->getConfig('ipCheck') && ($this->getSessionIP() === null || $this->getSessionIP() != $_SERVER['REMOTE_ADDR'])) {
  122. $this->logout('IP');
  123. return;
  124. }
  125. } else if(
  126. // Login if auto-login enabled or a login, userName or shoutbox parameter is given:
  127. $this->getConfig('forceAutoLogin') ||
  128. $this->getRequestVar('login') ||
  129. $this->getRequestVar('userName') ||
  130. $this->getRequestVar('shoutbox')
  131. ) {
  132. $this->login();
  133. }
  134. // Initialize the view:
  135. $this->initView();
  136. if($this->getView() == 'chat') {
  137. $this->initChatViewSession();
  138. } else if($this->getView() == 'logs') {
  139. $this->initLogsViewSession();
  140. }
  141. if(!$this->getRequestVar('ajax') && !headers_sent()) {
  142. // Set style cookie:
  143. $this->setStyle();
  144. // Set langCode cookie:
  145. $this->setLangCodeCookie();
  146. }
  147. $this->initCustomSession();
  148. }
  149. function initLogsViewSession() {
  150. if($this->getConfig('socketServerEnabled')) {
  151. if(!$this->getSessionVar('logsViewSocketAuthenticated')) {
  152. $this->updateLogsViewSocketAuthentication();
  153. $this->setSessionVar('logsViewSocketAuthenticated', true);
  154. }
  155. }
  156. }
  157. function updateLogsViewSocketAuthentication() {
  158. if($this->getUserRole() != AJAX_CHAT_ADMIN) {
  159. $channels = array();
  160. foreach($this->getChannels() as $channel) {
  161. if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
  162. continue;
  163. }
  164. array_push($channels, $channel);
  165. }
  166. array_push($channels, $this->getPrivateMessageID());
  167. array_push($channels, $this->getPrivateChannelID());
  168. } else {
  169. // The channelID "ALL" authenticates for all channels:
  170. $channels = array('ALL');
  171. }
  172. $this->updateSocketAuthentication(
  173. $this->getUserID(),
  174. $this->getSocketRegistrationID(),
  175. $channels
  176. );
  177. }
  178. function initChatViewSession() {
  179. // If channel is not null we are logged in to the chat view:
  180. if($this->getChannel() !== null) {
  181. // Check if the current user has been logged out due to inactivity:
  182. if(!$this->isUserOnline()) {
  183. $this->logout();
  184. return;
  185. }
  186. if($this->getRequestVar('ajax')) {
  187. $this->initChannel();
  188. $this->updateOnlineStatus();
  189. $this->checkAndRemoveInactive();
  190. }
  191. } else {
  192. if($this->getRequestVar('ajax')) {
  193. // Set channel, insert login messages and add to online list on first ajax request in chat view:
  194. $this->chatViewLogin();
  195. }
  196. }
  197. }
  198. function isChatOpen() {
  199. if($this->getUserRole() == AJAX_CHAT_ADMIN)
  200. return true;
  201. if($this->getConfig('chatClosed'))
  202. return false;
  203. $time = time();
  204. if($this->getConfig('timeZoneOffset') !== null) {
  205. // Subtract the server timezone offset and add the config timezone offset:
  206. $time -= date('Z', $time);
  207. $time += $this->getConfig('timeZoneOffset');
  208. }
  209. // Check the opening hours:
  210. if($this->getConfig('openingHour') < $this->getConfig('closingHour'))
  211. {
  212. if(($this->getConfig('openingHour') > date('G', $time)) || ($this->getConfig('closingHour') <= date('G', $time)))
  213. return false;
  214. }
  215. else
  216. {
  217. if(($this->getConfig('openingHour') > date('G', $time)) && ($this->getConfig('closingHour') <= date('G', $time)))
  218. return false;
  219. }
  220. // Check the opening weekdays:
  221. if(!in_array(date('w', $time), $this->getConfig('openingWeekDays')))
  222. return false;
  223. return true;
  224. }
  225. function handleRequest() {
  226. if($this->getRequestVar('ajax')) {
  227. if($this->isLoggedIn()) {
  228. // Parse info requests (for current userName, etc.):
  229. $this->parseInfoRequests();
  230. // Parse command requests (e.g. message deletion):
  231. $this->parseCommandRequests();
  232. // Parse message requests:
  233. $this->initMessageHandling();
  234. }
  235. // Send chat messages and online user list in XML format:
  236. $this->sendXMLMessages();
  237. } else {
  238. // Display XHTML content for non-ajax requests:
  239. $this->sendXHTMLContent();
  240. }
  241. }
  242. function parseCommandRequests() {
  243. if($this->getRequestVar('delete') !== null) {
  244. $this->deleteMessage($this->getRequestVar('delete'));
  245. }
  246. }
  247. function parseInfoRequests() {
  248. if($this->getRequestVar('getInfos')) {
  249. $infoRequests = explode(',', $this->getRequestVar('getInfos'));
  250. foreach($infoRequests as $infoRequest) {
  251. $this->parseInfoRequest($infoRequest);
  252. }
  253. }
  254. }
  255. function parseInfoRequest($infoRequest) {
  256. switch($infoRequest) {
  257. case 'userID':
  258. $this->addInfoMessage($this->getUserID(), 'userID');
  259. break;
  260. case 'userName':
  261. $this->addInfoMessage($this->getUserName(), 'userName');
  262. break;
  263. case 'userRole':
  264. $this->addInfoMessage($this->getUserRole(), 'userRole');
  265. break;
  266. case 'channelID':
  267. $this->addInfoMessage($this->getChannel(), 'channelID');
  268. break;
  269. case 'channelName':
  270. $this->addInfoMessage($this->getChannelName(), 'channelName');
  271. break;
  272. case 'socketRegistrationID':
  273. $this->addInfoMessage($this->getSocketRegistrationID(), 'socketRegistrationID');
  274. break;
  275. default:
  276. $this->parseCustomInfoRequest($infoRequest);
  277. }
  278. }
  279. function sendXHTMLContent() {
  280. $httpHeader = new AJAXChatHTTPHeader($this->getConfig('contentEncoding'), $this->getConfig('contentType'));
  281. $template = new AJAXChatTemplate($this, $this->getTemplateFileName(), $httpHeader->getContentType());
  282. // Send HTTP header:
  283. $httpHeader->send();
  284. // Send parsed template content:
  285. echo $template->getParsedContent();
  286. }
  287. function getTemplateFileName() {
  288. switch($this->getView()) {
  289. case 'chat':
  290. return AJAX_CHAT_PATH.'lib/template/loggedIn.html';
  291. case 'logs':
  292. return AJAX_CHAT_PATH.'lib/template/logs.html';
  293. default:
  294. return AJAX_CHAT_PATH.'lib/template/loggedOut.html';
  295. }
  296. }
  297. function initView() {
  298. $this->_view = null;
  299. // "chat" is the default view:
  300. $view = ($this->getRequestVar('view') === null) ? 'chat' : $this->getRequestVar('view');
  301. if($this->hasAccessTo($view)) {
  302. $this->_view = $view;
  303. }
  304. }
  305. function getView() {
  306. return $this->_view;
  307. }
  308. function hasAccessTo($view) {
  309. switch($view) {
  310. case 'chat':
  311. case 'teaser':
  312. if($this->isLoggedIn()) {
  313. return true;
  314. }
  315. return false;
  316. case 'logs':
  317. if($this->isLoggedIn() && ($this->getUserRole() == AJAX_CHAT_ADMIN ||
  318. ($this->getConfig('logsUserAccess') &&
  319. ($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_USER))
  320. )) {
  321. return true;
  322. }
  323. return false;
  324. default:
  325. return false;
  326. }
  327. }
  328. function login() {
  329. // Retrieve valid login user data (from request variables or session data):
  330. $userData = $this->getValidLoginUserData();
  331. if(!$userData) {
  332. $this->addInfoMessage('errorInvalidUser');
  333. return false;
  334. }
  335. // If the chat is closed, only the admin may login:
  336. if(!$this->isChatOpen() && $userData['userRole'] != AJAX_CHAT_ADMIN) {
  337. $this->addInfoMessage('errorChatClosed');
  338. return false;
  339. }
  340. if(!$this->getConfig('allowGuestLogins') && $userData['userRole'] == AJAX_CHAT_GUEST) {
  341. return false;
  342. }
  343. // Check if userID or userName are already listed online:
  344. if($this->isUserOnline($userData['userID']) || $this->isUserNameInUse($userData['userName'])) {
  345. if($userData['userRole'] == AJAX_CHAT_USER || $userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) {
  346. // Set the registered user inactive and remove the inactive users so the user can be logged in again:
  347. $this->setInactive($userData['userID'], $userData['userName']);
  348. $this->removeInactive();
  349. } else {
  350. $this->addInfoMessage('errorUserInUse');
  351. return false;
  352. }
  353. }
  354. // Check if user is banned:
  355. if($userData['userRole'] != AJAX_CHAT_ADMIN && $this->isUserBanned($userData['userName'], $userData['userID'], $_SERVER['REMOTE_ADDR'])) {
  356. $this->addInfoMessage('errorBanned');
  357. return false;
  358. }
  359. // Check if the max number of users is logged in (not affecting moderators or admins):
  360. if(!($userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) && $this->isMaxUsersLoggedIn()) {
  361. $this->addInfoMessage('errorMaxUsersLoggedIn');
  362. return false;
  363. }
  364. // Use a new session id (if session has been started by the chat):
  365. $this->regenerateSessionID();
  366. // Log in:
  367. $this->setUserID($userData['userID']);
  368. $this->setUserName($userData['userName']);
  369. $this->setLoginUserName($userData['userName']);
  370. $this->setUserRole($userData['userRole']);
  371. $this->setLoggedIn(true);
  372. $this->setLoginTimeStamp(time());
  373. // IP Security check variable:
  374. $this->setSessionIP($_SERVER['REMOTE_ADDR']);
  375. // The client authenticates to the socket server using a socketRegistrationID:
  376. if($this->getConfig('socketServerEnabled')) {
  377. $this->setSocketRegistrationID(
  378. md5(uniqid(rand(), true))
  379. );
  380. }
  381. // Add userID, userName and userRole to info messages:
  382. $this->addInfoMessage($this->getUserID(), 'userID');
  383. $this->addInfoMessage($this->getUserName(), 'userName');
  384. $this->addInfoMessage($this->getUserRole(), 'userRole');
  385. // Purge logs:
  386. if($this->getConfig('logsPurgeLogs')) {
  387. $this->purgeLogs();
  388. }
  389. return true;
  390. }
  391. function chatViewLogin() {
  392. $this->setChannel($this->getValidRequestChannelID());
  393. $this->addToOnlineList();
  394. // Add channelID and channelName to info messages:
  395. $this->addInfoMessage($this->getChannel(), 'channelID');
  396. $this->addInfoMessage($this->getChannelName(), 'channelName');
  397. // Login message:
  398. $text = '/login '.$this->getUserName();
  399. $this->insertChatBotMessage(
  400. $this->getChannel(),
  401. $text,
  402. null,
  403. 1
  404. );
  405. }
  406. function getValidRequestChannelID() {
  407. $channelID = $this->getRequestVar('channelID');
  408. $channelName = $this->getRequestVar('channelName');
  409. // Check the given channelID, or get channelID from channelName:
  410. if($channelID === null) {
  411. if($channelName !== null) {
  412. $channelID = $this->getChannelIDFromChannelName($channelName);
  413. // channelName might need encoding conversion:
  414. if($channelID === null) {
  415. $channelID = $this->getChannelIDFromChannelName(
  416. $this->trimChannelName($channelName, $this->getConfig('contentEncoding'))
  417. );
  418. }
  419. }
  420. }
  421. // Validate the resulting channelID:
  422. if(!$this->validateChannel($channelID)) {
  423. if($this->getChannel() !== null) {
  424. return $this->getChannel();
  425. }
  426. return $this->getConfig('defaultChannelID');
  427. }
  428. return $channelID;
  429. }
  430. function initChannel() {
  431. $channelID = $this->getRequestVar('channelID');
  432. $channelName = $this->getRequestVar('channelName');
  433. if($channelID !== null) {
  434. $this->switchChannel($this->getChannelNameFromChannelID($channelID));
  435. } else if($channelName !== null) {
  436. if($this->getChannelIDFromChannelName($channelName) === null) {
  437. // channelName might need encoding conversion:
  438. $channelName = $this->trimChannelName($channelName, $this->getConfig('contentEncoding'));
  439. }
  440. $this->switchChannel($channelName);
  441. }
  442. }
  443. function logout($type=null) {
  444. // Update the socket server authentication for the user:
  445. if($this->getConfig('socketServerEnabled')) {
  446. $this->updateSocketAuthentication($this->getUserID());
  447. }
  448. if($this->isUserOnline()) {
  449. $this->chatViewLogout($type);
  450. }
  451. $this->setLoggedIn(false);
  452. $this->destroySession();
  453. // Re-initialize the view:
  454. $this->initView();
  455. }
  456. function chatViewLogout($type) {
  457. $this->removeFromOnlineList();
  458. if($type !== null) {
  459. $type = ' '.$type;
  460. }
  461. // Logout message
  462. $text = '/logout '.$this->getUserName().$type;
  463. $this->insertChatBotMessage(
  464. $this->getChannel(),
  465. $text,
  466. null,
  467. 1
  468. );
  469. }
  470. function switchChannel($channelName) {
  471. $channelID = $this->getChannelIDFromChannelName($channelName);
  472. if($channelID !== null && $this->getChannel() == $channelID) {
  473. // User is already in the given channel, return:
  474. return;
  475. }
  476. // Check if we have a valid channel:
  477. if(!$this->validateChannel($channelID)) {
  478. // Invalid channel:
  479. $text = '/error InvalidChannelName '.$channelName;
  480. $this->insertChatBotMessage(
  481. $this->getPrivateMessageID(),
  482. $text
  483. );
  484. return;
  485. }
  486. $oldChannel = $this->getChannel();
  487. $this->setChannel($channelID);
  488. $this->updateOnlineList();
  489. // Channel leave message
  490. $text = '/channelLeave '.$this->getUserName();
  491. $this->insertChatBotMessage(
  492. $oldChannel,
  493. $text,
  494. null,
  495. 1
  496. );
  497. // Channel enter message
  498. $text = '/channelEnter '.$this->getUserName();
  499. $this->insertChatBotMessage(
  500. $this->getChannel(),
  501. $text,
  502. null,
  503. 1
  504. );
  505. $this->addInfoMessage($channelName, 'channelSwitch');
  506. $this->addInfoMessage($channelID, 'channelID');
  507. $this->_requestVars['lastID'] = 0;
  508. }
  509. function addToOnlineList() {
  510. $sql = 'INSERT INTO '.$this->getDataBaseTable('online').'(
  511. userID,
  512. userName,
  513. userRole,
  514. channel,
  515. dateTime,
  516. ip
  517. )
  518. VALUES (
  519. '.$this->db->makeSafe($this->getUserID()).',
  520. '.$this->db->makeSafe($this->getUserName()).',
  521. '.$this->db->makeSafe($this->getUserRole()).',
  522. '.$this->db->makeSafe($this->getChannel()).',
  523. NOW(),
  524. '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
  525. );';
  526. // Create a new SQL query:
  527. $result = $this->db->sqlQuery($sql);
  528. // Stop if an error occurs:
  529. if($result->error()) {
  530. echo $result->getError();
  531. die();
  532. }
  533. $this->resetOnlineUsersData();
  534. }
  535. function removeFromOnlineList() {
  536. $sql = 'DELETE FROM
  537. '.$this->getDataBaseTable('online').'
  538. WHERE
  539. userID = '.$this->db->makeSafe($this->getUserID()).';';
  540. // Create a new SQL query:
  541. $result = $this->db->sqlQuery($sql);
  542. // Stop if an error occurs:
  543. if($result->error()) {
  544. echo $result->getError();
  545. die();
  546. }
  547. $this->removeUserFromOnlineUsersData();
  548. }
  549. function updateOnlineList() {
  550. $sql = 'UPDATE
  551. '.$this->getDataBaseTable('online').'
  552. SET
  553. userName = '.$this->db->makeSafe($this->getUserName()).',
  554. channel = '.$this->db->makeSafe($this->getChannel()).',
  555. dateTime = NOW(),
  556. ip = '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).'
  557. WHERE
  558. userID = '.$this->db->makeSafe($this->getUserID()).';';
  559. // Create a new SQL query:
  560. $result = $this->db->sqlQuery($sql);
  561. // Stop if an error occurs:
  562. if($result->error()) {
  563. echo $result->getError();
  564. die();
  565. }
  566. $this->resetOnlineUsersData();
  567. }
  568. function initMessageHandling() {
  569. // Don't handle messages if we are not in chat view:
  570. if($this->getView() != 'chat') {
  571. return;
  572. }
  573. // Check if we have been uninvited from a private or restricted channel:
  574. if(!$this->validateChannel($this->getChannel())) {
  575. // Switch to the default channel:
  576. $this->switchChannel($this->getChannelNameFromChannelID($this->getConfig('defaultChannelID')));
  577. return;
  578. }
  579. if($this->getRequestVar('text') !== null) {
  580. $this->insertMessage($this->getRequestVar('text'));
  581. }
  582. }
  583. function insertParsedMessage($text) {
  584. // If a queryUserName is set, sent all messages as private messages to this userName:
  585. if($this->getQueryUserName() !== null && strpos($text, '/') !== 0) {
  586. $text = '/msg '.$this->getQueryUserName().' '.$text;
  587. }
  588. // Parse IRC-style commands:
  589. if(strpos($text, '/') === 0) {
  590. $textParts = explode(' ', $text);
  591. switch($textParts[0]) {
  592. // Channel switch:
  593. case '/join':
  594. $this->insertParsedMessageJoin($textParts);
  595. break;
  596. // Logout:
  597. case '/quit':
  598. $this->logout();
  599. break;
  600. // Private message:
  601. case '/msg':
  602. case '/describe':
  603. $this->insertParsedMessagePrivMsg($textParts);
  604. break;
  605. // Invitation:
  606. case '/invite':
  607. $this->insertParsedMessageInvite($textParts);
  608. break;
  609. // Uninvitation:
  610. case '/uninvite':
  611. $this->insertParsedMessageUninvite($textParts);
  612. break;
  613. // Private messaging:
  614. case '/query':
  615. $this->insertParsedMessageQuery($textParts);
  616. break;
  617. // Kicking offending users from the chat:
  618. case '/kick':
  619. $this->insertParsedMessageKick($textParts);
  620. break;
  621. // Listing banned users:
  622. case '/bans':
  623. $this->insertParsedMessageBans($textParts);
  624. break;
  625. // Unban user (remove from ban list):
  626. case '/unban':
  627. $this->insertParsedMessageUnban($textParts);
  628. break;
  629. // Describing actions:
  630. case '/me':
  631. case '/action':
  632. $this->insertParsedMessageAction($textParts);
  633. break;
  634. // Listing online Users:
  635. case '/who':
  636. $this->insertParsedMessageWho($textParts);
  637. break;
  638. // Listing available channels:
  639. case '/list':
  640. $this->insertParsedMessageList($textParts);
  641. break;
  642. // Retrieving the channel of a User:
  643. case '/whereis':
  644. $this->insertParsedMessageWhereis($textParts);
  645. break;
  646. // Listing information about a User:
  647. case '/whois':
  648. $this->insertParsedMessageWhois($textParts);
  649. break;
  650. // Rolling dice:
  651. case '/roll':
  652. $this->insertParsedMessageRoll($textParts);
  653. break;
  654. // Switching userName:
  655. case '/nick':
  656. $this->insertParsedMessageNick($textParts);
  657. break;
  658. // Custom or unknown command:
  659. default:
  660. if(!$this->parseCustomCommands($text, $textParts)) {
  661. $this->insertChatBotMessage(
  662. $this->getPrivateMessageID(),
  663. '/error UnknownCommand '.$textParts[0]
  664. );
  665. }
  666. }
  667. } else {
  668. // No command found, just insert the plain message:
  669. $this->insertCustomMessage(
  670. $this->getUserID(),
  671. $this->getUserName(),
  672. $this->getUserRole(),
  673. $this->getChannel(),
  674. $text
  675. );
  676. }
  677. }
  678. function insertParsedMessageJoin($textParts) {
  679. if(count($textParts) == 1) {
  680. // join with no arguments is the own private channel, if allowed:
  681. if($this->isAllowedToCreatePrivateChannel()) {
  682. // Private channels are identified by square brackets:
  683. $this->switchChannel($this->getChannelNameFromChannelID($this->getPrivateChannelID()));
  684. } else {
  685. $this->insertChatBotMessage(
  686. $this->getPrivateMessageID(),
  687. '/error MissingChannelName'
  688. );
  689. }
  690. } else {
  691. $this->switchChannel($textParts[1]);
  692. }
  693. }
  694. function insertParsedMessagePrivMsg($textParts) {
  695. if($this->isAllowedToSendPrivateMessage()) {
  696. if(count($textParts) < 3) {
  697. if(count($textParts) == 2) {
  698. $this->insertChatBotMessage(
  699. $this->getPrivateMessageID(),
  700. '/error MissingText'
  701. );
  702. } else {
  703. $this->insertChatBotMessage(
  704. $this->getPrivateMessageID(),
  705. '/error MissingUserName'
  706. );
  707. }
  708. } else {
  709. // Get UserID from UserName:
  710. $toUserID = $this->getIDFromName($textParts[1]);
  711. if($toUserID === null) {
  712. if($this->getQueryUserName() !== null) {
  713. // Close the current query:
  714. $this->insertMessage('/query');
  715. } else {
  716. $this->insertChatBotMessage(
  717. $this->getPrivateMessageID(),
  718. '/error UserNameNotFound '.$textParts[1]
  719. );
  720. }
  721. } else {
  722. // Insert /privaction command if /describe is used:
  723. $command = ($textParts[0] == '/describe') ? '/privaction' : '/privmsg';
  724. // Copy of private message to current User:
  725. $this->insertCustomMessage(
  726. $this->getUserID(),
  727. $this->getUserName(),
  728. $this->getUserRole(),
  729. $this->getPrivateMessageID(),
  730. $command.'to '.$textParts[1].' '.implode(' ', array_slice($textParts, 2))
  731. );
  732. // Private message to requested User:
  733. $this->insertCustomMessage(
  734. $this->getUserID(),
  735. $this->getUserName(),
  736. $this->getUserRole(),
  737. $this->getPrivateMessageID($toUserID),
  738. $command.' '.implode(' ', array_slice($textParts, 2))
  739. );
  740. }
  741. }
  742. } else {
  743. $this->insertChatBotMessage(
  744. $this->getPrivateMessageID(),
  745. '/error PrivateMessageNotAllowed'
  746. );
  747. }
  748. }
  749. function insertParsedMessageInvite($textParts) {
  750. if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
  751. if(count($textParts) == 1) {
  752. $this->insertChatBotMessage(
  753. $this->getPrivateMessageID(),
  754. '/error MissingUserName'
  755. );
  756. } else {
  757. $toUserID = $this->getIDFromName($textParts[1]);
  758. if($toUserID === null) {
  759. $this->insertChatBotMessage(
  760. $this->getPrivateMessageID(),
  761. '/error UserNameNotFound '.$textParts[1]
  762. );
  763. } else {
  764. // Add the invitation to the database:
  765. $this->addInvitation($toUserID);
  766. $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
  767. // Copy of invitation to current User:
  768. $this->insertChatBotMessage(
  769. $this->getPrivateMessageID(),
  770. '/inviteto '.$textParts[1].' '.$invitationChannelName
  771. );
  772. // Invitation to requested User:
  773. $this->insertChatBotMessage(
  774. $this->getPrivateMessageID($toUserID),
  775. '/invite '.$this->getUserName().' '.$invitationChannelName
  776. );
  777. }
  778. }
  779. } else {
  780. $this->insertChatBotMessage(
  781. $this->getPrivateMessageID(),
  782. '/error InviteNotAllowed'
  783. );
  784. }
  785. }
  786. function insertParsedMessageUninvite($textParts) {
  787. if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) {
  788. if(count($textParts) == 1) {
  789. $this->insertChatBotMessage(
  790. $this->getPrivateMessageID(),
  791. '/error MissingUserName'
  792. );
  793. } else {
  794. $toUserID = $this->getIDFromName($textParts[1]);
  795. if($toUserID === null) {
  796. $this->insertChatBotMessage(
  797. $this->getPrivateMessageID(),
  798. '/error UserNameNotFound '.$textParts[1]
  799. );
  800. } else {
  801. // Remove the invitation from the database:
  802. $this->removeInvitation($toUserID);
  803. $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel());
  804. // Copy of uninvitation to current User:
  805. $this->insertChatBotMessage(
  806. $this->getPrivateMessageID(),
  807. '/uninviteto '.$textParts[1].' '.$invitationChannelName
  808. );
  809. // Uninvitation to requested User:
  810. $this->insertChatBotMessage(
  811. $this->getPrivateMessageID($toUserID),
  812. '/uninvite '.$this->getUserName().' '.$invitationChannelName
  813. );
  814. }
  815. }
  816. } else {
  817. $this->insertChatBotMessage(
  818. $this->getPrivateMessageID(),
  819. '/error UninviteNotAllowed'
  820. );
  821. }
  822. }
  823. function insertParsedMessageQuery($textParts) {
  824. if($this->isAllowedToSendPrivateMessage()) {
  825. if(count($textParts) == 1) {
  826. if($this->getQueryUserName() !== null) {
  827. $this->insertChatBotMessage(
  828. $this->getPrivateMessageID(),
  829. '/queryClose '.$this->getQueryUserName()
  830. );
  831. // Close the current query:
  832. $this->setQueryUserName(null);
  833. } else {
  834. $this->insertChatBotMessage(
  835. $this->getPrivateMessageID(),
  836. '/error NoOpenQuery'
  837. );
  838. }
  839. } else {
  840. if($this->getIDFromName($textParts[1]) === null) {
  841. $this->insertChatBotMessage(
  842. $this->getPrivateMessageID(),
  843. '/error UserNameNotFound '.$textParts[1]
  844. );
  845. } else {
  846. if($this->getQueryUserName() !== null) {
  847. // Close the current query:
  848. $this->insertMessage('/query');
  849. }
  850. // Open a query to the requested user:
  851. $this->setQueryUserName($textParts[1]);
  852. $this->insertChatBotMessage(
  853. $this->getPrivateMessageID(),
  854. '/queryOpen '.$textParts[1]
  855. );
  856. }
  857. }
  858. } else {
  859. $this->insertChatBotMessage(
  860. $this->getPrivateMessageID(),
  861. '/error PrivateMessageNotAllowed'
  862. );
  863. }
  864. }
  865. function insertParsedMessageKick($textParts) {
  866. // Only moderators/admins may kick users:
  867. if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
  868. if(count($textParts) == 1) {
  869. $this->insertChatBotMessage(
  870. $this->getPrivateMessageID(),
  871. '/error MissingUserName'
  872. );
  873. } else {
  874. // Get UserID from UserName:
  875. $kickUserID = $this->getIDFromName($textParts[1]);
  876. if($kickUserID === null) {
  877. $this->insertChatBotMessage(
  878. $this->getPrivateMessageID(),
  879. '/error UserNameNotFound '.$textParts[1]
  880. );
  881. } else {
  882. // Check the role of the user to kick:
  883. $kickUserRole = $this->getRoleFromID($kickUserID);
  884. if($kickUserRole == AJAX_CHAT_ADMIN || ($kickUserRole == AJAX_CHAT_MODERATOR && $this->getUserRole() != AJAX_CHAT_ADMIN)) {
  885. // Admins and moderators may not be kicked:
  886. $this->insertChatBotMessage(
  887. $this->getPrivateMessageID(),
  888. '/error KickNotAllowed '.$textParts[1]
  889. );
  890. } else {
  891. // Kick user and insert message:
  892. $channel = $this->getChannelFromID($kickUserID);
  893. $banMinutes = (count($textParts) > 2) ? $textParts[2] : null;
  894. $this->kickUser($textParts[1], $banMinutes, $kickUserID);
  895. // If no channel found, user logged out before he could be kicked
  896. if($channel !== null) {
  897. $this->insertChatBotMessage(
  898. $channel,
  899. '/kick '.$textParts[1],
  900. null,
  901. 1
  902. );
  903. // Send a copy of the message to the current user, if not in the channel:
  904. if($channel != $this->getChannel()) {
  905. $this->insertChatBotMessage(
  906. $this->getPrivateMessageID(),
  907. '/kick '.$textParts[1],
  908. null,
  909. 1
  910. );
  911. }
  912. }
  913. }
  914. }
  915. }
  916. } else {
  917. $this->insertChatBotMessage(
  918. $this->getPrivateMessageID(),
  919. '/error CommandNotAllowed '.$textParts[0]
  920. );
  921. }
  922. }
  923. function insertParsedMessageBans($textParts) {
  924. // Only moderators/admins may see the list of banned users:
  925. if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
  926. $this->removeExpiredBans();
  927. $bannedUsers = $this->getBannedUsers();
  928. if(count($bannedUsers) > 0) {
  929. $this->insertChatBotMessage(
  930. $this->getPrivateMessageID(),
  931. '/bans '.implode(' ', $bannedUsers)
  932. );
  933. } else {
  934. $this->insertChatBotMessage(
  935. $this->getPrivateMessageID(),
  936. '/bansEmpty -'
  937. );
  938. }
  939. } else {
  940. $this->insertChatBotMessage(
  941. $this->getPrivateMessageID(),
  942. '/error CommandNotAllowed '.$textParts[0]
  943. );
  944. }
  945. }
  946. function insertParsedMessageUnban($textParts) {
  947. // Only moderators/admins may unban users:
  948. if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
  949. $this->removeExpiredBans();
  950. if(count($textParts) == 1) {
  951. $this->insertChatBotMessage(
  952. $this->getPrivateMessageID(),
  953. '/error MissingUserName'
  954. );
  955. } else {
  956. if(!in_array($textParts[1], $this->getBannedUsers())) {
  957. $this->insertChatBotMessage(
  958. $this->getPrivateMessageID(),
  959. '/error UserNameNotFound '.$textParts[1]
  960. );
  961. } else {
  962. // Unban user and insert message:
  963. $this->unbanUser($textParts[1]);
  964. $this->insertChatBotMessage(
  965. $this->getPrivateMessageID(),
  966. '/unban '.$textParts[1]
  967. );
  968. }
  969. }
  970. } else {
  971. $this->insertChatBotMessage(
  972. $this->getPrivateMessageID(),
  973. '/error CommandNotAllowed '.$textParts[0]
  974. );
  975. }
  976. }
  977. function insertParsedMessageAction($textParts) {
  978. if(count($textParts) == 1) {
  979. $this->insertChatBotMessage(
  980. $this->getPrivateMessageID(),
  981. '/error MissingText'
  982. );
  983. } else {
  984. if($this->getQueryUserName() !== null) {
  985. // If we are in query mode, sent the action to the query user:
  986. $this->insertMessage('/describe '.$this->getQueryUserName().' '.implode(' ', array_slice($textParts, 1)));
  987. } else {
  988. $this->insertCustomMessage(
  989. $this->getUserID(),
  990. $this->getUserName(),
  991. $this->getUserRole(),
  992. $this->getChannel(),
  993. implode(' ', $textParts)
  994. );
  995. }
  996. }
  997. }
  998. function insertParsedMessageWho($textParts) {
  999. if(count($textParts) == 1) {
  1000. if($this->isAllowedToListHiddenUsers()) {
  1001. // List online users from any channel:
  1002. $this->insertChatBotMessage(
  1003. $this->getPrivateMessageID(),
  1004. '/who '.implode(' ', $this->getOnlineUsers())
  1005. );
  1006. } else {
  1007. // Get online users for all accessible channels:
  1008. $channels = $this->getChannels();
  1009. // Add the own private channel if allowed:
  1010. if($this->isAllowedToCreatePrivateChannel()) {
  1011. array_push($channels, $this->getPrivateChannelID());
  1012. }
  1013. // Add the invitation channels:
  1014. foreach($this->getInvitations() as $channelID) {
  1015. if(!in_array($channelID, $channels)) {
  1016. array_push($channels, $channelID);
  1017. }
  1018. }
  1019. $this->insertChatBotMessage(
  1020. $this->getPrivateMessageID(),
  1021. '/who '.implode(' ', $this->getOnlineUsers($channels))
  1022. );
  1023. }
  1024. } else {
  1025. $channelName = $textParts[1];
  1026. $channelID = $this->getChannelIDFromChannelName($channelName);
  1027. if(!$this->validateChannel($channelID)) {
  1028. // Invalid channel:
  1029. $this->insertChatBotMessage(
  1030. $this->getPrivateMessageID(),
  1031. '/error InvalidChannelName '.$channelName
  1032. );
  1033. } else {
  1034. // Get online users for the given channel:
  1035. $onlineUsers = $this->getOnlineUsers(array($channelID));
  1036. if(count($onlineUsers) > 0) {
  1037. $this->insertChatBotMessage(
  1038. $this->getPrivateMessageID(),
  1039. '/whoChannel '.$channelName.' '.implode(' ', $onlineUsers)
  1040. );
  1041. } else {
  1042. $this->insertChatBotMessage(
  1043. $this->getPrivateMessageID(),
  1044. '/whoEmpty -'
  1045. );
  1046. }
  1047. }
  1048. }
  1049. }
  1050. function insertParsedMessageList($textParts) {
  1051. // Get the names of all accessible channels:
  1052. $channelNames = $this->getChannelNames();
  1053. // Add the own private channel, if allowed:
  1054. if($this->isAllowedToCreatePrivateChannel()) {
  1055. array_push($channelNames, $this->getPrivateChannelName());
  1056. }
  1057. // Add the invitation channels:
  1058. foreach($this->getInvitations() as $channelID) {
  1059. $channelName = $this->getChannelNameFromChannelID($channelID);
  1060. if($channelName !== null && !in_array($channelName, $channelNames)) {
  1061. array_push($channelNames, $channelName);
  1062. }
  1063. }
  1064. $this->insertChatBotMessage(
  1065. $this->getPrivateMessageID(),
  1066. '/list '.implode(' ', $channelNames)
  1067. );
  1068. }
  1069. function insertParsedMessageWhereis($textParts) {
  1070. if(count($textParts) == 1) {
  1071. $this->insertChatBotMessage(
  1072. $this->getPrivateMessageID(),
  1073. '/error MissingUserName'
  1074. );
  1075. } else {
  1076. // Get UserID from UserName:
  1077. $whereisUserID = $this->getIDFromName($textParts[1]);
  1078. if($whereisUserID === null) {
  1079. $this->insertChatBotMessage(
  1080. $this->getPrivateMessageID(),
  1081. '/error UserNameNotFound '.$textParts[1]
  1082. );
  1083. } else {
  1084. $channelID = $this->getChannelFromID($whereisUserID);
  1085. if($this->validateChannel($channelID)) {
  1086. $channelName = $this->getChannelNameFromChannelID($channelID);
  1087. } else {
  1088. $channelName = null;
  1089. }
  1090. if($channelName === null) {
  1091. $this->insertChatBotMessage(
  1092. $this->getPrivateMessageID(),
  1093. '/error UserNameNotFound '.$textParts[1]
  1094. );
  1095. } else {
  1096. // List user information:
  1097. $this->insertChatBotMessage(
  1098. $this->getPrivateMessageID(),
  1099. '/whereis '.$textParts[1].' '.$channelName
  1100. );
  1101. }
  1102. }
  1103. }
  1104. }
  1105. function insertParsedMessageWhois($textParts) {
  1106. // Only moderators/admins:
  1107. if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
  1108. if(count($textParts) == 1) {
  1109. $this->insertChatBotMessage(
  1110. $this->getPrivateMessageID(),
  1111. '/error MissingUserName'
  1112. );
  1113. } else {
  1114. // Get UserID from UserName:
  1115. $whoisUserID = $this->getIDFromName($textParts[1]);
  1116. if($whoisUserID === null) {
  1117. $this->insertChatBotMessage(
  1118. $this->getPrivateMessageID(),
  1119. '/error UserNameNotFound '.$textParts[1]
  1120. );
  1121. } else {
  1122. // List user information:
  1123. $this->insertChatBotMessage(
  1124. $this->getPrivateMessageID(),
  1125. '/whois '.$textParts[1].' '.$this->getIPFromID($whoisUserID)
  1126. );
  1127. }
  1128. }
  1129. } else {
  1130. $this->insertChatBotMessage(
  1131. $this->getPrivateMessageID(),
  1132. '/error CommandNotAllowed '.$textParts[0]
  1133. );
  1134. }
  1135. }
  1136. function insertParsedMessageRoll($textParts) {
  1137. if(count($textParts) == 1) {
  1138. // default is one d6:
  1139. $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
  1140. } else {
  1141. $diceParts = explode('d', $textParts[1]);
  1142. if(count($diceParts) == 2) {
  1143. $number = (int)$diceParts[0];
  1144. $sides = (int)$diceParts[1];
  1145. // Dice number must be an integer between 1 and 100, else roll only one:
  1146. $number = ($number > 0 && $number <= 100) ? $number : 1;
  1147. // Sides must be an integer between 1 and 100, else take 6:
  1148. $sides = ($sides > 0 && $sides <= 100) ? $sides : 6;
  1149. $text = '/roll '.$this->getUserName().' '.$number.'d'.$sides.' ';
  1150. for($i=0; $i<$number; $i++) {
  1151. if($i != 0)
  1152. $text .= ',';
  1153. $text .= $this->rollDice($sides);
  1154. }
  1155. } else {
  1156. // if dice syntax is invalid, roll one d6:
  1157. $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6);
  1158. }
  1159. }
  1160. $this->insertChatBotMessage(
  1161. $this->getChannel(),
  1162. $text
  1163. );
  1164. }
  1165. function insertParsedMessageNick($textParts) {
  1166. if(!$this->getConfig('allowNickChange') ||
  1167. (!$this->getConfig('allowGuestUserName') && $this->getUserRole() == AJAX_CHAT_GUEST)) {
  1168. $this->insertChatBotMessage(
  1169. $this->getPrivateMessageID(),
  1170. '/error CommandNotAllowed '.$textParts[0]
  1171. );
  1172. } else if(count($textParts) == 1) {
  1173. $this->insertChatBotMessage(
  1174. $this->getPrivateMessageID(),
  1175. '/error MissingUserName'
  1176. );
  1177. } else {
  1178. $newUserName = implode(' ', array_slice($textParts, 1));
  1179. if($newUserName == $this->getLoginUserName()) {
  1180. // Allow the user to regain the original login userName:
  1181. $prefix = '';
  1182. $suffix = '';
  1183. } else if($this->getUserRole() == AJAX_CHAT_GUEST) {
  1184. $prefix = $this->getConfig('guestUserPrefix');
  1185. $suffix = $this->getConfig('guestUserSuffix');
  1186. } else {
  1187. $prefix = $this->getConfig('changedNickPrefix');
  1188. $suffix = $this->getConfig('changedNickSuffix');
  1189. }
  1190. $maxLength = $this->getConfig('userNameMaxLength')
  1191. - $this->stringLength($prefix)
  1192. - $this->stringLength($suffix);
  1193. $newUserName = $this->trimString($newUserName, 'UTF-8', $maxLength, true);
  1194. if(!$newUserName) {
  1195. $this->insertChatBotMessage(
  1196. $this->getPrivateMessageID(),
  1197. '/error InvalidUserName'
  1198. );
  1199. } else {
  1200. $newUserName = $prefix.$newUserName.$suffix;
  1201. if($this->isUserNameInUse($newUserName)) {
  1202. $this->insertChatBotMessage(
  1203. $this->getPrivateMessageID(),
  1204. '/error UserNameInUse'
  1205. );
  1206. } else {
  1207. $oldUserName = $this->getUserName();
  1208. $this->setUserName($newUserName);
  1209. $this->updateOnlineList();
  1210. // Add info message to update the client-side stored userName:
  1211. $this->addInfoMessage($this->getUserName(), 'userName');
  1212. $this->insertChatBotMessage(
  1213. $this->getChannel(),
  1214. '/nick '.$oldUserName.' '.$newUserName,
  1215. null,
  1216. 2
  1217. );
  1218. }
  1219. }
  1220. }
  1221. }
  1222. function insertMessage($text) {
  1223. if(!$this->isAllowedToWriteMessage())
  1224. return;
  1225. if(!$this->floodControl())
  1226. return;
  1227. $text = $this->trimMessageText($text);
  1228. if($text == '')
  1229. return;
  1230. if(!$this->onNewMessage($text))
  1231. return;
  1232. $text = $this->replaceCustomText($text);
  1233. $this->insertParsedMessage($text);
  1234. }
  1235. function deleteMessage($messageID) {
  1236. // Retrieve the channel of the given message:
  1237. $sql = 'SELECT
  1238. channel
  1239. FROM
  1240. '.$this->getDataBaseTable('messages').'
  1241. WHERE
  1242. id='.$this->db->makeSafe($messageID).';';
  1243. // Create a new SQL query:
  1244. $result = $this->db->sqlQuery($sql);
  1245. // Stop if an error occurs:
  1246. if($result->error()) {
  1247. echo $result->getError();
  1248. die();
  1249. }
  1250. $row = $result->fetch();
  1251. if($row['channel'] !== null) {
  1252. $channel = $row['channel'];
  1253. if($this->getUserRole() == AJAX_CHAT_ADMIN) {
  1254. $condition = '';
  1255. } else if($this->getUserRole() == AJAX_CHAT_MODERATOR) {
  1256. $condition = ' AND
  1257. NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
  1258. AND
  1259. NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')';
  1260. } else if($this->getUserRole() == AJAX_CHAT_USER && $this->getConfig('allowUserMessageDelete')) {
  1261. $condition = 'AND
  1262. (
  1263. userID='.$this->db->makeSafe($this->getUserID()).'
  1264. OR
  1265. (
  1266. channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
  1267. OR
  1268. channel = '.$this->db->makeSafe($this->getPrivateChannelID()).'
  1269. )
  1270. AND
  1271. NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).')
  1272. AND
  1273. NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')
  1274. )';
  1275. } else {
  1276. return false;
  1277. }
  1278. // Remove given message from the database:
  1279. $sql = 'DELETE FROM
  1280. '.$this->getDataBaseTable('messages').'
  1281. WHERE
  1282. id='.$this->db->makeSafe($messageID).'
  1283. '.$condition.';';
  1284. // Create a new SQL query:
  1285. $result = $this->db->sqlQuery($sql);
  1286. // Stop if an error occurs:
  1287. if($result->error()) {
  1288. echo $result->getError();
  1289. die();
  1290. }
  1291. if($result->affectedRows() == 1) {
  1292. // Insert a deletion command to remove the message from the clients chatlists:
  1293. $this->insertChatBotMessage($channel, '/delete '.$messageID);
  1294. return true;
  1295. }
  1296. }
  1297. return false;
  1298. }
  1299. function floodControl() {
  1300. // Moderators and Admins need no flood control:
  1301. if($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_ADMIN) {
  1302. return true;
  1303. }
  1304. $time = time();
  1305. // Check the time of the last inserted message:
  1306. if($this->getInsertedMessagesRateTimeStamp()+60 < $time) {
  1307. $this->setInsertedMessagesRateTimeStamp($time);
  1308. $this->setInsertedMessagesRate(1);
  1309. } else {
  1310. // Increase the inserted messages rate:
  1311. $rate = $this->getInsertedMessagesRate()+1;
  1312. $this->setInsertedMessagesRate($rate);
  1313. // Check if message rate is too high:
  1314. if($rate > $this->getConfig('maxMessageRate')) {
  1315. $this->insertChatBotMessage(
  1316. $this->getPrivateMessageID(),
  1317. '/error MaxMessageRate'
  1318. );
  1319. // Return false so the message is not inserted:
  1320. return false;
  1321. }
  1322. }
  1323. return true;
  1324. }
  1325. function isAllowedToWriteMessage() {
  1326. if($this->getUserRole() != AJAX_CHAT_GUEST)
  1327. return true;
  1328. if($this->getConfig('allowGuestWrite'))
  1329. return true;
  1330. return false;
  1331. }
  1332. function insertChatBotMessage($channelID, $messageText, $ip=null, $mode=0) {
  1333. $this->insertCustomMessage(
  1334. $this->getConfig('chatBotID'),
  1335. $this->getConfig('chatBotName'),
  1336. AJAX_CHAT_CHATBOT,
  1337. $channelID,
  1338. $messageText,
  1339. $ip,
  1340. $mode
  1341. );
  1342. }
  1343. function insertCustomMessage($userID, $userName, $userRole, $channelID, $text, $ip=null, $mode=0) {
  1344. // The $mode parameter is used for socket updates:
  1345. // 0 = normal messages
  1346. // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
  1347. // 2 = messages with online user updates (nick)
  1348. $ip = $ip ? $ip : $_SERVER['REMOTE_ADDR'];
  1349. $sql = 'INSERT INTO '.$this->getDataBaseTable('messages').'(
  1350. userID,
  1351. userName,
  1352. userRole,
  1353. channel,
  1354. dateTime,
  1355. ip,
  1356. text
  1357. )
  1358. VALUES (
  1359. '.$this->db->makeSafe($userID).',
  1360. '.$this->db->makeSafe($userName).',
  1361. '.$this->db->makeSafe($userRole).',
  1362. '.$this->db->makeSafe($channelID).',
  1363. NOW(),
  1364. '.$this->db->makeSafe($this->ipToStorageFormat($ip)).',
  1365. '.$this->db->makeSafe($text).'
  1366. );';
  1367. // Create a new SQL query:
  1368. $result = $this->db->sqlQuery($sql);
  1369. // Stop if an error occurs:
  1370. if($result->error()) {
  1371. echo $result->getError();
  1372. die();
  1373. }
  1374. if($this->getConfig('socketServerEnabled')) {
  1375. $this->sendSocketMessage(
  1376. $this->getSocketBroadcastMessage(
  1377. $this->db->getLastInsertedID(),
  1378. time(),
  1379. $userID,
  1380. $userName,
  1381. $userRole,
  1382. $channelID,
  1383. $text,
  1384. $mode
  1385. )
  1386. );
  1387. }
  1388. }
  1389. function getSocketBroadcastMessage(
  1390. $messageID,
  1391. $timeStamp,
  1392. $userID,
  1393. $userName,
  1394. $userRole,
  1395. $channelID,
  1396. $text,
  1397. $mode
  1398. ) {
  1399. // The $mode parameter:
  1400. // 0 = normal messages
  1401. // 1 = channel messages (e.g. login/logout, channel enter/leave, kick)
  1402. // 2 = messages with online user updates (nick)
  1403. // Get the message XML content:
  1404. $xml = '<root chatID="'.$this->getConfig('socketServerChatID').'" channelID="'.$channelID.'" mode="'.$mode.'">';
  1405. if($mode) {
  1406. // Add the list of online users if the user list has been updated ($mode > 0):
  1407. $xml .= $this->getChatViewOnlineUsersXML(array($channelID));
  1408. }
  1409. if($mode != 1 || $this->getConfig('showChannelMessages')) {
  1410. $xml .= '<messages>';
  1411. $xml .= $this->getChatViewMessageXML(
  1412. $messageID,
  1413. $timeStamp,
  1414. $userID,
  1415. $userName,
  1416. $userRole,
  1417. $channelID,
  1418. $text
  1419. );
  1420. $xml .= '</messages>';
  1421. }
  1422. $xml .= '</root>';
  1423. return $xml;
  1424. }
  1425. function sendSocketMessage($message) {
  1426. // Open a TCP socket connection to the socket server:
  1427. if($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
  1428. if(@socket_connect($socket, $this->getConfig('socketServerIP'), $this->getConfig('socketServerPort'))) {
  1429. // Append a null-byte to the string as EOL (End Of Line) character
  1430. // which is required by Flash XML socket communication:
  1431. $message .= "\0";
  1432. @socket_write(
  1433. $socket,
  1434. $message,
  1435. strlen($message) // Using strlen to count the bytes instead of the number of UTF-8 characters
  1436. );
  1437. }
  1438. @socket_close($socket);
  1439. }
  1440. }
  1441. function updateSocketAuthentication($userID, $socketRegistrationID=null, $channels=null) {
  1442. // If no $socketRegistrationID or no $channels are given the authentication is removed for the given user:
  1443. $authentication = '<authenticate chatID="'.$this->getConfig('socketServerChatID').'" userID="'.$userID.'" regID="'.$socketRegistrationID.'">';
  1444. if($channels) {
  1445. foreach($channels as $channelID) {
  1446. $authentication .= '<channel id="'.$channelID.'"/>';
  1447. }
  1448. }
  1449. $authentication .= '</authenticate>';
  1450. $this->sendSocketMessage($authentication);
  1451. }
  1452. function setSocketRegistrationID($value) {
  1453. $this->setSessionVar('SocketRegistrationID', $value);
  1454. }
  1455. function getSocketRegistrationID() {
  1456. return $this->getSessionVar('SocketRegistrationID');
  1457. }
  1458. function rollDice($sides) {
  1459. // seed with microseconds since last "whole" second:
  1460. mt_srand((double)microtime()*1000000);
  1461. return mt_rand(1, $sides);
  1462. }
  1463. function kickUser($userName, $banMinutes=null, $userID=null) {
  1464. if($userID === null) {
  1465. $userID = $this->getIDFromName($userName);
  1466. }
  1467. if($userID === null) {
  1468. return;
  1469. }
  1470. $banMinutes = $banMinutes ? $banMinutes : $this->getConfig('defaultBanTime');
  1471. if($banMinutes) {
  1472. // Ban User for the given time in minutes:
  1473. $this->banUser($userName, $banMinutes, $userID);
  1474. }
  1475. // Remove given User from online list:
  1476. $sql = 'DELETE FROM
  1477. '.$this->getDataBaseTable('online').'
  1478. WHERE
  1479. userID = '.$this->db->makeSafe($userID).';';
  1480. // Create a new SQL query:
  1481. $result = $this->db->sqlQuery($sql);
  1482. // Stop if an error occurs:
  1483. if($result->error()) {
  1484. echo $result->getError();
  1485. die();
  1486. }
  1487. // Update the socket server authentication for the kicked user:
  1488. if($this->getConfig('socketServerEnabled')) {
  1489. $this->updateSocketAuthentication($userID);
  1490. }
  1491. $this->removeUserFromOnlineUsersData($userID);
  1492. }
  1493. function getBannedUsersData($key=null, $value=null) {
  1494. if($this->_bannedUsersData === null) {
  1495. $this->_bannedUsersData = array();
  1496. $sql = 'SELECT
  1497. userID,
  1498. userName,
  1499. ip
  1500. FROM
  1501. '.$this->getDataBaseTable('bans').'
  1502. WHERE
  1503. NOW() < dateTime;';
  1504. // Create a new SQL query:
  1505. $result = $this->db->sqlQuery($sql);
  1506. // Stop if an error occurs:
  1507. if($result->error()) {
  1508. echo $result->getError();
  1509. die();
  1510. }
  1511. while($row = $result->fetch()) {
  1512. $row['ip'] = $this->ipFromStorageFormat($row['ip']);
  1513. array_push($this->_bannedUsersData, $row);
  1514. }
  1515. $result->free();
  1516. }
  1517. if($key) {
  1518. $bannedUsersData = array();
  1519. foreach($this->_bannedUsersData as $bannedUserData) {
  1520. if(!isset($bannedUserData[$key])) {
  1521. return $bannedUsersData;
  1522. }
  1523. if($value) {
  1524. if($bannedUserData[$key] == $value) {
  1525. array_push($bannedUsersData, $bannedUserData);
  1526. } else {
  1527. continue;
  1528. }
  1529. } else {
  1530. array_push($bannedUsersData, $bannedUserData[$key]);
  1531. }
  1532. }
  1533. return $bannedUsersData;
  1534. }
  1535. return $this->_bannedUsersData;
  1536. }
  1537. function getBannedUsers() {
  1538. return $this->getBannedUsersData('userName');
  1539. }
  1540. function banUser($userName, $banMinutes=null, $userID=null) {
  1541. if($userID === null) {
  1542. $userID = $this->getIDFromName($userName);
  1543. }
  1544. $ip = $this->getIPFromID($userID);
  1545. if(!$ip || $userID === null) {
  1546. return;
  1547. }
  1548. // Remove expired bans:
  1549. $this->removeExpiredBans();
  1550. $banMinutes = (int)$banMinutes;
  1551. if(!$banMinutes) {
  1552. // If banMinutes is not a valid integer, use the defaultBanTime:
  1553. $banMinutes = $this->getConfig('defaultBanTime');
  1554. }
  1555. $sql = 'INSERT INTO '.$this->getDataBaseTable('bans').'(
  1556. userID,
  1557. userName,
  1558. dateTime,
  1559. ip
  1560. )
  1561. VALUES (
  1562. '.$this->db->makeSafe($userID).',
  1563. '.$this->db->makeSafe($userName).',
  1564. DATE_ADD(NOW(), interval '.$this->db->makeSafe($banMinutes).' MINUTE),
  1565. '.$this->db->makeSafe($this->ipToStorageFormat($ip)).'
  1566. );';
  1567. // Create a new SQL query:
  1568. $result = $this->db->sqlQuery($sql);
  1569. // Stop if an error occurs:
  1570. if($result->error()) {
  1571. echo $result->getError();
  1572. die();
  1573. }
  1574. }
  1575. function unbanUser($userName) {
  1576. $sql = 'DELETE FROM
  1577. '.$this->getDataBaseTable('bans').'
  1578. WHERE
  1579. userName = '.$this->db->makeSafe($userName).';';
  1580. // Create a new SQL query:
  1581. $result = $this->db->sqlQuery($sql);
  1582. // Stop if an error occurs:
  1583. if($result->error()) {
  1584. echo $result->getError();
  1585. die();
  1586. }
  1587. }
  1588. function removeExpiredBans() {
  1589. $sql = 'DELETE FROM
  1590. '.$this->getDataBaseTable('bans').'
  1591. WHERE
  1592. dateTime < NOW();';
  1593. // Create a new SQL query:
  1594. $result = $this->db->sqlQuery($sql);
  1595. // Stop if an error occurs:
  1596. if($result->error()) {
  1597. echo $result->getError();
  1598. die();
  1599. }
  1600. }
  1601. function setInactive($userID, $userName=null) {
  1602. $condition = 'userID='.$this->db->makeSafe($userID);
  1603. if($userName !== null) {
  1604. $condition .= ' OR userName='.$this->db->makeSafe($userName);
  1605. }
  1606. $sql = 'UPDATE
  1607. '.$this->getDataBaseTable('online').'
  1608. SET
  1609. dateTime = DATE_SUB(NOW(), interval '.(intval($this->getConfig('inactiveTimeout'))+1).' MINUTE)
  1610. WHERE
  1611. '.$condition.';';
  1612. // Create a new SQL query:
  1613. $result = $this->db->sqlQuery($sql);
  1614. // Stop if an error occurs:
  1615. if($result->error()) {
  1616. echo $result->getError();
  1617. die();
  1618. }
  1619. $this->resetOnlineUsersData();
  1620. }
  1621. function removeInactive() {
  1622. $sql = 'SELECT
  1623. userID,
  1624. userName,
  1625. channel
  1626. FROM
  1627. '.$this->getDataBaseTable('online').'
  1628. WHERE
  1629. NOW() > DATE_ADD(dateTime, interval '.$this->getConfig('inactiveTimeout').' MINUTE);';
  1630. // Create a new SQL query:
  1631. $result = $this->db->sqlQuery($sql);
  1632. // Stop if an error occurs:
  1633. if($result->error()) {
  1634. echo $result->getError();
  1635. die();
  1636. }
  1637. if($result->numRows() > 0) {
  1638. $condition = '';
  1639. while($row = $result->fetch()) {
  1640. if(!empty($condition))
  1641. $condition .= ' OR ';
  1642. // Add userID to condition for removal:
  1643. $condition .= 'userID='.$this->db->makeSafe($row['userID']);
  1644. // Update the socket server authentication for the kicked user:
  1645. if($this->getConfig('socketServerEnabled')) {
  1646. $this->updateSocketAuthentication($row['userID']);
  1647. }
  1648. $this->removeUserFromOnlineUsersData($row['userID']);
  1649. // Insert logout timeout message:
  1650. $text = '/logout '.$row['userName'].' Timeout';
  1651. $this->insertChatBotMessage(
  1652. $row['channel'],
  1653. $text,
  1654. null,
  1655. 1
  1656. );
  1657. }
  1658. $result->free();
  1659. $sql = 'DELETE FROM
  1660. '.$this->getDataBaseTable('online').'
  1661. WHERE
  1662. '.$condition.';';
  1663. // Create a new SQL query:
  1664. $result = $this->db->sqlQuery($sql);
  1665. // Stop if an error occurs:
  1666. if($result->error()) {
  1667. echo $result->getError();
  1668. die();
  1669. }
  1670. }
  1671. }
  1672. function updateOnlineStatus() {
  1673. // Update online status every 50 seconds (this allows update requests to be in time):
  1674. if(!$this->getStatusUpdateTimeStamp() || ((time() - $this->getStatusUpdateTimeStamp()) > 50)) {
  1675. $this->updateOnlineList();
  1676. $this->setStatusUpdateTimeStamp(time());
  1677. }
  1678. }
  1679. function checkAndRemoveInactive() {
  1680. // Remove inactive users every inactiveCheckInterval:
  1681. if(!$this->getInactiveCheckTimeStamp() || ((time() - $this->getInactiveCheckTimeStamp()) > $this->getConfig('inactiveCheckInterval')*60)) {
  1682. $this->removeInactive();
  1683. $this->setInactiveCheckTimeStamp(time());
  1684. }
  1685. }
  1686. function sendXMLMessages() {
  1687. $httpHeader = new AJAXChatHTTPHeader('UTF-8', 'text/xml');
  1688. // Send HTTP header:
  1689. $httpHeader->send();
  1690. // Output XML messages:
  1691. echo $this->getXMLMessages();
  1692. }
  1693. function getXMLMessages() {
  1694. switch($this->getView()) {
  1695. case 'chat':
  1696. return $this->getChatViewXMLMessages();
  1697. case 'teaser':
  1698. return $this->getTeaserViewXMLMessages();
  1699. case 'logs':
  1700. return $this->getLogsViewXMLMessages();
  1701. default:
  1702. return $this->getLogoutXMLMessage();
  1703. }
  1704. }
  1705. function getMessageCondition() {
  1706. $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')).'
  1707. AND (
  1708. channel = '.$this->db->makeSafe($this->getChannel()).'
  1709. OR
  1710. channel = '.$this->db->makeSafe($this->getPrivateMessageID()).'
  1711. )
  1712. AND
  1713. ';
  1714. if($this->getConfig('requestMessagesPriorChannelEnter') ||
  1715. ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($this->getChannel(), $this->getConfig('requestMessagesPriorChannelEnterList')))) {
  1716. $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
  1717. } else {
  1718. $condition .= 'dateTime >= \''.date('Y-m-d H:i:s', $this->getChannelEnterTimeStamp()).'\'';
  1719. }
  1720. return $condition;
  1721. }
  1722. function getMessageFilter() {
  1723. $filterChannelMessages = '';
  1724. if(!$this->getConfig('showChannelMessages') || $this->getRequestVar('shoutbox')) {
  1725. $filterChannelMessages = ' AND NOT (
  1726. text LIKE (\'/login%\')
  1727. OR
  1728. text LIKE (\'/logout%\')
  1729. OR
  1730. text LIKE (\'/channelEnter%\')
  1731. OR
  1732. text LIKE (\'/channelLeave%\')
  1733. OR
  1734. text LIKE (\'/kick%\')
  1735. )';
  1736. }
  1737. return $filterChannelMessages;
  1738. }
  1739. function getInfoMessagesXML() {
  1740. $xml = '<infos>';
  1741. // Go through the info messages:
  1742. foreach($this->getInfoMessages() as $type=>$infoArray) {
  1743. foreach($infoArray as $info) {
  1744. $xml .= '<info type="'.$type.'">';
  1745. $xml .= '<![CDATA['.$this->encodeSpecialChars($info).']]>';
  1746. $xml .= '</info>';
  1747. }
  1748. }
  1749. $xml .= '</infos>';
  1750. return $xml;
  1751. }
  1752. function getChatViewOnlineUsersXML($channelIDs) {
  1753. // Get the online users for the given channels:
  1754. $onlineUsersData = $this->getOnlineUsersData($channelIDs);
  1755. $xml = '<users>';
  1756. foreach($onlineUsersData as $onlineUserData) {
  1757. $xml .= '<user';
  1758. $xml .= ' userID="'.$onlineUserData['userID'].'"';
  1759. $xml .= ' userRole="'.$onlineUserData['userRole'].'"';
  1760. $xml .= ' channelID="'.$onlineUserData['channel'].'"';
  1761. $xml .= '>';
  1762. $xml .= '<![CDATA['.$this->encodeSpecialChars($onlineUserData['userName']).']]>';
  1763. $xml .= '</user>';
  1764. }
  1765. $xml .= '</users>';
  1766. return $xml;
  1767. }
  1768. function getLogoutXMLMessage() {
  1769. $xml = '<?xml version="1.0" encoding="UTF-8"?>';
  1770. $xml .= '<root>';
  1771. $xml .= '<infos>';
  1772. $xml .= '<info type="logout">';
  1773. $xml .= '<![CDATA['.$this->encodeSpecialChars($this->getConfig('logoutData')).']]>';
  1774. $xml .= '</info>';
  1775. $xml .= '</infos>';
  1776. $xml .= '</root>';
  1777. return $xml;
  1778. }
  1779. function getChatViewMessageXML(
  1780. $messageID,
  1781. $timeStamp,
  1782. $userID,
  1783. $userName,
  1784. $userRole,
  1785. $channelID,
  1786. $text
  1787. ) {
  1788. $message = '<message';
  1789. $message .= ' id="'.$messageID.'"';
  1790. $message .= ' dateTime="'.date('r', $timeStamp).'"';
  1791. $message .= ' userID="'.$userID.'"';
  1792. $message .= ' userRole="'.$userRole.'"';
  1793. $message .= ' channelID="'.$channelID.'"';
  1794. $message .= '>';
  1795. $message .= '<username><![CDATA['.$this->encodeSpecialChars($userName).']]></username>';
  1796. $message .= '<text><![CDATA['.$this->encodeSpecialChars($text).']]></text>';
  1797. $message .= '</message>';
  1798. return $message;
  1799. }
  1800. function getChatViewMessagesXML() {
  1801. // Get the last messages in descending order (this optimises the LIMIT usage):
  1802. $sql = 'SELECT
  1803. id,
  1804. userID,
  1805. userName,
  1806. userRole,
  1807. channel AS channelID,
  1808. UNIX_TIMESTAMP(dateTime) AS timeStamp,
  1809. text
  1810. FROM
  1811. '.$this->getDataBaseTable('messages').'
  1812. WHERE
  1813. '.$this->getMessageCondition().'
  1814. '.$this->getMessageFilter().'
  1815. ORDER BY
  1816. id
  1817. DESC
  1818. LIMIT '.$this->getConfig('requestMessagesLimit').';';
  1819. // Create a new SQL query:
  1820. $result = $this->db->sqlQuery($sql);
  1821. // Stop if an error occurs:
  1822. if($result->error()) {
  1823. echo $result->getError();
  1824. die();
  1825. }
  1826. $messages = '';
  1827. // Add the messages in reverse order so it is ascending again:
  1828. while($row = $result->fetch()) {
  1829. $message = $this->getChatViewMessageXML(
  1830. $row['id'],
  1831. $row['timeStamp'],
  1832. $row['userID'],
  1833. $row['userName'],
  1834. $row['userRole'],
  1835. $row['channelID'],
  1836. $row['text']
  1837. );
  1838. $messages = $message.$messages;
  1839. }
  1840. $result->free();
  1841. $messages = '<messages>'.$messages.'</messages>';
  1842. return $messages;
  1843. }
  1844. function getChatViewXMLMessages() {
  1845. $xml = '<?xml version="1.0" encoding="UTF-8"?>';
  1846. $xml .= '<root>';
  1847. $xml .= $this->getInfoMessagesXML();
  1848. $xml .= $this->getChatViewOnlineUsersXML(array($this->getChannel()));
  1849. $xml .= $this->getChatViewMessagesXML();
  1850. $xml .= '</root>';
  1851. return $xml;
  1852. }
  1853. function getTeaserMessageCondition() {
  1854. $channelID = $this->getValidRequestChannelID();
  1855. $condition = 'channel = '.$this->db->makeSafe($channelID).'
  1856. AND
  1857. ';
  1858. if($this->getConfig('requestMessagesPriorChannelEnter') ||
  1859. ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($channelID, $this->getConfig('requestMessagesPriorChannelEnterList')))) {
  1860. $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)';
  1861. } else {
  1862. // Teaser content may not be shown for this channel:
  1863. $condition .= '0 = 1';
  1864. }
  1865. return $condition;
  1866. }
  1867. function getTeaserViewMessagesXML() {
  1868. // Get the last messages in descending order (this optimises the LIMIT usage):
  1869. $sql = 'SELECT
  1870. id,
  1871. userID,
  1872. userName,
  1873. userRole,
  1874. channel AS channelID,
  1875. UNIX_TIMESTAMP(dateTime) AS timeStamp,
  1876. text
  1877. FROM
  1878. '.$this->getDataBaseTable('messages').'
  1879. WHERE
  1880. '.$this->getTeaserMessageCondition().'
  1881. '.$this->getMessageFilter().'
  1882. ORDER BY
  1883. id
  1884. DESC
  1885. LIMIT '.$this->getConfig('requestMessagesLimit').';';
  1886. // Create a new SQL query:
  1887. $result = $this->db->sqlQuery($sql);
  1888. // Stop if an error occurs:
  1889. if($result->error()) {
  1890. echo $result->getError();
  1891. die();
  1892. }
  1893. $messages = '';
  1894. // Add the messages in reverse order so it is ascending again:
  1895. while($row = $result->fetch()) {
  1896. $message = '';
  1897. $message .= '<message';
  1898. $message .= ' id="'.$row['id'].'"';
  1899. $message .= ' dateTime="'.date('r', $row['timeStamp']).'"';
  1900. $message .= ' userID="'.$row['userID'].'"';
  1901. $message .= ' userRole="'.$row['userRole'].'"';
  1902. $message .= ' channelID="'.$row['channelID'].'"';
  1903. $message .= '>';
  1904. $message .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
  1905. $message .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
  1906. $message .= '</message>';
  1907. $messages = $message.$messages;
  1908. }
  1909. $result->free();
  1910. $messages = '<messages>'.$messages.'</messages>';
  1911. return $messages;
  1912. }
  1913. function getTeaserViewXMLMessages() {
  1914. $xml = '<?xml version="1.0" encoding="UTF-8"?>';
  1915. $xml .= '<root>';
  1916. $xml .= $this->getInfoMessagesXML();
  1917. $xml .= $this->getTeaserViewMessagesXML();
  1918. $xml .= '</root>';
  1919. return $xml;
  1920. }
  1921. function getLogsViewCondition() {
  1922. $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID'));
  1923. // Check the channel condition:
  1924. switch($this->getRequestVar('channelID')) {
  1925. case '-3':
  1926. // Just display messages from all accessible channels
  1927. if($this->getUserRole() != AJAX_CHAT_ADMIN) {
  1928. $condition .= ' AND (channel = '.$this->db->makeSafe($this->getPrivateMessageID());
  1929. $condition .= ' OR channel = '.$this->db->makeSafe($this->getPrivateChannelID());
  1930. foreach($this->getChannels() as $channel) {
  1931. if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) {
  1932. continue;
  1933. }
  1934. $condition .= ' OR channel = '.$this->db->makeSafe($channel);
  1935. }
  1936. $condition .= ')';
  1937. }
  1938. break;
  1939. case '-2':
  1940. if($this->getUserRole() != AJAX_CHAT_ADMIN) {
  1941. $condition .= ' AND channel = '.($this->getPrivateMessageID());
  1942. } else {
  1943. $condition .= ' AND channel > '.($this->getConfig('privateMessageDiff')-1);
  1944. }
  1945. break;
  1946. case '-1':
  1947. if($this->getUserRole() != AJAX_CHAT_ADMIN) {
  1948. $condition .= ' AND channel = '.($this->getPrivateChannelID());
  1949. } else {
  1950. $condition .= ' AND (channel > '.($this->getConfig('privateChannelDiff')-1).' AND channel < '.($this->getConfig('privateMessageDiff')).')';
  1951. }
  1952. break;
  1953. default:
  1954. if(($this->getUserRole() == AJAX_CHAT_ADMIN || !$this->getConfig('logsUserAccessChannelList') || in_array($this->getRequestVar('channelID'), $this->getConfig('logsUserAccessChannelList')))
  1955. && $this->validateChannel($this->getRequestVar('channelID'))) {
  1956. $condition .= ' AND channel = '.$this->db->makeSafe($this->getRequestVar('channelID'));
  1957. } else {
  1958. // No valid channel:
  1959. $condition .= ' AND 0 = 1';
  1960. }
  1961. }
  1962. // Check the period condition:
  1963. $hour = ($this->getRequestVar('hour') === null || $this->getRequestVar('hour') > 23 || $this->getRequestVar('hour') < 0) ? null : $this->getRequestVar('hour');
  1964. $day = ($this->getRequestVar('day') === null || $this->getRequestVar('day') > 31 || $this->getRequestVar('day') < 1) ? null : $this->getRequestVar('day');
  1965. $month = ($this->getRequestVar('month') === null || $this->getRequestVar('month') > 12 || $this->getRequestVar('month') < 1) ? null : $this->getRequestVar('month');
  1966. $year = ($this->getRequestVar('year') === null || $this->getRequestVar('year') > date('Y') || $this->getRequestVar('year') < $this->getConfig('logsFirstYear')) ? null : $this->getRequestVar('year');
  1967. // If a time (hour) is given but no date (year, month, day), use the current date:
  1968. if($hour !== null) {
  1969. if($day === null)
  1970. $day = date('j');
  1971. if($month === null)
  1972. $month = date('n');
  1973. if($year === null)
  1974. $year = date('Y');
  1975. }
  1976. if($year === null) {
  1977. // No year given, so no period condition
  1978. } else if($month === null) {
  1979. // Define the given year as period:
  1980. $periodStart = mktime(0, 0, 0, 1, 1, $year);
  1981. // The last day in a month can be expressed by using 0 for the day of the next month:
  1982. $periodEnd = mktime(23, 59, 59, 13, 0, $year);
  1983. } else if($day === null) {
  1984. // Define the given month as period:
  1985. $periodStart = mktime(0, 0, 0, $month, 1, $year);
  1986. // The last day in a month can be expressed by using 0 for the day of the next month:
  1987. $periodEnd = mktime(23, 59, 59, $month+1, 0, $year);
  1988. } else if($hour === null){
  1989. // Define the given day as period:
  1990. $periodStart = mktime(0, 0, 0, $month, $day, $year);
  1991. $periodEnd = mktime(23, 59, 59, $month, $day, $year);
  1992. } else {
  1993. // Define the given hour as period:
  1994. $periodStart = mktime($hour, 0, 0, $month, $day, $year);
  1995. $periodEnd = mktime($hour, 59, 59, $month, $day, $year);
  1996. }
  1997. if(isset($periodStart))
  1998. $condition .= ' AND dateTime > \''.date('Y-m-d H:i:s', $periodStart).'\' AND dateTime <= \''.date('Y-m-d H:i:s', $periodEnd).'\'';
  1999. // Check the search condition:
  2000. if($this->getRequestVar('search')) {
  2001. if(($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) && strpos($this->getRequestVar('search'), 'ip=') === 0) {
  2002. // Search for messages with the given IP:
  2003. $ip = substr($this->getRequestVar('search'), 3);
  2004. $condition .= ' AND (ip = '.$this->db->makeSafe($this->ipToStorageFormat($ip)).')';
  2005. } else if(strpos($this->getRequestVar('search'), 'userID=') === 0) {
  2006. // Search for messages with the given userID:
  2007. $userID = substr($this->getRequestVar('search'), 7);
  2008. $condition .= ' AND (userID = '.$this->db->makeSafe($userID).')';
  2009. } else {
  2010. // Use the search value as regular expression on message text and username:
  2011. $condition .= ' AND (userName REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).' OR text REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).')';
  2012. }
  2013. }
  2014. // If no period or search condition is given, just monitor the last messages on the given channel:
  2015. if(!isset($periodStart) && !$this->getRequestVar('search')) {
  2016. $condition .= ' AND NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('logsRequestMessagesTimeDiff').' HOUR)';
  2017. }
  2018. return $condition;
  2019. }
  2020. function getLogsViewMessagesXML() {
  2021. $sql = 'SELECT
  2022. id,
  2023. userID,
  2024. userName,
  2025. userRole,
  2026. channel AS channelID,
  2027. UNIX_TIMESTAMP(dateTime) AS timeStamp,
  2028. ip,
  2029. text
  2030. FROM
  2031. '.$this->getDataBaseTable('messages').'
  2032. WHERE
  2033. '.$this->getLogsViewCondition().'
  2034. ORDER BY
  2035. id
  2036. LIMIT '.$this->getConfig('logsRequestMessagesLimit').';';
  2037. // Create a new SQL query:
  2038. $result = $this->db->sqlQuery($sql);
  2039. // Stop if an error occurs:
  2040. if($result->error()) {
  2041. echo $result->getError();
  2042. die();
  2043. }
  2044. $xml = '<messages>';
  2045. while($row = $result->fetch()) {
  2046. $xml .= '<message';
  2047. $xml .= ' id="'.$row['id'].'"';
  2048. $xml .= ' dateTime="'.date('r', $row['timeStamp']).'"';
  2049. $xml .= ' userID="'.$row['userID'].'"';
  2050. $xml .= ' userRole="'.$row['userRole'].'"';
  2051. $xml .= ' channelID="'.$row['channelID'].'"';
  2052. if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) {
  2053. $xml .= ' ip="'.$this->ipFromStorageFormat($row['ip']).'"';
  2054. }
  2055. $xml .= '>';
  2056. $xml .= '<username><![CDATA['.$this->encodeSpecialChars($row['userName']).']]></username>';
  2057. $xml .= '<text><![CDATA['.$this->encodeSpecialChars($row['text']).']]></text>';
  2058. $xml .= '</message>';
  2059. }
  2060. $result->free();
  2061. $xml .= '</messages>';
  2062. return $xml;
  2063. }
  2064. function getLogsViewXMLMessages() {
  2065. $xml = '<?xml version="1.0" encoding="UTF-8"?>';
  2066. $xml .= '<root>';
  2067. $xml .= $this->getInfoMessagesXML();
  2068. $xml .= $this->getLogsViewMessagesXML();
  2069. $xml .= '</root>';
  2070. return $xml;
  2071. }
  2072. function purgeLogs() {
  2073. $sql = 'DELETE FROM
  2074. '.$this->getDataBaseTable('messages').'
  2075. WHERE
  2076. dateTime < DATE_SUB(NOW(), interval '.$this->getConfig('logsPurgeTimeDiff').' DAY);';
  2077. // Create a new SQL query:
  2078. $result = $this->db->sqlQuery($sql);
  2079. // Stop if an error occurs:
  2080. if($result->error()) {
  2081. echo $result->getError();
  2082. die();
  2083. }
  2084. }
  2085. function getInfoMessages($type=null) {
  2086. if(!isset($this->_infoMessages)) {
  2087. $this->_infoMessages = array();
  2088. }
  2089. if($type) {
  2090. if(!isset($this->_infoMessages[$type])) {
  2091. $this->_infoMessages[$type] = array();
  2092. }
  2093. return $this->_infoMessages[$type];
  2094. } else {
  2095. return $this->_infoMessages;
  2096. }
  2097. }
  2098. function addInfoMessage($info, $type='error') {
  2099. if(!isset($this->_infoMessages)) {
  2100. $this->_infoMessages = array();
  2101. }
  2102. if(!isset($this->_infoMessages[$type])) {
  2103. $this->_infoMessages[$type] = array();
  2104. }
  2105. if(!in_array($info, $this->_infoMessages[$type])) {
  2106. array_push($this->_infoMessages[$type], $info);
  2107. }
  2108. }
  2109. function getRequestVars() {
  2110. return $this->_requestVars;
  2111. }
  2112. function getRequestVar($key) {
  2113. if($this->_requestVars && isset($this->_requestVars[$key])) {
  2114. return $this->_requestVars[$key];
  2115. }
  2116. return null;
  2117. }
  2118. function setRequestVar($key, $value) {
  2119. if(!$this->_requestVars) {
  2120. $this->_requestVars = array();
  2121. }
  2122. $this->_requestVars[$key] = $value;
  2123. }
  2124. function getOnlineUsersData($channelIDs=null, $key=null, $value=null) {
  2125. if($this->_onlineUsersData === null) {
  2126. $this->_onlineUsersData = array();
  2127. $sql = 'SELECT
  2128. userID,
  2129. userName,
  2130. userRole,
  2131. channel,
  2132. UNIX_TIMESTAMP(dateTime) AS timeStamp,
  2133. ip
  2134. FROM
  2135. '.$this->getDataBaseTable('online').'
  2136. ORDER BY
  2137. userName;';
  2138. // Create a new SQL query:
  2139. $result = $this->db->sqlQuery($sql);
  2140. // Stop if an error occurs:
  2141. if($result->error()) {
  2142. echo $result->getError();
  2143. die();
  2144. }
  2145. while($row = $result->fetch()) {
  2146. $row['ip'] = $this->ipFromStorageFormat($row['ip']);
  2147. array_push($this->_onlineUsersData, $row);
  2148. }
  2149. $result->free();
  2150. }
  2151. if($channelIDs || $key) {
  2152. $onlineUsersData = array();
  2153. foreach($this->_onlineUsersData as $userData) {
  2154. if($channelIDs && !in_array($userData['channel'], $channelIDs)) {
  2155. continue;
  2156. }
  2157. if($key) {
  2158. if(!isset($userData[$key])) {
  2159. return $onlineUsersData;
  2160. }
  2161. if($value !== null) {
  2162. if($userData[$key] == $value) {
  2163. array_push($onlineUsersData, $userData);
  2164. } else {
  2165. continue;
  2166. }
  2167. } else {
  2168. array_push($onlineUsersData, $userData[$key]);
  2169. }
  2170. } else {
  2171. array_push($onlineUsersData, $userData);
  2172. }
  2173. }
  2174. return $onlineUsersData;
  2175. }
  2176. return $this->_onlineUsersData;
  2177. }
  2178. function removeUserFromOnlineUsersData($userID=null) {
  2179. if(!$this->_onlineUsersData) {
  2180. return;
  2181. }
  2182. $userID = ($userID === null) ? $this->getUserID() : $userID;
  2183. for($i=0; $i<count($this->_onlineUsersData); $i++) {
  2184. if($this->_onlineUsersData[$i]['userID'] == $userID) {
  2185. array_splice($this->_onlineUsersData, $i, 1);
  2186. break;
  2187. }
  2188. }
  2189. }
  2190. function resetOnlineUsersData() {
  2191. $this->_onlineUsersData = null;
  2192. }
  2193. function getOnlineUsers($channelIDs=null) {
  2194. return $this->getOnlineUsersData($channelIDs, 'userName');
  2195. }
  2196. function getOnlineUserIDs($channelIDs=null) {
  2197. return $this->getOnlineUsersData($channelIDs, 'userID');
  2198. }
  2199. function startSession() {
  2200. if(!session_id()) {
  2201. // Set the session name:
  2202. session_name($this->getConfig('sessionName'));
  2203. // Set session cookie parameters:
  2204. session_set_cookie_params(
  2205. 0, // The session is destroyed on logout anyway, so no use to set this
  2206. $this->getConfig('sessionCookiePath'),
  2207. $this->getConfig('sessionCookieDomain'),
  2208. $this->getConfig('sessionCookieSecure')
  2209. );
  2210. // Start the session:
  2211. session_start();
  2212. // We started a new session:
  2213. $this->_sessionNew = true;
  2214. }
  2215. }
  2216. function destroySession() {
  2217. if($this->_sessionNew) {
  2218. // Delete all session variables:
  2219. $_SESSION = array();
  2220. // Delete the session cookie:
  2221. if (isset($_COOKIE[session_name()])) {
  2222. setcookie(
  2223. session_name(),
  2224. '',
  2225. time()-42000,
  2226. $this->getConfig('sessionCookiePath'),
  2227. $this->getConfig('sessionCookieDomain'),
  2228. $this->getConfig('sessionCookieSecure')
  2229. );
  2230. }
  2231. // Destroy the session:
  2232. session_destroy();
  2233. } else {
  2234. // Unset all session variables starting with the sessionKeyPrefix:
  2235. foreach($_SESSION as $key=>$value) {
  2236. if(strpos($key, $this->getConfig('sessionKeyPrefix')) === 0) {
  2237. unset($_SESSION[$key]);
  2238. }
  2239. }
  2240. }
  2241. }
  2242. function regenerateSessionID() {
  2243. if($this->_sessionNew) {
  2244. // Regenerate session id:
  2245. @session_regenerate_id(true);
  2246. }
  2247. }
  2248. function getSessionVar($key, $prefix=null) {
  2249. if($prefix === null)
  2250. $prefix = $this->getConfig('sessionKeyPrefix');
  2251. // Return the session value if existing:
  2252. if(isset($_SESSION[$prefix.$key]))
  2253. return $_SESSION[$prefix.$key];
  2254. else
  2255. return null;
  2256. }
  2257. function setSessionVar($key, $value, $prefix=null) {
  2258. if($prefix === null)
  2259. $prefix = $this->getConfig('sessionKeyPrefix');
  2260. // Set the session value:
  2261. $_SESSION[$prefix.$key] = $value;
  2262. }
  2263. function getSessionIP() {
  2264. return $this->getSessionVar('IP');
  2265. }
  2266. function setSessionIP($ip) {
  2267. $this->setSessionVar('IP', $ip);
  2268. }
  2269. function getQueryUserName() {
  2270. return $this->getSessionVar('QueryUserName');
  2271. }
  2272. function setQueryUserName($userName) {
  2273. $this->setSessionVar('QueryUserName', $userName);
  2274. }
  2275. function getInvitations() {
  2276. if($this->_invitations === null) {
  2277. $this->_invitations = array();
  2278. $sql = 'SELECT
  2279. channel
  2280. FROM
  2281. '.$this->getDataBaseTable('invitations').'
  2282. WHERE
  2283. userID='.$this->db->makeSafe($this->getUserID()).'
  2284. AND
  2285. DATE_SUB(NOW(), interval 1 DAY) < dateTime;';
  2286. // Create a new SQL query:
  2287. $result = $this->db->sqlQuery($sql);
  2288. // Stop if an error occurs:
  2289. if($result->error()) {
  2290. echo $result->getError();
  2291. die();
  2292. }
  2293. while($row = $result->fetch()) {
  2294. array_push($this->_invitations, $row['channel']);
  2295. }
  2296. $result->free();
  2297. }
  2298. return $this->_invitations;
  2299. }
  2300. function removeExpiredInvitations() {
  2301. $sql = 'DELETE FROM
  2302. '.$this->getDataBaseTable('invitations').'
  2303. WHERE
  2304. DATE_SUB(NOW(), interval 1 DAY) > dateTime;';
  2305. // Create a new SQL query:
  2306. $result = $this->db->sqlQuery($sql);
  2307. // Stop if an error occurs:
  2308. if($result->error()) {
  2309. echo $result->getError();
  2310. die();
  2311. }
  2312. }
  2313. function addInvitation($userID, $channelID=null) {
  2314. $this->removeExpiredInvitations();
  2315. $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
  2316. $sql = 'INSERT INTO '.$this->getDataBaseTable('invitations').'(
  2317. userID,
  2318. channel,
  2319. dateTime
  2320. )
  2321. VALUES (
  2322. '.$this->db->makeSafe($userID).',
  2323. '.$this->db->makeSafe($channelID).',
  2324. NOW()
  2325. );';
  2326. // Create a new SQL query:
  2327. $result = $this->db->sqlQuery($sql);
  2328. // Stop if an error occurs:
  2329. if($result->error()) {
  2330. echo $result->getError();
  2331. die();
  2332. }
  2333. }
  2334. function removeInvitation($userID, $channelID=null) {
  2335. $channelID = ($channelID === null) ? $this->getChannel() : $channelID;
  2336. $sql = 'DELETE FROM
  2337. '.$this->getDataBaseTable('invitations').'
  2338. WHERE
  2339. userID='.$this->db->makeSafe($userID).'
  2340. AND
  2341. channel='.$this->db->makeSafe($channelID).';';
  2342. // Create a new SQL query:
  2343. $result = $this->db->sqlQuery($sql);
  2344. // Stop if an error occurs:
  2345. if($result->error()) {
  2346. echo $result->getError();
  2347. die();
  2348. }
  2349. }
  2350. function getUserID() {
  2351. return $this->getSessionVar('UserID');
  2352. }
  2353. function setUserID($id) {
  2354. $this->setSessionVar('UserID', $id);
  2355. }
  2356. function getUserName() {
  2357. return $this->getSessionVar('UserName');
  2358. }
  2359. function setUserName($name) {
  2360. $this->setSessionVar('UserName', $name);
  2361. }
  2362. function getLoginUserName() {
  2363. return $this->getSessionVar('LoginUserName');
  2364. }
  2365. function setLoginUserName($name) {
  2366. $this->setSessionVar('LoginUserName', $name);
  2367. }
  2368. function getUserRole() {
  2369. $userRole = $this->getSessionVar('UserRole');
  2370. if($userRole === null)
  2371. return AJAX_CHAT_GUEST;
  2372. return $userRole;
  2373. }
  2374. function setUserRole($role) {
  2375. $this->setSessionVar('UserRole', $role);
  2376. }
  2377. function getChannel() {
  2378. return $this->getSessionVar('Channel');
  2379. }
  2380. function setChannel($channel) {
  2381. $this->setSessionVar('Channel', $channel);
  2382. // Save the channel enter timestamp:
  2383. $this->setChannelEnterTimeStamp(time());
  2384. // Update the channel authentication for the socket server:
  2385. if($this->getConfig('socketServerEnabled')) {
  2386. $this->updateSocketAuthentication(
  2387. $this->getUserID(),
  2388. $this->getSocketRegistrationID(),
  2389. array($channel,$this->getPrivateMessageID())
  2390. );
  2391. }
  2392. // Reset the logs view socket authentication session var:
  2393. if($this->getSessionVar('logsViewSocketAuthenticated')) {
  2394. $this->setSessionVar('logsViewSocketAuthenticated', false);
  2395. }
  2396. }
  2397. function isLoggedIn() {
  2398. return (bool)$this->getSessionVar('LoggedIn');
  2399. }
  2400. function setLoggedIn($bool) {
  2401. $this->setSessionVar('LoggedIn', $bool);
  2402. }
  2403. function getLoginTimeStamp() {
  2404. return $this->getSessionVar('LoginTimeStamp');
  2405. }
  2406. function setLoginTimeStamp($time) {
  2407. $this->setSessionVar('LoginTimeStamp', $time);
  2408. }
  2409. function getChannelEnterTimeStamp() {
  2410. return $this->getSessionVar('ChannelEnterTimeStamp');
  2411. }
  2412. function setChannelEnterTimeStamp($time) {
  2413. $this->setSessionVar('ChannelEnterTimeStamp', $time);
  2414. }
  2415. function getStatusUpdateTimeStamp() {
  2416. return $this->getSessionVar('StatusUpdateTimeStamp');
  2417. }
  2418. function setStatusUpdateTimeStamp($time) {
  2419. $this->setSessionVar('StatusUpdateTimeStamp', $time);
  2420. }
  2421. function getInactiveCheckTimeStamp() {
  2422. return $this->getSessionVar('InactiveCheckTimeStamp');
  2423. }
  2424. function setInactiveCheckTimeStamp($time) {
  2425. $this->setSessionVar('InactiveCheckTimeStamp', $time);
  2426. }
  2427. function getInsertedMessagesRate() {
  2428. return $this->getSessionVar('InsertedMessagesRate');
  2429. }
  2430. function setInsertedMessagesRate($rate) {
  2431. $this->setSessionVar('InsertedMessagesRate', $rate);
  2432. }
  2433. function getInsertedMessagesRateTimeStamp() {
  2434. return $this->getSessionVar('InsertedMessagesRateTimeStamp');
  2435. }
  2436. function setInsertedMessagesRateTimeStamp($time) {
  2437. $this->setSessionVar('InsertedMessagesRateTimeStamp', $time);
  2438. }
  2439. function getLangCode() {
  2440. // Get the langCode from request or cookie:
  2441. $langCodeCookie = isset($_COOKIE[$this->getConfig('sessionName').'_lang']) ? $_COOKIE[$this->getConfig('sessionName').'_lang'] : null;
  2442. $langCode = $this->getRequestVar('lang') ? $this->getRequestVar('lang') : $langCodeCookie;
  2443. // Check if the langCode is valid:
  2444. if(!in_array($langCode, $this->getConfig('langAvailable'))) {
  2445. // Determine the user language:
  2446. $language = new AJAXChatLanguage($this->getConfig('langAvailable'), $this->getConfig('langDefault'));
  2447. $langCode = $language->getLangCode();
  2448. }
  2449. return $langCode;
  2450. }
  2451. function setLangCodeCookie() {
  2452. setcookie(
  2453. $this->getConfig('sessionName').'_lang',
  2454. $this->getLangCode(),
  2455. time()+60*60*24*$this->getConfig('sessionCookieLifeTime'),
  2456. $this->getConfig('sessionCookiePath'),
  2457. $this->getConfig('sessionCookieDomain'),
  2458. $this->getConfig('sessionCookieSecure')
  2459. );
  2460. }
  2461. function removeUnsafeCharacters($str) {
  2462. // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127:
  2463. return AJAXChatEncoding::removeUnsafeCharacters($str);
  2464. }
  2465. function subString($str, $start=0, $length=null, $encoding='UTF-8') {
  2466. return AJAXChatString::subString($str, $start, $length, $encoding);
  2467. }
  2468. function stringLength($str, $encoding='UTF-8') {
  2469. return AJAXChatString::stringLength($str, $encoding);
  2470. }
  2471. function trimMessageText($text) {
  2472. return $this->trimString($text, 'UTF-8', $this->getConfig('messageTextMaxLength'));
  2473. }
  2474. function trimUserName($userName) {
  2475. return $this->trimString($userName, null, $this->getConfig('userNameMaxLength'), true, true);
  2476. }
  2477. function trimChannelName($channelName) {
  2478. return $this->trimString($channelName, null, null, true, true);
  2479. }
  2480. function trimString($str, $sourceEncoding=null, $maxLength=null, $replaceWhitespace=false, $decodeEntities=false, $htmlEntitiesMap=null) {
  2481. // Make sure the string contains valid unicode:
  2482. $str = $this->convertToUnicode($str, $sourceEncoding);
  2483. // Make sure the string contains no unsafe characters:
  2484. $str = $this->removeUnsafeCharacters($str);
  2485. // Strip whitespace from the beginning and end of the string:
  2486. $str = trim($str);
  2487. if($replaceWhitespace) {
  2488. // Replace any whitespace in the userName with the underscore "_":
  2489. $str = preg_replace('/\s/u', '_', $str);
  2490. }
  2491. if($decodeEntities) {
  2492. // Decode entities:
  2493. $str = $this->decodeEntities($str, 'UTF-8', $htmlEntitiesMap);
  2494. }
  2495. if($maxLength) {
  2496. // Cut the string to the allowed length:
  2497. $str = $this->subString($str, 0, $maxLength);
  2498. }
  2499. return $str;
  2500. }
  2501. function convertToUnicode($str, $sourceEncoding=null) {
  2502. if($sourceEncoding === null) {
  2503. $sourceEncoding = $this->getConfig('sourceEncoding');
  2504. }
  2505. return $this->convertEncoding($str, $sourceEncoding, 'UTF-8');
  2506. }
  2507. function convertFromUnicode($str, $contentEncoding=null) {
  2508. if($contentEncoding === null) {
  2509. $contentEncoding = $this->getConfig('contentEncoding');
  2510. }
  2511. return $this->convertEncoding($str, 'UTF-8', $contentEncoding);
  2512. }
  2513. function convertEncoding($str, $charsetFrom, $charsetTo) {
  2514. return AJAXChatEncoding::convertEncoding($str, $charsetFrom, $charsetTo);
  2515. }
  2516. function encodeEntities($str, $encoding='UTF-8', $convmap=null) {
  2517. return AJAXChatEncoding::encodeEntities($str, $encoding, $convmap);
  2518. }
  2519. function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) {
  2520. return AJAXChatEncoding::decodeEntities($str, $encoding, $htmlEntitiesMap);
  2521. }
  2522. function htmlEncode($str) {
  2523. return AJAXChatEncoding::htmlEncode($str, $this->getConfig('contentEncoding'));
  2524. }
  2525. function encodeSpecialChars($str) {
  2526. return AJAXChatEncoding::encodeSpecialChars($str);
  2527. }
  2528. function decodeSpecialChars($str) {
  2529. return AJAXChatEncoding::decodeSpecialChars($str);
  2530. }
  2531. function ipToStorageFormat($ip) {
  2532. if(function_exists('inet_pton')) {
  2533. // ipv4 & ipv6:
  2534. return @inet_pton($ip);
  2535. }
  2536. // Only ipv4:
  2537. return @pack('N',@ip2long($ip));
  2538. }
  2539. function ipFromStorageFormat($ip) {
  2540. if(function_exists('inet_ntop')) {
  2541. // ipv4 & ipv6:
  2542. return @inet_ntop($ip);
  2543. }
  2544. // Only ipv4:
  2545. $unpacked = @unpack('Nlong',$ip);
  2546. if(isset($unpacked['long'])) {
  2547. return @long2ip($unpacked['long']);
  2548. }
  2549. return null;
  2550. }
  2551. function getConfig($key, $subkey=null) {
  2552. if($subkey)
  2553. return $this->_config[$key][$subkey];
  2554. else
  2555. return $this->_config[$key];
  2556. }
  2557. function setConfig($key, $subkey, $value) {
  2558. if($subkey) {
  2559. if(!isset($this->_config[$key])) {
  2560. $this->_config[$key] = array();
  2561. }
  2562. $this->_config[$key][$subkey] = $value;
  2563. } else {
  2564. $this->_config[$key] = $value;
  2565. }
  2566. }
  2567. function getLang($key=null) {
  2568. if(!$this->_lang) {
  2569. // Include the language file:
  2570. $lang = null;
  2571. require(AJAX_CHAT_PATH.'lib/lang/'.$this->getLangCode().'.php');
  2572. $this->_lang = &$lang;
  2573. }
  2574. if($key === null)
  2575. return $this->_lang;
  2576. if(isset($this->_lang[$key]))
  2577. return $this->_lang[$key];
  2578. return null;
  2579. }
  2580. function getChatURL() {
  2581. if(defined('AJAX_CHAT_URL')) {
  2582. return AJAX_CHAT_URL;
  2583. }
  2584. return
  2585. (isset($_SERVER['HTTPS']) ? 'https://' : 'http://').
  2586. (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : '').
  2587. (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME'].
  2588. (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443 || $_SERVER['SERVER_PORT'] == 80 ? '' : ':'.$_SERVER['SERVER_PORT']))).
  2589. substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')+1);
  2590. }
  2591. function getIDFromName($userName) {
  2592. $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
  2593. if($userDataArray && isset($userDataArray[0])) {
  2594. return $userDataArray[0]['userID'];
  2595. }
  2596. return null;
  2597. }
  2598. function getNameFromID($userID) {
  2599. $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
  2600. if($userDataArray && isset($userDataArray[0])) {
  2601. return $userDataArray[0]['userName'];
  2602. }
  2603. return null;
  2604. }
  2605. function getChannelFromID($userID) {
  2606. $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
  2607. if($userDataArray && isset($userDataArray[0])) {
  2608. return $userDataArray[0]['channel'];
  2609. }
  2610. return null;
  2611. }
  2612. function getIPFromID($userID) {
  2613. $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
  2614. if($userDataArray && isset($userDataArray[0])) {
  2615. return $userDataArray[0]['ip'];
  2616. }
  2617. return null;
  2618. }
  2619. function getRoleFromID($userID) {
  2620. $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
  2621. if($userDataArray && isset($userDataArray[0])) {
  2622. return $userDataArray[0]['userRole'];
  2623. }
  2624. return null;
  2625. }
  2626. function getChannelNames() {
  2627. return array_flip($this->getChannels());
  2628. }
  2629. function getChannelIDFromChannelName($channelName) {
  2630. if(!$channelName)
  2631. return null;
  2632. $channels = $this->getAllChannels();
  2633. if(array_key_exists($channelName,$channels)) {
  2634. return $channels[$channelName];
  2635. }
  2636. $channelID = null;
  2637. // Check if the requested channel is the own private channel:
  2638. if($channelName == $this->getPrivateChannelName()) {
  2639. return $this->getPrivateChannelID();
  2640. }
  2641. // Try to retrieve a private room ID:
  2642. $strlenChannelName = $this->stringLength($channelName);
  2643. $strlenPrefix = $this->stringLength($this->getConfig('privateChannelPrefix'));
  2644. $strlenSuffix = $this->stringLength($this->getConfig('privateChannelSuffix'));
  2645. if($this->subString($channelName,0,$strlenPrefix) == $this->getConfig('privateChannelPrefix')
  2646. && $this->subString($channelName,$strlenChannelName-$strlenSuffix) == $this->getConfig('privateChannelSuffix')) {
  2647. $userName = $this->subString(
  2648. $channelName,
  2649. $strlenPrefix,
  2650. $strlenChannelName-($strlenPrefix+$strlenSuffix)
  2651. );
  2652. $userID = $this->getIDFromName($userName);
  2653. if($userID !== null) {
  2654. $channelID = $this->getPrivateChannelID($userID);
  2655. }
  2656. }
  2657. return $channelID;
  2658. }
  2659. function getChannelNameFromChannelID($channelID) {
  2660. foreach($this->getAllChannels() as $key=>$value) {
  2661. if($value == $channelID) {
  2662. return $key;
  2663. }
  2664. }
  2665. // Try to retrieve a private room name:
  2666. if($channelID == $this->getPrivateChannelID()) {
  2667. return $this->getPrivateChannelName();
  2668. }
  2669. $userName = $this->getNameFromID($channelID-$this->getConfig('privateChannelDiff'));
  2670. if($userName === null) {
  2671. return null;
  2672. }
  2673. return $this->getPrivateChannelName($userName);
  2674. }
  2675. function getChannelName() {
  2676. return $this->getChannelNameFromChannelID($this->getChannel());
  2677. }
  2678. function getPrivateChannelName($userName=null) {
  2679. if($userName === null) {
  2680. $userName = $this->getUserName();
  2681. }
  2682. return $this->getConfig('privateChannelPrefix').$userName.$this->getConfig('privateChannelSuffix');
  2683. }
  2684. function getPrivateChannelID($userID=null) {
  2685. if($userID === null) {
  2686. $userID = $this->getUserID();
  2687. }
  2688. return $userID + $this->getConfig('privateChannelDiff');
  2689. }
  2690. function getPrivateMessageID($userID=null) {
  2691. if($userID === null) {
  2692. $userID = $this->getUserID();
  2693. }
  2694. return $userID + $this->getConfig('privateMessageDiff');
  2695. }
  2696. function isAllowedToSendPrivateMessage() {
  2697. if($this->getConfig('allowPrivateMessages') || $this->getUserRole() == AJAX_CHAT_ADMIN) {
  2698. return true;
  2699. }
  2700. return false;
  2701. }
  2702. function isAllowedToCreatePrivateChannel() {
  2703. if($this->getConfig('allowPrivateChannels')) {
  2704. switch($this->getUserRole()) {
  2705. case AJAX_CHAT_USER:
  2706. return true;
  2707. case AJAX_CHAT_MODERATOR:
  2708. return true;
  2709. case AJAX_CHAT_ADMIN:
  2710. return true;
  2711. default:
  2712. return false;
  2713. }
  2714. }
  2715. return false;
  2716. }
  2717. function isAllowedToListHiddenUsers() {
  2718. // Hidden users are users within private or restricted channels:
  2719. switch($this->getUserRole()) {
  2720. case AJAX_CHAT_MODERATOR:
  2721. return true;
  2722. case AJAX_CHAT_ADMIN:
  2723. return true;
  2724. default:
  2725. return false;
  2726. }
  2727. }
  2728. function isUserOnline($userID=null) {
  2729. $userID = ($userID === null) ? $this->getUserID() : $userID;
  2730. $userDataArray = $this->getOnlineUsersData(null,'userID',$userID);
  2731. if($userDataArray && count($userDataArray) > 0) {
  2732. return true;
  2733. }
  2734. return false;
  2735. }
  2736. function isUserNameInUse($userName=null) {
  2737. $userName = ($userName === null) ? $this->getUserName() : $userName;
  2738. $userDataArray = $this->getOnlineUsersData(null,'userName',$userName);
  2739. if($userDataArray && count($userDataArray) > 0) {
  2740. return true;
  2741. }
  2742. return false;
  2743. }
  2744. function isUserBanned($userName, $userID=null, $ip=null) {
  2745. if($userID !== null) {
  2746. $bannedUserDataArray = $this->getBannedUsersData('userID',$userID);
  2747. if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
  2748. return true;
  2749. }
  2750. }
  2751. if($ip !== null) {
  2752. $bannedUserDataArray = $this->getBannedUsersData('ip',$ip);
  2753. if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
  2754. return true;
  2755. }
  2756. }
  2757. $bannedUserDataArray = $this->getBannedUsersData('userName',$userName);
  2758. if($bannedUserDataArray && isset($bannedUserDataArray[0])) {
  2759. return true;
  2760. }
  2761. return false;
  2762. }
  2763. function isMaxUsersLoggedIn() {
  2764. if(count($this->getOnlineUsersData()) >= $this->getConfig('maxUsersLoggedIn')) {
  2765. return true;
  2766. }
  2767. return false;
  2768. }
  2769. function validateChannel($channelID) {
  2770. if($channelID === null) {
  2771. return false;
  2772. }
  2773. // Return true for normal channels the user has acces to:
  2774. if(in_array($channelID, $this->getChannels())) {
  2775. return true;
  2776. }
  2777. // Return true if the user is allowed to join his own private channel:
  2778. if($channelID == $this->getPrivateChannelID() && $this->isAllowedToCreatePrivateChannel()) {
  2779. return true;
  2780. }
  2781. // Return true if the user has been invited to a restricted or private channel:
  2782. if(in_array($channelID, $this->getInvitations())) {
  2783. return true;
  2784. }
  2785. // No valid channel, return false:
  2786. return false;
  2787. }
  2788. function createGuestUserName() {
  2789. $maxLength = $this->getConfig('userNameMaxLength')
  2790. - $this->stringLength($this->getConfig('guestUserPrefix'))
  2791. - $this->stringLength($this->getConfig('guestUserSuffix'));
  2792. // seed with microseconds since last "whole" second:
  2793. mt_srand((double)microtime()*1000000);
  2794. // Create a random userName using numbers between 100000 and 999999:
  2795. $userName = substr(mt_rand(100000, 999999), 0, $maxLength);
  2796. return $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
  2797. }
  2798. // Guest userIDs must not interfere with existing userIDs and must be lower than privateChannelDiff:
  2799. function createGuestUserID() {
  2800. // seed with microseconds since last "whole" second:
  2801. mt_srand((double)microtime()*1000000);
  2802. return mt_rand($this->getConfig('minGuestUserID'), $this->getConfig('privateChannelDiff')-1);
  2803. }
  2804. function getGuestUser() {
  2805. if(!$this->getConfig('allowGuestLogins'))
  2806. return null;
  2807. if($this->getConfig('allowGuestUserName')) {
  2808. $maxLength = $this->getConfig('userNameMaxLength')
  2809. - $this->stringLength($this->getConfig('guestUserPrefix'))
  2810. - $this->stringLength($this->getConfig('guestUserSuffix'));
  2811. // Trim guest userName:
  2812. $userName = $this->trimString($this->getRequestVar('userName'), null, $maxLength, true, true);
  2813. // If given userName is invalid, create one:
  2814. if(!$userName) {
  2815. $userName = $this->createGuestUserName();
  2816. } else {
  2817. // Add the guest users prefix and suffix to the given userName:
  2818. $userName = $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix');
  2819. }
  2820. } else {
  2821. $userName = $this->createGuestUserName();
  2822. }
  2823. $userData = array();
  2824. $userData['userID'] = $this->createGuestUserID();
  2825. $userData['userName'] = $userName;
  2826. $userData['userRole'] = AJAX_CHAT_GUEST;
  2827. return $userData;
  2828. }
  2829. function getCustomVar($key) {
  2830. if(!isset($this->_customVars))
  2831. $this->_customVars = array();
  2832. if(!isset($this->_customVars[$key]))
  2833. return null;
  2834. return $this->_customVars[$key];
  2835. }
  2836. function setCustomVar($key, $value) {
  2837. if(!isset($this->_customVars))
  2838. $this->_customVars = array();
  2839. $this->_customVars[$key] = $value;
  2840. }
  2841. // Override to replace custom template tags:
  2842. // Return the replacement for the given tag (and given tagContent)
  2843. function replaceCustomTemplateTags($tag, $tagContent) {
  2844. return null;
  2845. }
  2846. // Override to initialize custom configuration settings:
  2847. function initCustomConfig() {
  2848. }
  2849. // Override to add custom request variables:
  2850. // Add values to the request variables array: $this->_requestVars['customVariable'] = null;
  2851. function initCustomRequestVars() {
  2852. }
  2853. // Override to add custom session code right after the session has been started:
  2854. function initCustomSession() {
  2855. }
  2856. // Override, to parse custom info requests:
  2857. // $infoRequest contains the current info request
  2858. // Add info responses using the method addInfoMessage($info, $type)
  2859. function parseCustomInfoRequest($infoRequest) {
  2860. }
  2861. // Override to replace custom text:
  2862. // Return replaced text
  2863. // $text contains the whole message
  2864. function replaceCustomText(&$text) {
  2865. return $text;
  2866. }
  2867. // Override to add custom commands:
  2868. // Return true if a custom command has been successfully parsed, else false
  2869. // $text contains the whole message, $textParts the message split up as words array
  2870. function parseCustomCommands($text, $textParts) {
  2871. return false;
  2872. }
  2873. // Override to perform custom actions on new messages:
  2874. // Return true if message may be inserted, else false
  2875. // $text contains the whole message
  2876. function onNewMessage($text) {
  2877. return true;
  2878. }
  2879. // Override to perform custom actions on new messages:
  2880. // Method to set the style cookie depending on user data
  2881. function setStyle() {
  2882. }
  2883. // Override:
  2884. // Returns true if the userID of the logged in user is identical to the userID of the authentication system
  2885. // or the user is authenticated as guest in the chat and the authentication system
  2886. function revalidateUserID() {
  2887. return true;
  2888. }
  2889. // Override:
  2890. // Returns an associative array containing userName, userID and userRole
  2891. // Returns null if login is invalid
  2892. function getValidLoginUserData() {
  2893. // Check if we have a valid registered user:
  2894. if(false) {
  2895. // Here is the place to check user authentication
  2896. } else {
  2897. // Guest users:
  2898. return $this->getGuestUser();
  2899. }
  2900. }
  2901. // Override:
  2902. // Store the channels the current user has access to
  2903. // Make sure channel names don't contain any whitespace
  2904. function &getChannels() {
  2905. if($this->_channels === null) {
  2906. $this->_channels = $this->getAllChannels();
  2907. }
  2908. return $this->_channels;
  2909. }
  2910. // Override:
  2911. // Store all existing channels
  2912. // Make sure channel names don't contain any whitespace
  2913. function &getAllChannels() {
  2914. if($this->_allChannels === null) {
  2915. $this->_allChannels = array();
  2916. // Default channel, public to everyone:
  2917. $this->_allChannels[$this->trimChannelName($this->getConfig('defaultChannelName'))] = $this->getConfig('defaultChannelID');
  2918. }
  2919. return $this->_allChannels;
  2920. }
  2921. }
  2922. ?>