PageRenderTime 71ms CodeModel.GetById 12ms RepoModel.GetById 1ms 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

Large files files are truncated, but you can click here to view the full file

  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. $r

Large files files are truncated, but you can click here to view the full file