From 67e36b1a7d11e3e2fdf57e2778c906cb22939f82 Mon Sep 17 00:00:00 2001 From: Philip Nicolcev Date: Mon, 15 Dec 2014 23:48:15 -0500 Subject: [PATCH 1/5] use dirname() and stop using chdir() for mybb integration. --- chat/lib/custom.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chat/lib/custom.php b/chat/lib/custom.php index 2305b5b..8e73d4d 100644 --- a/chat/lib/custom.php +++ b/chat/lib/custom.php @@ -12,6 +12,5 @@ // MyBB initialization: define('IN_MYBB', 1); -chdir(AJAX_CHAT_PATH.'../'); -require(AJAX_CHAT_PATH.'../global.php'); -?> \ No newline at end of file + +require(dirname(AJAX_CHAT_PATH).'/global.php'); From 6c4754ab68e7f129f0935fb0768545561e53ebeb Mon Sep 17 00:00:00 2001 From: Philip Nicolcev Date: Sun, 22 Feb 2015 10:35:57 -0500 Subject: [PATCH 2/5] Merge edits from master. --- chat/changelog.txt | 27 +- chat/css/Cobalt.css | 209 +- chat/css/Core.css | 198 +- chat/css/Lithium.css | 201 +- chat/css/Mercury.css | 274 +- chat/css/MyBB.css | 198 +- chat/css/Oxygen.css | 203 +- chat/css/Pine.css | 142 + chat/css/Plum.css | 222 +- chat/css/Sulfur.css | 201 +- chat/css/Uranium.css | 361 +- chat/css/XenForo.css | 238 + chat/css/beige.css | 203 +- chat/css/black.css | 209 +- chat/css/custom.css | 17 + chat/css/fonts.css | 19 +- chat/css/global.css | 292 +- chat/css/grey.css | 204 +- chat/css/ie5-6.css | 70 - chat/css/pine_images/chatlist.jpg | Bin 0 -> 50564 bytes chat/css/print.css | 23 +- chat/css/prosilver.css | 277 +- chat/css/shoutbox.css | 4 + chat/css/subSilver.css | 117 - chat/css/subblack2.css | 117 - chat/css/vBulletin.css | 226 +- chat/img/audio.png | Bin 3966 -> 0 bytes chat/img/autoscroll.png | Bin 4181 -> 0 bytes chat/img/broken-image.png | Bin 0 -> 1037 bytes chat/img/buttons-sprite.png | Bin 0 -> 8327 bytes chat/img/help.png | Bin 1359 -> 0 bytes chat/img/playback.png | Bin 961 -> 0 bytes chat/img/settings.png | Bin 1151 -> 0 bytes chat/img/users.png | Bin 1277 -> 0 bytes chat/index.php | 6 +- chat/js/FABridge.js | 1182 ++-- chat/js/chat.js | 754 +-- chat/js/config.js | 75 +- chat/js/lang/cy.js | 184 +- chat/js/lang/el.js | 182 +- chat/js/lang/it.js | 4 +- chat/js/lang/ka.js | 2 +- chat/js/lang/kr.js | 2 +- chat/js/lang/nl-be.js | 180 +- chat/js/lang/no.js | 182 +- chat/js/lang/pl.js | 182 +- chat/js/lang/sl.js | 2 +- chat/lib/class/AJAXChat.php | 6649 ++++++++++----------- chat/lib/class/AJAXChatDataBase.php | 2 +- chat/lib/class/AJAXChatHTTPHeader.php | 2 +- chat/lib/class/AJAXChatLanguage.php | 2 +- chat/lib/class/AJAXChatMySQLDataBase.php | 2 +- chat/lib/class/AJAXChatMySQLQuery.php | 2 +- chat/lib/class/AJAXChatMySQLiDataBase.php | 2 +- chat/lib/class/AJAXChatMySQLiQuery.php | 2 +- chat/lib/class/AJAXChatTemplate.php | 2 +- chat/lib/config.php | 6 +- chat/lib/lang/ar.php | 249 +- chat/lib/lang/bg.php | 5 +- chat/lib/lang/ca.php | 253 +- chat/lib/lang/cy.php | 251 +- chat/lib/lang/cz.php | 5 +- chat/lib/lang/da.php | 3 + chat/lib/lang/de.php | 5 +- chat/lib/lang/el.php | 5 +- chat/lib/lang/en.php | 5 +- chat/lib/lang/es.php | 249 +- chat/lib/lang/et.php | 5 +- chat/lib/lang/fa.php | 3 + chat/lib/lang/fi.php | 3 + chat/lib/lang/fr.php | 253 +- chat/lib/lang/gl.php | 5 +- chat/lib/lang/he.php | 5 +- chat/lib/lang/hr.php | 3 + chat/lib/lang/hu.php | 5 +- chat/lib/lang/in.php | 5 +- chat/lib/lang/it.php | 5 +- chat/lib/lang/ja.php | 5 +- chat/lib/lang/ka.php | 7 +- chat/lib/lang/kr.php | 7 +- chat/lib/lang/mk.php | 5 +- chat/lib/lang/nl-be.php | 251 +- chat/lib/lang/nl.php | 251 +- chat/lib/lang/no.php | 251 +- chat/lib/lang/pl.php | 251 +- chat/lib/lang/pt-br.php | 5 +- chat/lib/lang/pt-pt.php | 5 +- chat/lib/lang/ro.php | 5 +- chat/lib/lang/ru.php | 5 +- chat/lib/lang/sk.php | 5 +- chat/lib/lang/sl.php | 251 +- chat/lib/lang/sr.php | 5 +- chat/lib/lang/sv.php | 5 +- chat/lib/lang/th.php | 5 +- chat/lib/lang/tr.php | 5 +- chat/lib/lang/uk.php | 5 +- chat/lib/lang/zh-tw.php | 3 + chat/lib/lang/zh.php | 5 +- chat/lib/template/loggedIn.html | 639 +- chat/lib/template/loggedOut.html | 83 +- chat/lib/template/logs.html | 51 +- chat/readme.html | 800 +-- chat/sounds/sound_7.mp3 | Bin 0 -> 24241 bytes chat/sounds/sound_8.mp3 | Bin 0 -> 33436 bytes readme.md | 28 +- 105 files changed, 9276 insertions(+), 8844 deletions(-) create mode 100644 chat/css/Pine.css create mode 100644 chat/css/XenForo.css create mode 100644 chat/css/custom.css delete mode 100644 chat/css/ie5-6.css create mode 100644 chat/css/pine_images/chatlist.jpg delete mode 100644 chat/css/subSilver.css delete mode 100644 chat/css/subblack2.css delete mode 100644 chat/img/audio.png delete mode 100644 chat/img/autoscroll.png create mode 100644 chat/img/broken-image.png create mode 100644 chat/img/buttons-sprite.png delete mode 100644 chat/img/help.png delete mode 100644 chat/img/playback.png delete mode 100644 chat/img/settings.png delete mode 100644 chat/img/users.png create mode 100644 chat/sounds/sound_7.mp3 create mode 100644 chat/sounds/sound_8.mp3 diff --git a/chat/changelog.txt b/chat/changelog.txt index 733eb99..6d86137 100644 --- a/chat/changelog.txt +++ b/chat/changelog.txt @@ -843,4 +843,29 @@ Bugfixes: - Fix potential conflict between php and mysql timezones by using mysql's FROM_UNIXTIME(). - thanks to ManOnDaMoon. - Normalized sound volumes a bit. - Fixed mybb integration database connection. Connection details should be pulled automatically now. -- Fidex mybb integration guest logins to accept guests that don't enter a username (assign numbers like other versions). \ No newline at end of file +- Fidex mybb integration guest logins to accept guests that don't enter a username (assign numbers like other versions). + +Version 0.8.8 (?.?.2014) +------------------------------- +Notice: +- Templates, especially loggedIn.html have changed a lot to add mobile support. Javascript in the templates files has also changed. +- CSS for themes has slightly changed and you may need to update your custom stylesheets. +- The themes subSilver and subblack2 were removed. +- If you are using the javascript override handleCustomInfoMessage in custom.js, you should make it return true if you capture an event. + +New Features: +- Private messages now have their own sound - thanks to marquisite. +- Private messages have their own background color. +- Added two new sounds - one is extra for your customization pleasure. +- Added a custom user group and banned user group for customization and integration - thanks to marquisite. +- Added a debug mode to chat.js - thanks to Sophist-UK. +- New theme "Pine" added - thanks to Rosina Ramirez. + +Bugfixes: +- HTML is now stripped from [IMG] tag URLs, and tag parsing errors will no longer crash chat. - thanks to gWorldz. +- Nesting an [IMG] inside a [URL] tag will now only open the URL instead of also opening the image - thanks to James Almer. +- Users can now be kicked for 0 minutes, which is effectively a kick and not a ban - thanks to micheal-swiggs. +- User list sorting is now case insensitive (lists should be properly alphabetical) - thanks to marquisite. + +Misc: +- Removed unneeded call to mt_srand() - thanks to Joshua Embrey. diff --git a/chat/css/Cobalt.css b/chat/css/Cobalt.css index 08c4e36..d4e89e6 100644 --- a/chat/css/Cobalt.css +++ b/chat/css/Cobalt.css @@ -2,121 +2,114 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by PunBB style "Cobalt": * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#1a1a1a; + color:#ababab; + border: 0; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-color:#1D68E0; + color:#000; +} +#content select, #loginForm select, #loginForm input, #content textarea { + background-color:#383838; + color:#ababab; + border: 1px solid #565656; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#1a1a1a; - color:#ababab; - border: 0; - } - #content select, #loginForm select, #loginForm input, #content textarea { - background-color:#383838; - color:#ababab; - border: 1px solid #565656; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#2A2A2A; - color:#D4D4D4; - } - #loginContent h1 { - color:#D4D4D4; - } - #loginContent a { - color:#60A0DC; - } - #loginContent #loginFormContainer #loginButton { - background-color:#424242; - color:#D4D4D4; - } - #loginContent #errorContainer { - color:red; - } - - #content { - background-color:#2A2A2A; - color:#D4D4D4; - } - #content h1 { - color:#D4D4D4; - } - #content a { - color:#60A0DC; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer { - border: 1px solid #565656; - background-color:#383838; - } - #content #bbCodeContainer, #content #emoticonsContainer { - background-color:#383838; - padding: 5px; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#565656; - } - #content .rowOdd { - background-color:#484848; - } - #content .guest { - color:gray; - } - #content .user { - color:#D4D4D4; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#60A0DC; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#60A0DC; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#383838; - color:#D4D4D4; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#2A2A2A; + color:#D4D4D4; +} +.ajax-chat h1 { + color:#D4D4D4; +} +.ajax-chat a { + color:#60A0DC; +} +#loginContent #loginButton { + background-color:#424242; + color:#D4D4D4; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer { + border: 1px solid #565656; + background-color:#383838; +} +.ajax-chat .popup { + background-color:#383838; + padding:5px; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#565656; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#484848; +} +#content #chatList .rowOdd.private { + background-color:#B83C1D; +} +#content #chatList .rowEven.private { + background-color:#C84A24; +} +#content .guest { + color:gray; +} +#content .user { + color:#D4D4D4; +} +#content .customUser { + color:#acc2d7; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#60A0DC; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#60A0DC; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#383838; + color:#D4D4D4; } \ No newline at end of file diff --git a/chat/css/Core.css b/chat/css/Core.css index 104fb1b..06de2ac 100644 --- a/chat/css/Core.css +++ b/chat/css/Core.css @@ -2,114 +2,116 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by Simple Machines Forum style "SMF Default Theme - Core": * http://www.simplemachines.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); -@media screen,projection,handheld { +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#CDE7FF; + color:#333333; + border: 1px solid #787878; +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #787878; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#CDE7FF; - color:#333333; - border: 1px solid #787878; - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #787878; - } +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - #loginContent { - background-color:#E5E5E8; - color:#000; - } - #loginContent h1 { - color:#000; - } - #loginContent a { - color:#000; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#E5E5E8; - color:#000; - } - #content h1 { - color:#000; - } - #content a { - color:#000; - } - #content input, #content select, #content textarea { - background-color:#FFF; - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content #emoticonsContainer { - border-color:#ADADAD; +/* Other Theme Elements */ +.ajax-chat { + background-color:#E5E5E8; + color:#000; +} +.ajax-chat h1 { + color:#000; +} +.ajax-chat a { + color:#000; +} +#loginContent #errorContainer { + color:red; +} +#content input, #content select, #content textarea { + background-color:#FFF; + color:#000; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + border-color:#ADADAD; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#ADADAD; + border:1px solid gray; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#ECEDF3; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#F6F6F6; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#003d8e; +} +#content .moderator { + color:#0000FF; +} +#content .admin { + color:#FF0000; +} +#content .chatBot { + color:#476C8E; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#476C8E; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#88A6C0; + color:#FFF; +} + +@media (max-width: 700px) { + #content #emoticonsContainer { background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#ECEDF3; - } - #content .rowOdd { - background-color:#F6F6F6; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#0000FF; - } - #content .admin { - color:#FF0000; - } - #content .chatBot { - color:#476C8E; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#476C8E; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#88A6C0; - color:#FFF; + border: 1px solid #ADADAD; } } \ No newline at end of file diff --git a/chat/css/Lithium.css b/chat/css/Lithium.css index 8776158..07cf534 100644 --- a/chat/css/Lithium.css +++ b/chat/css/Lithium.css @@ -2,115 +2,112 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by PunBB style "Lithium": * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#6C8A3F; + color: #fff; + border:1px solid #6C8A3F; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-color:#5E7D2E; +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #6C8A3F; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#6C8A3F; - color: #fff; - border: 1px solid #6C8A3F; - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #6C8A3F; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#F1F1F1; - color:#333333; - } - #loginContent h1 { - color:#333333; - } - #loginContent a { - color:#638137; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#333333; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#F1F1F1; - color:#333333; - } - #content h1 { - color:#333333; - } - #content a { - color:#638137; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:#6C8A3F; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#F1F1F1; - } - #content .rowOdd { - background-color:#DEDFDF; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#638137; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#638137; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#6C8A3F; - color:#FFF; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#F1F1F1; + color:#333; +} +.ajax-chat h1 { + color:#333333; +} +.ajax-chat a { + color:#638137; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#333333; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:#6C8A3F; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#FFF; + border:1px solid #6C8A3F; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#F1F1F1; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#DEDFDF; +} +#content #chatList .rowOdd.private { + background-color:#84CF86; +} +#content #chatList .rowEven.private { + background-color:#9FD598; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#406021; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#638137; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#638137; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#6C8A3F; + color:#FFF; } \ No newline at end of file diff --git a/chat/css/Mercury.css b/chat/css/Mercury.css index f7e12d5..1fe0530 100644 --- a/chat/css/Mercury.css +++ b/chat/css/Mercury.css @@ -2,153 +2,147 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by PunBB style "Mercury": * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); -@media screen,projection,handheld { +/* Buttons */ +#content input, #content select, #content textarea { + border: 0; +} +#content textarea { + border-color: #383838; +} +#content input { + border-radius: 5px; +} - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - #content input, #content select, #content textarea { - border: 1px solid #565656; - } - #content textarea { - border-color: #383838; - } - #content input { - border-radius: 3px; - } - #loginContent { - background-color:#2A2A2A; - color:#D4D4D4; - } - #loginContent h1 { - color:#D4D4D4; - } - #loginContent a { - color:#F6B620; - } - #loginContent input, #loginContent select { - background-color:#424242; - border-color:#565656; - color:#D4D4D4; - } - #loginContent #loginFormContainer #loginButton { - background-color:#424242; - color:#D4D4D4; - border-radius: 3px; - } - #loginContent #errorContainer { - color:red; - } - - #content { - background-color:#2A2A2A; - color:#D4D4D4; - } - #content h1 { - color:#D4D4D4; - } - #content a { - color:#F6B620; - } - #content input, #content select, #content textarea { - background-color:#383838; - color:#D4D4D4; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content #emoticonsContainer { - border: 0; - background-color:#383838; - } - #content #colorCodesContainer { - padding: 5px; - box-shadow: 2px 2px 4px #000; - border-radius: 3px; - } - #content #onlineListContainer { - background: #383838; - } - #content #onlineListContainer #onlineList div { - margin: 0 1px 1px 1px; - border-radius: 5px; - background: #404040; - } - #content #onlineListContainer #onlineList ul { - margin-top: 1px; - list-style: none; - } - #content #emoticonsContainer { - border-radius: 3px; - } - #content #bbCodeContainer { - border: 0; padding-left: 0; - } - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton { - background-color:#383838; - color:#D4D4D4; - } - #content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover { - background-color:#565656; - } - #content #optionsContainer input.button { - border: 0; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#505050; - } - #content .rowOdd { - background-color:#484848; - } - #content .guest { - color:gray; - } - #content .user { - color:#D4D4D4; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#F6B620; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#F6B620; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - color:#D4D4D4; - height: 15px; - } -} \ No newline at end of file +/* Other Theme Elements */ +.ajax-chat { + background-color:#2A2A2A; + color:#D4D4D4; +} +.ajax-chat h1 { + color:#D4D4D4; +} +.ajax-chat a { + color:#F6B620; +} +#loginContent input, #loginContent select { + background-color:#424242; + border-color:#565656; + color:#D4D4D4; +} +#loginContent #loginButton { + background-color:#424242; + color:#D4D4D4; + border-radius: 3px; +} +#loginContent #errorContainer { + color:red; +} +#content input, #content select, #content textarea { + background-color:#383838; + color:#D4D4D4; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + border:0; + background-color:#383838; +} +.ajax-chat .popup { + padding:5px; + box-shadow:2px 2px 4px #000; + border-radius:3px; + background-color:#424242; + border:1px solid #333; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #onlineListContainer { + background: #383838; +} +#content #onlineListContainer #onlineList div { + margin: 0 1px 1px 1px; + border-radius: 5px; + background: #404040; +} +#content #onlineListContainer #onlineList ul { + margin-top: 1px; + list-style: none; +} +#content #bbCodeContainer { + border: 0; padding-left: 0; +} +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton { + background-color:#383838; + color:#D4D4D4; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover { + background-color:#565656; +} +#content #optionsContainer input.button { + border: 0; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#505050; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#484848; +} +#content #chatList .rowOdd.private { + background-color:#101010; +} +#content #chatList .rowEven.private { + background-color:#1f1f1f; +} +#content .guest { + color:gray; +} +#content .user { + color:#D4D4D4; +} +#content .customUser { + color:#e0ca95; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#F6B620; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#F6B620; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + color:#D4D4D4; + height: 15px; +} diff --git a/chat/css/MyBB.css b/chat/css/MyBB.css index 9daa19d..e71f624 100644 --- a/chat/css/MyBB.css +++ b/chat/css/MyBB.css @@ -2,114 +2,108 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by MyBB style "MyBB Default": - * http://www.mybboard.net/ + * http://www.mybb.com/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#02619f; + color:#fff; + font-weight: bold; + border: 0px solid #02619f; + border-radius: 5px; +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #02619f; + border-radius: 5px; +} -@media screen,projection,handheld { - - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#02619f; - color:#fff; - font-weight: bold; - border: 0px solid #02619f; - border-radius: 5px; - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #02619f; - border-radius: 5px; - } +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - #loginContent { - background-color:#FFF; - color:#000; - } - #loginContent h1 { - color:#000; - } - #loginContent a { - color:#000; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#FFF; - color:#000; - } - #content h1 { - color:#000; - } - #content a { - color:#000; - } - #content input, #content select, #content textarea { - background-color:#FFF; - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content #emoticonsContainer { - border-color:#ADADAD; - background-color:#E5E5E8; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven, #content .rowOdd { - background-color:#EFEFEF; - border-bottom: 1px solid #bdccf7; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#0000FF; - } - #content .admin { - color:#FF0000; - } - #content .chatBot { - color:#476C8E; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#476C8E; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#02619f; - color:#FFF; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#FFF; + color:#000; +} +.ajax-chat h1 { + color:#000; +} +.ajax-chat a { + color:#000; +} +#loginContent #errorContainer { + color:red; +} +#content input, #content select, #content textarea { + background-color:#FFF; + color:#000; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer { + border-color:#ADADAD; + background-color:#E5E5E8; +} +.ajax-chat .popup { + border:1px solid #ADADAD; + background-color:#E5E5E8; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #content .rowOdd { + background-color:#EFEFEF; + border-bottom: 1px solid #bdccf7; +} +#content #chatList .private { + background-color:#F8D0D0; + border-bottom:1px solid #ED3950; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#02619f; +} +#content .moderator { + color:#0000FF; +} +#content .admin { + color:#FF0000; +} +#content .chatBot { + color:#476C8E; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#476C8E; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#02619f; + color:#FFF; } \ No newline at end of file diff --git a/chat/css/Oxygen.css b/chat/css/Oxygen.css index 9163174..0009723 100644 --- a/chat/css/Oxygen.css +++ b/chat/css/Oxygen.css @@ -2,115 +2,114 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by PunBB style "Oxygen": * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#0066B9; + background-image: linear-gradient(to bottom, #4795CC 0px, #2A6AB8 100%); + color: #fff; + border: 1px solid #0066B9; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-image:linear-gradient(to top, #4795CC 0px, #2A6AB8 100%); +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #0066B9; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#0066B9; - color: #fff; - border: 1px solid #0066B9; - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #0066B9; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#F1F1F1; - color:#333333; - } - #loginContent h1 { - color:#333333; - } - #loginContent a { - color:#0066B9; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#333333; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#F1F1F1; - color:#333333; - } - #content h1 { - color:#333333; - } - #content a { - color:#0066B9; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:#0066B9; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#F1F1F1; - } - #content .rowOdd { - background-color:#DEDFDF; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#0066B9; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#0066B9; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#0066B9; - color:#FFF; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#F1F1F1; + color:#333; +} +.ajax-chat h1 { + color:#333333; +} +.ajax-chat a { + color:#0066B9; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#333333; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:#0066B9; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#FFF; + border:1px solid #0066B9; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#F1F1F1; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#E6E7E7; +} +#content #chatList .rowOdd.private { + background-color:#BCC5FF; +} +#content #chatList .rowEven.private { + background-color:#C7D1FC; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#003366; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#0066B9; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#0066B9; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#0066B9; + background-image: linear-gradient(to bottom, #2A6AB8 0px, #4795CC 100%); + color:#FFF; } \ No newline at end of file diff --git a/chat/css/Pine.css b/chat/css/Pine.css new file mode 100644 index 0000000..8d831f3 --- /dev/null +++ b/chat/css/Pine.css @@ -0,0 +1,142 @@ +/* + * @package AJAX_Chat + * @author Rosina Ramirez + */ +@import url('global.css'); +@import url('fonts.css'); +@import url('print.css'); +@import url('custom.css'); + +#content input, select, #content textarea, #loginButton { + border: 0; +} +#loginButton{ + box-shadow:0px 1px 4px 0px rgba(0,0,0,0.5); +} +#content textarea { + border-color: #383838; +} +.ajax-chat { + background-color:#0f2314; + color:#f0f0f0; +} +.ajax-chat a, .ajax-chat a:visited, .ajax-chat h1{ + color:#C5EBB7; +} +input, select { + background:#0A140C; + border: 1px solid rgba(0,0,0,1); + color:#C5EBB7; +} +#loginContent #errorContainer { + color:#FF6262; +} + +#content textarea { + background:rgba(0,0,0,0.5); + color:#C5EBB7; +} +#content #chatList{ + background: url('pine_images/chatlist.jpg') no-repeat bottom right #0a180d; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer{ + box-shadow: inset 1px 1px 10px rgba(0,0,0,0.6); + border:0 +} +#content #colorCodesContainer a:first-child{ + border-left: 1px solid #000; +} +#content #colorCodesContainer a { + border-color: #000; + border-left: 0; +} +#content #colorCodesContainer { + background: #000; + background: rgba(0,0,0,0.4); + border: 0; +} +#content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + background: rgba(0,0,0,0.3) +} +#content #onlineListContainer #onlineList ul { + list-style: none; +} +#content #emoticonsContainer { + border-radius: 3px; +} +#content #bbCodeContainer { + border: 0; + padding-left: 0; +} + +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} + +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginButton { + background-color:#4C9C1F; + color:#fff; + padding:6px 12px +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginButton:hover { + background-color:#57B324; +} +#content #optionsContainer input.button { + border: 0; +} +#content #optionsContainer input { + background-color:transparent; +} +.ajax-chat .popup { + background-color:#F7F5DC; + border: 1px solid #808080; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background:#2C4E3D; + background:rgba(44, 78, 61, 0.6) +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background:#416453; + background:rgba(65, 100, 83, 0.6) +} +#content #chatList .rowOdd.private { + background-color:#00701C; +} +#content #chatList .rowEven.private { + background-color:#007B07; +} +#content .guest { + color:#B8B8B8; +} +#content .user { + color:#C8E4CF; +} +#content .customUser { + color:#4c9c1f; +} +#content .moderator { + color:#71E271; +} +#content .admin { + color:#FF6262; +} +#content .chatBot { + color:#E7B98E; +} +#content #chatList .chatBotErrorMessage { + color:#FF6262; +} +#content #chatList .deleteSelected { + border-color:#FF6262; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + color:#C5EBB7; + height: 15px; +} \ No newline at end of file diff --git a/chat/css/Plum.css b/chat/css/Plum.css index a1aec9f..f79d446 100644 --- a/chat/css/Plum.css +++ b/chat/css/Plum.css @@ -1,112 +1,134 @@ /* * @package AJAX_Chat * @author Rosina Ramirez - * @copyright (c) Rosina Ramirez - * @license Modified MIT License - * @link https://blueimp.net/ajax/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); -@media screen,projection,handheld { +.ajax-chat { + background-color:#2A112F; + color:#9765A0; +} +.ajax-chat a { + color:#DA83A1; +} +.ajax-chat h1 { + color:#CDA6D2; +} +#content input, select, #content textarea, #loginButton { + border: 0; box-shadow:1px 1px 4px 0px rgba(0,0,0,0.5); +} +#content textarea { + border-color:#383838; +} +#content input, #loginButton { + border-radius:8px; +} +#content input, #loginContent input, #content select, #loginContent select { + background:#17081a; + border:1px solid rgba(0,0,0,1); + color:#9765A0; +} +#loginContent #errorContainer { + color:red; +} +#content textarea { + background:rgba(0,0,0,0.3); + color:#9765A0; +} +#content #chatList{ + background: url('plum_images/plum.png') no-repeat bottom right rgba(0,0,0,0.3); +} +.ajax-chat #content .popup { + padding: 5px; + box-shadow: 2px 2px 4px #000; + border-radius: 3px; + background:rgba(225,225,225,0.2); + border-color:#9765A0; +} +#content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + background: url('plum_images/plum2.png') no-repeat bottom left rgba(0,0,0,0.3); +} +#content #onlineListContainer #onlineList ul { + list-style: none; +} +#content #emoticonsContainer { + border-radius:3px; +} +#content #bbCodeContainer { + border:0; + padding-left:0; +} - #content input, select, #content textarea, #loginButton { - border: 0; box-shadow:1px 1px 4px 0px rgba(0,0,0,0.5); - } - #content textarea { border-color: #383838; } - #content input, #loginButton { border-radius: 8px; } - #loginContent, #content { - background-color:#2A112F; - color:#9765A0; - } - a { - color:#DA83A1; - } - input, select { - background:#17081a; - border: 1px solid rgba(0,0,0,1); - color:#9765A0; - } - #loginContent #errorContainer { - color:red; - } - h1 { - color:#CDA6D2; - } - - #content textarea { - background:rgba(0,0,0,0.3); - color:#9765A0; - } - #content #chatList{ - background: url('plum_images/plum.png') no-repeat bottom right rgba(0,0,0,0.3); - } - #content #colorCodesContainer { - padding: 5px; - box-shadow: 2px 2px 4px #000; - border-radius: 3px; - background:rgba(225,225,225,0.2) - } +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} + +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginButton { + background-color:#461124; + color:#DAABBC; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginButton:hover { + background-color:#591E33; +} +#content #optionsContainer input.button { + border: 0; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background:rgba(0,0,0,0.2); +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background:rgba(0,0,0,0.3); +} +#content #chatList .rowOdd.private { + background-color:#700030; +} +#content #chatList .rowEven.private { + background-color:#7B0039; +} +#content .guest { + color:#CD9595; +} +#content .user { + color:#CDA6D2; +} +#content .customUser { + color:#da83a1; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#CDA6D2; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + color:#CDA6D2; + height: 15px; +} + +@media (max-width: 480px) { #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { - background: url('plum_images/plum2.png') no-repeat bottom left rgba(0,0,0,0.3); - } - #content #onlineListContainer #onlineList ul { - list-style: none; - } - #content #emoticonsContainer { border-radius: 3px; } - #content #bbCodeContainer { border: 0; padding-left: 0; } - #content #statusIconContainer { background-image: url('../img/loading-sprite.png'); } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginButton { - background-color:#461124; - color:#DAABBC; - } - #content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginButton:hover { - background-color:#591E33; - } - #content #optionsContainer input.button { border: 0; } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background:rgba(0,0,0,0.2); - } - #content .rowOdd { - background:rgba(0,0,0,0.3); - } - #content .guest { - color:gray; - } - #content .user { - color:#CDA6D2; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#CDA6D2; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - color:#CDA6D2; - height: 15px; + background:#2A112F; } } \ No newline at end of file diff --git a/chat/css/Sulfur.css b/chat/css/Sulfur.css index f7d721c..d0ed944 100644 --- a/chat/css/Sulfur.css +++ b/chat/css/Sulfur.css @@ -2,115 +2,112 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by PunBB style "Sulfur": * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#B84623; + color: #fff; + border: 1px solid #B84623; +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-color:#9A2806; +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #B84623; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#B84623; - color: #fff; - border: 1px solid #B84623; - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #B84623; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#F1F1F1; - color:#333333; - } - #loginContent h1 { - color:#333333; - } - #loginContent a { - color:#B84623; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#333333; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#F1F1F1; - color:#333333; - } - #content h1 { - color:#333333; - } - #content a { - color:#B84623; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:#B84623; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#F1F1F1; - } - #content .rowOdd { - background-color:#DEDFDF; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#B84623; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#B84623; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#B84623; - color:#FFF; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#F1F1F1; + color:#333333; +} +.ajax-chat h1 { + color:#333; +} +.ajax-chat a { + color:#B84623; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#333; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:#B84623; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#FFF; + border:1px solid #B84623; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#F1F1F1; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#DEDFDF; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#602010; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#B84623; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#B84623; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#B84623; + color:#FFF; } \ No newline at end of file diff --git a/chat/css/Uranium.css b/chat/css/Uranium.css index 7ff9b64..b8ac92f 100644 --- a/chat/css/Uranium.css +++ b/chat/css/Uranium.css @@ -1,178 +1,219 @@ /* * @package AJAX_Chat * @author Rosina Ramirez - * @copyright (c) Rosina Ramirez - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - * */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); +html { + height: 100%; +} +input, select, textarea, #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3, #content #inputFieldContainer, #loginContent input { + border-radius:5px; + -webkit-border-radius:5px; + border:0; +} +#content #inputFieldContainer{ + background:#0E0E0E; + padding:0; +} +#content #inputFieldContainer #inputField{ + box-shadow: inset 1px 1px 5px 1px #000; + border:0; + padding:3px 0.5%; + width: 99%; +} +#content #inputFieldContainer #inputField:focus{ + outline:none; + box-shadow:0px 0px 8px 1px #376e34; +} +#loginContent #loginButton { + background-color:#424242; + color:#b0b8a8; + border-radius: 3px; +} +#loginContent #errorContainer { + color:red; +} -@media screen,projection,handheld { - - input, select, textarea, #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content .rowEven, - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3, #content #inputFieldContainer, #loginContent input - { border-radius: 5px; -webkit-border-radius:5px;border:0;} - #loginContent a { - color:#4c9546; - } - #content #inputFieldContainer{height:46px; background:#0E0E0E;padding:0;} - #content #inputFieldContainer #inputField{box-shadow: inset 1px 1px 5px 1px #000; border:0;height: 40px;padding: 3px 0.5%;width: 99%;} - #content #inputFieldContainer #inputField:focus{outline:none;box-shadow:0px 0px 8px 1px #376e34;} - #loginContent #loginFormContainer #loginButton { - background-color:#424242; - color:#b0b8a8; - border-radius: 3px; - } - #loginContent #errorContainer { - color:red; - } - - #content, #loginContent { +.ajax-chat { + height: 100%; background-color: #464646; - background-image: -webkit-gradient(linear, left top, left bottom, from(#464646), to(#181818)); background-image: -webkit-linear-gradient(top, #464646, #181818); background-image: -moz-linear-gradient(top, #464646, #181818); background-image: -o-linear-gradient(top, #464646, #181818); background-image: linear-gradient(to bottom, #464646, #181818); color:#b0b8a8; - } - h1, h3 { - color:#e2e9db; - text-shadow: 1px 1px 2px #191919; - } - #content a { - color:#4c9546; - } - #loginContent input, #loginContent select{background:#171717; color:#b0b8a8;} - input, select{padding: 3px;} - #content input,#content select,#content textarea { - background-color:#0e0e0e; - color:#b0b8a8; - } - #content #colorCodesContainer,#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #inputFieldContainer, - #loginContent input[type=text], #loginContent input[type=password]{ - box-shadow: 0px 0px 8px 1px #495a49; -webkit-box-shadow: 0px 0px 8px 1px #495a49; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { - background-color:#171717; - border:0; - } - #content #chatList:after, #content #chatList:before{ - content:''; - display:block; - position:absolute; - border-radius: 5px; - } - #content #chatList:before{top:17px;left:0px;width:0px;height:98%;box-shadow: 1px 0px 8px 1px #000;} - #content #chatList:after{top:0px;left:17px;width:98%;height:0px;box-shadow: 0px 1px 8px 1px #000;} - - #content #onlineListContainer #onlineList div { - margin: 0 1px 1px 1px; - background: none; - } - #content #onlineListContainer #onlineList ul { - margin-top: 1px; - list-style: none; - } - - #content #helplist table, #content #settingsList table{border-spacing:0;} - #content #emoticonsContainer { border-radius: 3px; } - #content #bbCodeContainer { border: 0; padding-left: 0; } - #content #statusIconContainer { background-image: url('../img/loading-sprite.png'); } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - #content #bbCodeContainer input { - background-color: #d8ffd6; - background-image: -webkit-gradient(linear, left top, left bottom, from(#d8ffd6), to(#467a44)); - background-image: -webkit-linear-gradient(top, #d8ffd6, #467a44); - background-image: -moz-linear-gradient(top, #d8ffd6, #467a44); - background-image: -o-linear-gradient(top, #d8ffd6, #467a44); - background-image: linear-gradient(to bottom, #d8ffd6, #467a44); - color:#1d1d1d; - } - #content #bbCodeContainer input:hover{ - background-color: #ffffff; - background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#08ff35)); - background-image: -webkit-linear-gradient(top, #ffffff, #08ff35); - background-image: -moz-linear-gradient(top, #ffffff, #08ff35); - background-image: -o-linear-gradient(top, #ffffff, #08ff35); - background-image: linear-gradient(to bottom, #ffffff, #08ff35); - } - #content #bbCodeContainer input:active, #content #logoutButton:active, #content #submitButton:active, #loginContent #loginButton:active{box-shadow:0px 0px 8px 1px #38ff56;} - #content #logoutButton, #content #submitButton,#loginContent #loginButton{ - background-color: #4fff58; - background-image: -webkit-gradient(linear, left top, left bottom, from(#4fff58), to(#194221)); - background-image: -webkit-linear-gradient(top, #4fff58, #194221); - background-image: -moz-linear-gradient(top, #4fff58, #194221); - background-image: -o-linear-gradient(top, #4fff58, #194221); - background-image: linear-gradient(to bottom, #4fff58, #194221); - font-weight:bold; color:#fff; - text-shadow:0px 0px 5px #000; - } - #content #logoutButton:hover, #content #submitButton:hover, #loginContent #loginButton:hover{ - background-color: #99ffa8; - background-image: -webkit-gradient(linear, left top, left bottom, from(#99ffa8), to(#002405)); - background-image: -webkit-linear-gradient(top, #99ffa8, #002405); - background-image: -moz-linear-gradient(top, #99ffa8, #002405); - background-image: -o-linear-gradient(top, #99ffa8, #002405); - background-image: linear-gradient(to bottom, #99ffa8, #002405); - } +} +.ajax-chat h1, .ajax-chat h3 { + color:#e2e9db; + text-shadow: 1px 1px 2px #191919; +} +.ajax-chat a { + color:#4c9546; +} +.ajax-chat input, .ajax-chat select{ + padding: 3px; +} +#loginContent input, #loginContent select { + background:#171717; + color:#b0b8a8; +} +#content input,#content select,#content textarea { + background-color:#0e0e0e; + color:#b0b8a8; +} +.ajax-chat .popup, #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, +#content #inputFieldContainer, #loginContent input[type=text], #loginContent input[type=password] { + box-shadow: 0px 0px 8px 1px #495a49; + -webkit-box-shadow: 0px 0px 8px 1px #495a49; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + background-color:#171717; + border:0; +} +#content #chatList:after, #content #chatList:before{ + content:''; + display:block; + position:absolute; + border-radius: 5px; +} +#content #chatList:before{ + top:17px; + left:0px; + width:0px; + height:98%; + box-shadow: 1px 0px 8px 1px #000; +} +#content #chatList:after{ + top:0px; + left:17px; + width:98%; + height:0px; + box-shadow: 0px 1px 8px 1px #000; +} + +#content #onlineListContainer #onlineList div { + margin: 0 1px 1px 1px; + background: none; +} +#content #onlineListContainer #onlineList ul { + margin-top: 1px; + list-style: none; +} - #content #colorCodesContainer{ - border:0; - background:rgba(0,0,0,0.7); - padding:7px; - } - #content #colorCodesContainer a{border-radius:10px; box-shadow:0px 0px 3px 1px rgba(255,255,255,0.3); margin:0 5px;border:0;} - #content #optionsContainer input.button { border: 0; padding: 0; margin-right: 5px;} - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#131413; - } - #content .guest { - color:gray; - } - #content .user { - color:#b0b8a8; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#4c9546; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#4c9546; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { +#content #helplist table, #content #settingsList table { + border-spacing:0; +} +#content #emoticonsContainer { + border-radius: 3px; +} +#content #bbCodeContainer { + border: 0; + padding-left: 0; +} + +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} + +#content #bbCodeContainer input { + background-color: #d8ffd6; + background-image: -webkit-linear-gradient(top, #d8ffd6, #467a44); + background-image: -moz-linear-gradient(top, #d8ffd6, #467a44); + background-image: -o-linear-gradient(top, #d8ffd6, #467a44); + background-image: linear-gradient(to bottom, #d8ffd6, #467a44); + color:#1d1d1d; +} +#content #bbCodeContainer input:hover{ + background-color: #ffffff; + background-image: -webkit-linear-gradient(top, #ffffff, #08ff35); + background-image: -moz-linear-gradient(top, #ffffff, #08ff35); + background-image: -o-linear-gradient(top, #ffffff, #08ff35); + background-image: linear-gradient(to bottom, #ffffff, #08ff35); +} +#content #bbCodeContainer input:active, #content #logoutButton:active, #content #submitButton:active, #loginContent #loginButton:active{ + box-shadow:0px 0px 8px 1px #38ff56; +} +#content #logoutButton, #content #submitButton,#loginContent #loginButton{ + background-color: #4fff58; + background-image: -webkit-linear-gradient(top, #4fff58, #194221); + background-image: -moz-linear-gradient(top, #4fff58, #194221); + background-image: -o-linear-gradient(top, #4fff58, #194221); + background-image: linear-gradient(to bottom, #4fff58, #194221); + font-weight:bold; color:#fff; + text-shadow:0px 0px 5px #000; +} +#content #logoutButton:hover, #content #submitButton:hover, #loginContent #loginButton:hover{ + background-color: #99ffa8; + background-image: -webkit-linear-gradient(top, #99ffa8, #002405); + background-image: -moz-linear-gradient(top, #99ffa8, #002405); + background-image: -o-linear-gradient(top, #99ffa8, #002405); + background-image: linear-gradient(to bottom, #99ffa8, #002405); +} + +.ajax-chat .popup, .ajax-chat #content .popup#colorCodesContainer { + border:0; + background:rgba(0,0,0,0.7); + padding:5px; +} +#content #colorCodesContainer a{ + border-radius:10px; + box-shadow:0px 0px 3px 1px rgba(255,255,255,0.3); + margin:5px; + border:0; +} +#content #optionsContainer input.button { border: 0; padding: 0; margin-right: 5px;} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#131413; +} +#content #chatList .rowOdd.private, #content #chatList .rowEven.private { + background-color: #0C3A00; + background-image: linear-gradient(to bottom, #1C5417, #05410E); +} +#content .guest { + color:gray; +} +#content .user { + color:#b0b8a8; +} +#content .customUser { + color:#4efb57; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#4c9546; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#4c9546; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { background-color: #171717; - background-image: -webkit-gradient(linear, left top, left bottom, from(#3b6c37), to(#171717)); background-image: -webkit-linear-gradient(top, #3b6c37, #223220, #171717); - background-image: -moz-linear-gradient(top, #3b6c37, #223220, #171717); - background-image: -o-linear-gradient(top, #3b6c37, #223220, #171717); - background-image: linear-gradient(to bottom, #3b6c37, #223220, #171717); - } - + background-image: -moz-linear-gradient(top, #3b6c37, #223220, #171717); + background-image: -o-linear-gradient(top, #3b6c37, #223220, #171717); + background-image: linear-gradient(to bottom, #3b6c37, #223220, #171717); } \ No newline at end of file diff --git a/chat/css/XenForo.css b/chat/css/XenForo.css new file mode 100644 index 0000000..db1a3d0 --- /dev/null +++ b/chat/css/XenForo.css @@ -0,0 +1,238 @@ +/* + * @package AJAX_Chat + * @author ManOnDaMoon + */ +@import url('global.css'); +@import url('fonts.css'); +@import url('print.css'); +@import url('custom.css'); + +/* Main Buttons */ +#content #logoutButton,#content #submitButton,#loginForm #loginButton { + font: 12pt Calibri, 'Trebuchet MS', Verdana, Geneva, Arial, Helvetica, sans-serif; + color: white; + font-weight: bold; + background: #e68c17 url('../../styles/default/xenforo/gradients/form-button-white-25px.png') repeat-x center -7px; + border: 3px solid White; + border-radius: 8px; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -khtml-border-radius: 8px; + text-align: center; + box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); + -khtml-box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); + display: inline-block; + cursor: pointer; + height: 33px; + background-color: #e68c17; + padding: 0 10px 0 10px; +} +#content #logoutButton:hover,#content #submitButton:hover,#loginForm #loginButton:hover { + box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); + -khtml-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); + position: relative; + top: 2px; +} + +/* BBCode Buttons */ +#content #bbCodeContainer input { + font-style: normal; + font-size: 12px; + font-family: Calibri, 'Trebuchet MS', Verdana, Geneva, Arial, Helvetica, sans-serif; + color: rgb(0, 0, 0); + background: rgb(220, 220, 235) url('../../styles/default/xenforo/gradients/form-button-white-25px.png') repeat-x top; + padding: 0px 6px; + border: 1px solid rgb(221, 221, 235); + border-top-color: rgb(255, 255, 255); + border-bottom-color: rgb(179, 179, 189); + border-radius: 7px; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + -khtml-border-radius: 7px; + text-align: center; + box-shadow: 0px 1px 4px 0px rgb(200, 200, 210); + -webkit-box-shadow: 0px 1px 4px 0px rgb(200, 200, 210); + -moz-box-shadow: 0px 1px 4px 0px rgb(200, 200, 210); + -khtml-box-shadow: 0px 1px 4px 0px rgb(200, 200, 210); + text-shadow: 0 0 0 transparent, 0px -1px 2px white; + outline: none; + line-height: 23px; + display: inline-block; + cursor: pointer; + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + height: 23px; +} +#content #bbCodeContainer input:hover { + color: black; + text-decoration: none; + background-color: rgb(255, 255, 200); + border-color: rgb(255, 255, 200); + border-top-color: white; + border-bottom-color: rgb(190, 190, 170); +} +#content textarea { + font-size: 13px; + font-family: Calibri, 'Trebuchet MS', Verdana, Geneva, Arial, Helvetica, sans-serif; + color: #000000; + background-color: rgb(240, 247, 252); + border-width: 1px; + border-style: solid; + border-top-color: rgb(192, 192, 192); + border-right-color: rgb(233, 233, 233); + border-bottom-color: rgb(233, 233, 233); + border-left-color: rgb(192, 192, 192); + border-radius: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -khtml-border-radius: 4px; + outline: 0; +} +#content textarea:focus { + background: rgb(255, 255, 240) url('../../styles/default/xenforo/gradients/form-element-focus-25.png') repeat-x; + border-top-color: rgb(150, 150, 150); + border-bottom-color: rgb(230, 230, 230); +} +#content select,#loginForm select,#loginForm input { + background-color: #F7F7FF; + color: #60A0DC; + border: 1px solid #a5cae4; +} +#content select:focus,#loginForm select:focus,#loginForm input:focus { + background: rgb(255, 255, 240) url('../../styles/default/xenforo/gradients/form-element-focus-25.png') repeat-x; + border-top-color: rgb(150, 150, 150); + border-bottom-color: rgb(230, 230, 230); +} + +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} + +/* Other Theme Elements */ +.ajax-chat { + background-color: #176093; + color: #F7F7FF; +} +.ajax-chat h1, .ajax-chat a { + color: #60A0DC; +} +#loginContent #errorContainer { + color: red; +} +#content { + background-color: #F7F7FF; + color: #176093; + font-size: 12px; +} +#content #headline { + color:#F7F7FF; + background:#176093; +} +#content #copyright { + color: #F7F7FF; +} +#content #copyright { + font-style: italic; + font-size: 0.8em; +} +#content #chatList,#content #colorCodesContainer { + background-color: rgb(240, 247, 252); + border: 1px solid #a5cae4; + border-radius: 10px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + -khtml-border-radius: 10px; +} +#content #onlineListContainer,#content #helpContainer,#content #settingsContainer, #content #reportContainer { + background-color: rgb(240, 247, 252); + border: 1px solid #a5cae4; + border-radius: 10px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + -khtml-border-radius: 10px; +} +.ajax-chat .popup { + background-color:#FFF; + border: 1px solid #ababab; + box-shadow: 2px 2px 2px #777; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content #onlineListContainer #onlineList, #content #helpContainer #helpList, #content #settingsContainer #settingsList, #content #reportContainer #reportList { + padding-top: 5px; +} +#content #bbCodeContainer,#content #emoticonsContainer { + background-color: rgb(240, 247, 252); + padding: 5px; +} +#content #colorCodesContainer a { + border-color: #a5cae4; +} +#content #optionsContainer input { + background-color: transparent; +} +#content .rowEven { + background: #d7edfc url('../../styles/default/xenforo/gradients/category-23px-light.png') repeat-x top; +} +#content .rowOdd { + background-color: #F7F7FF; +} +#content .guest { + color: gray; +} +#content .user { + color: #176093; +} +#content .customUser { + color: #e68c17; +} +#content .moderator { + color: #00AA00; +} +#content .admin, #content .chatBotErrorMessage { + color: red; +} +#content .chatBot { + color: #60A0DC; +} +#content #chatList a { + color: #60A0DC; +} +#content #chatList .deleteSelected { + border-color: red; +} +#content #onlineListContainer h3,#content #helpContainer h3,#content #settingsContainer h3,#content #reportContainer h3 { + font-size: 11px; + background: #f9d9b0 url('../../styles/default/xenforo/gradients/category-23px-light.png') repeat-x top; + color: #6d3f03; + border-bottom: 1px solid #f9bc6d; +} +#content #chatList .report { + display:block; + float:right; + width:10px; + height:10px; + margin-top:2px; + margin-left:5px; + background:url('../img/report.gif') 0 0 no-repeat; +} +#content #chatList .report:hover { + background-position:0 -10px;; +} diff --git a/chat/css/beige.css b/chat/css/beige.css index 7c30bbe..ca99df3 100644 --- a/chat/css/beige.css +++ b/chat/css/beige.css @@ -2,113 +2,110 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#d9ce72; + color:#333333; + border:1px solid #c8b360; + background-image:linear-gradient(to bottom, #d9ce72, #e1d995); +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-image:linear-gradient(to bottom, #C1B022, #C8BD66); +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border:1px solid #c8b360; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background:url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#d9ce72; - color:#333333; - border: 1px solid #c8b360; - background-image: linear-gradient(to bottom, #d9ce72, #e1d995); - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #c8b360; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#F7F5DC; - color:#000; - } - #loginContent h1 { - color:#000; - } - #loginContent a { - color:#000; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#000; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#eee9be; - color:#000; - } - #content h1 { - color:#000; - } - #content a { - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:gray; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#FFFFF0; - } - #content .rowOdd { - background-color:#F7F5DC; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#FF6600; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#1E90FF; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#FFFFF0; - color:#000; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#F7F5DC; + color:#000; +} +.ajax-chat a { + color:#000; +} +.ajax-chat h1 { + color:#000; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#000; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:gray; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#F7F5DC; + border: 1px solid #808080; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#FFFFF0; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#F7F5DC; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#645a30; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#FF6600; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#1E90FF; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#FFFFF0; + color:#000; } \ No newline at end of file diff --git a/chat/css/black.css b/chat/css/black.css index 292b5d1..2420ec9 100644 --- a/chat/css/black.css +++ b/chat/css/black.css @@ -2,114 +2,115 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ + * + * Color palette inspired by PunBB style "Cobalt": + * http://punbb.org/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#000; + color:#f0f0f0; + border: 1px solid #808080; + background-image: linear-gradient(to bottom, #222, #000); +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-color:#222; + background-image: linear-gradient(to top, #222, #000); +} +#content select, #loginForm select, #loginForm input, #content textarea { + background-color:#000; + color:#fafafa; + border: 1px solid #808080; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#000; - color:#f0f0f0; - border: 1px solid #808080; - background-image: linear-gradient(to bottom, #222, #000); - } - #content select, #loginForm select, #loginForm input, #content textarea { - background-color:#000; - color:#fafafa; - border: 1px solid #808080; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#000; - color:#FFF; - } - #loginContent h1 { - color:#FFF; - } - #loginContent a { - color:#FFF; - } - #loginContent input, #loginContent select { - background-color:#212121; - color:#FFF; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#000; - color:#FFF; - } - #content h1 { - color:#FFF; - } - #content a { - color:#FFF; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:gray; - background-color:#000; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#212121; - } - #content .rowOdd { - background-color:#000; - } - #content .guest { - color:gray; - } - #content .user { - color:#FFF; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#FF6600; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#1E90FF; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#212121; - color:#FFF; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#000; + color:#FFF; +} +.ajax-chat a { + color:#FFF; +} +.ajax-chat h1 { + color:#FFF; +} +#loginContent input, #loginContent select { + background-color:#212121; + color:#FFF; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:gray; + background-color:#000; +} +.ajax-chat .popup { + background-color:#000; + border: 1px solid gray; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#212121; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#000; +} +#content #chatList .rowOdd.private { + background-color:#B83C1D; +} +#content #chatList .rowEven.private { + background-color:#C84A24; +} +#content .guest { + color:gray; +} +#content .user { + color:#FFF; +} +#content .customUser { + color:#ffcc33; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#FF6600; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#1E90FF; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#212121; + color:#FFF; } \ No newline at end of file diff --git a/chat/css/custom.css b/chat/css/custom.css new file mode 100644 index 0000000..63fdec0 --- /dev/null +++ b/chat/css/custom.css @@ -0,0 +1,17 @@ +/* Custom CSS - enter css overrides for all styles below */ + +/* e.g. to hide the logout button and the channel, style and language selectors, uncomment the following: + +#content #logoutChannelContainer { + display:none; +} +#content #mainPanelContainer { + top: 45px; +} +#content #copyright { + right: 60px; +} +#content #statusIconContainer { + top: 10px; +} +*/ \ No newline at end of file diff --git a/chat/css/fonts.css b/chat/css/fonts.css index e12f628..be935ca 100644 --- a/chat/css/fonts.css +++ b/chat/css/fonts.css @@ -1,12 +1,3 @@ -/* - * @package AJAX_Chat - * @author Sebastian Tschan - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - */ - -/* Fonts */ #loginContent { font-family:Verdana, Arial, Helvetica, sans-serif; font-size:0.8em; @@ -58,6 +49,9 @@ #content #chatList span.user { font-weight:bold; } +#content #chatList span.customUser { + font-weight:bold; +} #content #chatList span.moderator { font-weight:bold; } @@ -89,12 +83,9 @@ #content #onlineListContainer #onlineList div { font-size:0.9em; } -#content #helpContainer #helpList td { +#content #helpContainer #helpList, #content #settingsContainer #settingsList { font-size:0.9em; } -#content #helpContainer #helpList td.code { +#content #helpContainer #helpList dd { font-style:italic; -} -#content #settingsContainer #settingsList td { - font-size:0.9em; } \ No newline at end of file diff --git a/chat/css/global.css b/chat/css/global.css index eff916f..0495fad 100644 --- a/chat/css/global.css +++ b/chat/css/global.css @@ -8,25 +8,28 @@ */ /* Positioning */ -#loginContent { - position:absolute; - width:100%; - height:100%; +body.ajax-chat { + padding:0; + margin:0; } -#loginContent #loginHeadlineContainer { - margin: 100px 100px 0 100px; +#loginContent { + margin: 0 auto 0; + padding-top: 20px; + width:250px; } -#loginContent #loginFormContainer, #loginContent #errorContainer { - margin: 0 100px; +#loginContent #loginHeadline { + margin:0; + line-height:35px; } -#loginContent #loginFormContainer div { - margin-bottom:7px; +#loginContent #loginForm div { + margin:5px 0; } #loginContent #loginRegisteredUsers { padding-top:5px; } #loginContent #copyright { - margin: 20px 100px 0 100px; + margin:20px 0 0 0; + text-align:right; } #content { position:absolute; @@ -38,96 +41,135 @@ right:20px; top:20px; } -#content #headlineContainer { +#content #headline { position:absolute; - left:20px; - top:5px; + left:0px; + right:0px; + top:0px; + padding:0 0 0 20px; + line-height:45px; + margin:0; } #content #logoutChannelContainer { position:absolute; + z-index:2; left:20px; top:50px; + right:50px; } #content #logoutChannelContainer select{ - width: 105px; - height: 22px; + width:105px; + height:22px; } #content #statusIconContainer { position:absolute; right:20px; top:50px; - width: 22px; - height: 22px; + width:22px; + height:22px; } #content #chatList { + height:100%; + overflow:auto; +} +#content #mainPanelContainer { position:absolute; left:20px; - right:230px; + right:20px; top:85px; bottom:150px; +} +#content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + float:right; + height:100%; overflow:auto; + margin-left:10px; + position:relative; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + line-height:25px; + padding: 0 10px; + margin:0; + text-align:center; +} +#content #onlineListContainer { + width:200px; +} +#content #helpContainer, #content #settingsContainer { + width:360px; +} +#content #onlineListContainer #onlineList, #content #helpContainer #helpList, #content #settingsContainer #settingsList { + position:absolute; + left:0px; + right:0px; + top:25px; + bottom:0px; + overflow:auto; +} +#content #helpContainer #helpList dl, #content #settingsContainer #settingsList dl { + overflow:hidden; + padding:5px; + margin:0; +} +#content #helpContainer #helpList dt, #content #settingsContainer #settingsList dt { + float:left; + width:55%; + padding:0 2% 0 0; + margin:0; + clear:left; +} +#content #helpContainer #helpList dd, #content #settingsContainer #settingsList dd { + width:43%; + float:left; + margin:0; + padding:0; } #content #inputFieldContainer { position:absolute; left:20px; right:20px; bottom:95px; - padding-right:4px; + padding-right:2px; +} +#content #inputFieldContainer #inputField { + width:100%; + height:40px; + padding:0; } #content #submitButtonContainer { position:absolute; right:20px; bottom:60px; } -#content #onlineListContainer { - position:absolute; - right:20px; - top:85px; - width:200px; - bottom:150px; -} -#content #helpContainer { - position:absolute; - right:20px; - top:85px; - width:360px; - bottom:150px; -} -#content #settingsContainer { - position:absolute; - right:20px; - top:85px; - width:360px; - bottom:150px; -} #content #bbCodeContainer { position:absolute; left:20px; bottom:20px; padding:3px; } -#content #colorCodesContainer { +#content #bbCodeContainer input { + display:block; + float:left; + margin-right:2px; +} +#content #bbCodeContainer #bbCodeEmoticon { + display:none; +} +#content #colorCodesContainer, #content #emoticonsContainer { position:absolute; left:20px; bottom:55px; padding:3px; z-index:1; } -#content #emoticonsContainer { - position:absolute; - left:20px; - bottom:57px; - padding:3px; -} -#content #optionsContainer { - position:absolute; - right:20px; - bottom:20px; - padding:3px; - padding-right:0px; +#content #emoticonsContainer a { + margin-left:1px; + margin-right:1px; + z-index:1; } -#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginContent #loginButton { - padding: 4px 10px; +#content #emoticonsContainer img { + vertical-align:middle; + margin-bottom:2px; } #content #colorCodesContainer a { display:block; @@ -135,24 +177,22 @@ width:20px; height:20px; } +#content #optionsContainer { + position:absolute; + right:20px; + bottom:20px; + padding:3px 0 3px 3px; +} #content #optionsContainer input { vertical-align:middle; } -#content #optionsContainer input.button { - width:22px; - height:22px; -} -#content #emoticonsContainer a { - margin-left:1px; - margin-right:1px; -} -#content #emoticonsContainer img { - vertical-align:middle; - margin-bottom:2px; +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginContent #loginButton { + padding: 4px 10px; } -#content #headlineContainer h1 { - margin-left:auto; - margin-top:12px; +#content #logoutButton { + display:block; + float:left; + margin: 0 5px 5px 0; } #content #chatList div { padding: 2px 10px; @@ -178,24 +218,6 @@ padding-left:5px; background:url('../img/delete.png') no-repeat right; } -#content #inputFieldContainer #inputField { - width:100%; - height:40px; -} -#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - height:30px; - padding: 4px 10px; - margin:0px; - text-align:center; -} -#content #onlineListContainer #onlineList, #content #helpContainer #helpList, #content #settingsContainer #settingsList { - position:absolute; - left:0px; - right:0px; - top:25px; - bottom:0px; - overflow:auto; -} #content #onlineListContainer #onlineList div { padding: 2px 10px; } @@ -206,61 +228,56 @@ margin: 5px 0; padding-left:20px; } -#content #helpContainer #helpList td, #content #settingsContainer #settingsList td { - padding: 4px 10px; - vertical-align:top; -} -#content #settingsContainer #settingsList td { - vertical-align:middle; -} -#content #settingsContainer #settingsList td.setting { - width:115px; -} -#content #settingsContainer #settingsList input.text { - width:100px; -} #content #settingsContainer #settingsList select.left { text-align:right; } -#content #settingsContainer #settingsList input.button { - width:22px; - height:22px; - vertical-align:middle; - margin-bottom:2px; -} /* Buttons */ +#content #optionsContainer input, #content #settingsContainer #settingsList input.button, #content #showChannelsButton { + background: url('../img/buttons-sprite.png') no-repeat; + vertical-align:middle; + width:22px; + height:22px; + padding:0; +} #content #optionsContainer #helpButton { - background:url('../img/help.png') no-repeat; + background-position: -69px -22px; } #content #optionsContainer #settingsButton { - background:url('../img/settings.png') no-repeat; + background-position: -92px 0px; } #content #optionsContainer #onlineListButton { - background:url('../img/users.png') no-repeat; + background-position: -69px 0px; } #content #optionsContainer #audioButton { - background:url('../img/audio.png') no-repeat 0px 0px; + background-position: 0px 0px; } #content #optionsContainer #audioButton.off { - background-position: 0px 100%; + background-position: 0px -22px; } #content #optionsContainer #autoScrollButton { - background:url('../img/autoscroll.png') no-repeat 0px 0px; + background-position: -23px 0px; } #content #optionsContainer #autoScrollButton.off { - background-position: 0px 100%; + background-position: -23px -22px; } #content #settingsContainer #settingsList input.playback { - background:url('../img/playback.png') no-repeat; + background-position: -92px -22px; + margin-bottom:3px; +} +#content #logoutChannelContainer #showChannelsButton { + background-position: -46px 0px; + display:none; +} +#content #logoutChannelContainer #showChannelsButton.off { + background-position: -46px -22px; } /* Borders */ #content img { border:none; } -#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, -#content #colorCodesContainer a, #content textarea { +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer a, #content textarea { border-width:1px; border-style:solid; } @@ -268,11 +285,46 @@ border-width:1px; border-style:dotted; } -#content #helpContainer #helpList table, #content #settingsContainer #settingsList table { - border-collapse:collapse; -} /* Misc */ #content #bbCodeContainer input, #content #optionsContainer input.button, #content #settingsContainer #settingsList input.button, #content #logoutButton, #content #submitButton, #loginContent #loginButton { cursor:pointer; +} + +@media (max-width: 700px) { + #content #mainPanelContainer { top:65px; left:5px; right:5px; bottom:105px; } + #content #headline { margin:0; padding:0 0 0 5px; line-height:25px; } + #content #statusIconContainer { top:2px; right:2px; } + #content #copyright { top:0px; right:30px; line-height: 25px;} + #content #logoutChannelContainer { top:30px; left:5px; right:0px; } + #content #logoutChannelContainer label { display:none; } + #content #emoticonsContainer, #content #submitButtonContainer { display:none; } + #content #bbCodeContainer { bottom:45px; left:5px; padding:0; } + #content #bbCodeContainer #bbCodeEmoticon { display:block; } + #content #bbCodeContainer #bbCodeQuote, #content #bbCodeContainer #bbCodeCode { display:none; } + #content #optionsContainer { bottom:10px; right:5px; } + #content #chatList { left:5px; right:150px; bottom:115px; font-size:12px; } + #content #inputFieldContainer #inputField { height:20px; } + #content #inputFieldContainer { left:5px; right:5px; bottom:75px; } + #content #colorCodesContainer, #content #emoticonsContainer { bottom:85px; left:5px; } + #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { margin-left:0; border-left-width:0; } +} + +@media (max-width: 480px) { + #content #mainPanelContainer { top:65px; left:0px; right:0px; bottom:105px; } + #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { border-right-width:0; position:absolute; width:auto; top:0px; right:0px; bottom:0px; left:0px; } + #content #chatList { border-left-width: 0; border-right-width: 0; } + #content #bbCodeContainer #bbCodeIMG, #content #bbCodeContainer #bbCodeURL { display:none; } + #content #bbCodeContainer { padding:0; } + #content #emoticonsContainer { bottom:80px; left:5px; } + #content #logoutChannelInner { display:none; clear:left; padding:5px; text-align:right; } + #content #logoutChannelContainer #showChannelsButton { display:block; position:absolute; right:5px; top:5px; } +} + +@media (max-height: 300px) { + #content #inputFieldContainer #inputField { height:20px; } + #content #bbCodeContainer, #content #optionsContainer, #content #emoticonsContainer, #content #submitButtonContainer, + #content #statusIconContainer, #content #logoutChannelContainer { display:none; } + #content #inputFieldContainer { bottom: 5px; } + #content #mainPanelContainer { bottom:40px; top:35px; } } \ No newline at end of file diff --git a/chat/css/grey.css b/chat/css/grey.css index 36d55d6..64b70c4 100644 --- a/chat/css/grey.css +++ b/chat/css/grey.css @@ -2,114 +2,110 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#8a8a8a; + color:#fff; + border:1px solid #808080; + background-image:linear-gradient(to bottom, #8a8a8a, #444); +} +#content #bbCodeContainer input:hover, #content #logoutButton:hover, #content #submitButton:hover, #loginForm #loginButton:hover { + background-image:linear-gradient(to top, #8a8a8a, #444); +} +#content select, #loginForm select, #loginForm input, #content textarea { + color:#333333; + border: 1px solid #808080; +} -@media screen,projection,handheld { +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#8a8a8a; - color:#fff; - border: 1px solid #808080; - background-image: linear-gradient(to bottom, #8a8a8a, #444); - } - #content select, #loginForm select, #loginForm input, #content textarea { - color:#333333; - border: 1px solid #808080; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Other Theme Elements */ - #loginContent { - background-color:#F6F6F6; - color:#000; - } - #loginContent h1 { - color:#000; - } - #loginContent a { - color:#000; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#000; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#d0d0d0; - color:#000; - } - #content h1 { - color:#000; - } - #content a { - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea { - border-color:gray; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#FFF; - } - #content .rowOdd { - background-color:#F6F6F6; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#FF6600; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#1E90FF; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#FFF; - color:#000; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#d0d0d0; + color:#000; +} +.ajax-chat h1 { + color:#000; +} +.ajax-chat a { + color:#000; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#000; +} +#loginContent #errorContainer { + color:red; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content textarea { + border-color:gray; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#FFF; + border:1px solid gray; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#FFF; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#F6F6F6; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#606060; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#FF6600; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#1E90FF; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#FFF; + color:#000; } \ No newline at end of file diff --git a/chat/css/ie5-6.css b/chat/css/ie5-6.css deleted file mode 100644 index c6ddda3..0000000 --- a/chat/css/ie5-6.css +++ /dev/null @@ -1,70 +0,0 @@ -/* - * @package AJAX_Chat - * @author Sebastian Tschan - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - */ - - -/* - * Positioning adjustments for IE versions < 7 - */ - -body { - width:100%; - height:100%; -} -#content #chatList { - position:static; - margin-right:230px; - margin-left:20px; - margin-top:85px; - height:360px; -} -#content #onlineListContainer { - height:360px; -} -#content #helpContainer { - height:360px; -} -#content #settingsContainer { - height:360px; -} -#content #inputFieldContainer { - top:460px; - padding:0px; -} -#content #submitButtonContainer { - top:517px; -} -#content #bbCodeContainer { - top:550px; -} -#content #colorCodesContainer { - top:516px; -} -#content #emoticonsContainer { - top:517px; -} -#content #optionsContainer { - top:555px; -} -#content #inputFieldContainer #inputField { - width:94%; -} -#content #onlineListContainer #onlineList { - width:100%; - height:335px; - overflow:auto; -} -#content #helpContainer #helpList { - width:100%; - height:335px; - overflow:auto; -} -#content #settingsContainer #settingsList { - width:100%; - height:335px; - overflow:auto; -} \ No newline at end of file diff --git a/chat/css/pine_images/chatlist.jpg b/chat/css/pine_images/chatlist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7366dfe13ec0801c7e069867cb2b2c721d723f3 GIT binary patch literal 50564 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 RbSY+d?il><_2Qr9{|g+;-If3V literal 0 HcmV?d00001 diff --git a/chat/css/print.css b/chat/css/print.css index a37857d..5a5516e 100644 --- a/chat/css/print.css +++ b/chat/css/print.css @@ -1,25 +1,11 @@ -/* - * @package AJAX_Chat - * @author Sebastian Tschan - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - */ - - -/* - * Print layout - */ - @media print { - #content { position:static; } #content #copyright { display:none; } - #content #headlineContainer { + #content #headline { display:none; } #content #logoutChannelContainer { @@ -72,11 +58,9 @@ #content #chatList .delete { display:none; } - #content #chatList { border:none; } - #content { font-family:'times new roman', times, serif; font-size:1.0em; @@ -85,7 +69,6 @@ #content #chatList code { font-size:0.8em; } - #content { color:#000; } @@ -95,6 +78,9 @@ #content .user { color:#000; } + #content .customUser { + color:#0044CC; + } #content .moderator { color:#00AA00; } @@ -110,5 +96,4 @@ #content #chatList a { color:#1E90FF; } - } \ No newline at end of file diff --git a/chat/css/prosilver.css b/chat/css/prosilver.css index 867c30d..f0a0c32 100644 --- a/chat/css/prosilver.css +++ b/chat/css/prosilver.css @@ -2,153 +2,150 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by phpBB style "prosilver": * http://www.phpbb.com/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); + +/* Firefox button padding fix */ +#content #bbCodeContainer input::-moz-focus-inner, #content #logoutButton::-moz-focus-inner, #content #submitButton::-moz-focus-inner { + border:0; + padding:0; +} + +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#F7F5F1; + color:#333333; + border: 1px solid #8a8a8a; + background-image: linear-gradient(to bottom, #fafafa, #cdcdcd); + background-image: -webkit-linear-gradient(top, #fafafa, #cdcdcd); +} +#content select, #loginForm select, #loginForm input, #content textarea { + background-color:#FFF; + color:#333333; + border: 1px solid #ababab; +} + +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} -@media screen,projection,handheld { +/* Headers */ +#loginContent h1 { + color:#333333; +} +#content #headline { + left: 0px; + right: 0px; + background: #0c95d9; + color: white; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#0c95d9; + color:#fff; + height: 25px; +} - /* Firefox button padding fix */ - #content #bbCodeContainer input::-moz-focus-inner, #content #logoutButton::-moz-focus-inner, #content #submitButton::-moz-focus-inner { - border:0; - padding:0; - } - - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#F7F5F1; - color:#333333; - border: 1px solid #8a8a8a; - background-image: linear-gradient(to bottom, #fafafa, #cdcdcd); - background-image: -webkit-linear-gradient(top, #fafafa, #cdcdcd); - } - #content select, #loginForm select, #loginForm input, #content textarea { - background-color:#FFF; - color:#333333; - border: 1px solid #ababab; - } - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - /* Headers */ - #loginContent h1 { - color:#333333; - } - #content #headlineContainer h1 { - color: white; - margin-left: 20px; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#0c95d9; - color:#fff; - height: 25px; - } - - /* Other Theme Elements */ - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer { - border-color: #ababab; - } - #content #chatList .deleteSelected { - border-width:1px; - border-style:dotted; - } - #content #helpContainer #helpList table, #content #settingsContainer #settingsList table { - border-collapse:collapse; - } - #loginContent { - background-color:#F9F9F9; - color:#28313F; - } - #loginContent a { - color:#333333; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#333333; - } - #loginContent #loginFormContainer #loginButton { - background-color:#F7F5F1; - color:#333333; - } - #loginContent #errorContainer { - color:red; - } - #content #headlineContainer { - top: 0; - left: 0; - width: 100%; - background: #0c95d9; - } - #content #copyright, #content #copyright a { - color: white; - } - #content { - background-color:#F9F9F9; - color:#28313F; - } - #content a { - color:#333333; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content #emoticonsContainer { - background-color:#FFF; - } - #content #colorCodesContainer { - box-shadow: 2px 2px 2px #777; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#eaf1f6; - } - #content .rowOdd { - background-color:#e1eaf2; - } - #content .guest { - color:gray; - } - #content .user { - color:#333333; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:#AA0000; - } - #content .chatBot { - color:#D31141; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#D31141; - } - #content #chatList .deleteSelected { - border-color:red; - } +/* Other Theme Elements */ +.ajax-chat { + background-color:#F9F9F9; + color:#28313F; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + border-color: #ababab; +} +.ajax-chat .popup { + background-color:#FFF; + border: 1px solid #ababab; + box-shadow: 2px 2px 2px #777; +} +#content #chatList .deleteSelected { + border-width:1px; + border-style:dotted; +} +#content #helpContainer #helpList table, #content #settingsContainer #settingsList table { + border-collapse:collapse; +} +#loginContent a { + color:#333333; +} +#loginContent input, #loginContent select { + background-color:#FFF; + color:#333333; +} +#loginContent #loginButton { + background-color:#F7F5F1; + color:#333333; +} +#loginContent #errorContainer { + color:red; +} +#content #copyright, #content #copyright a { + color: white; +} +#content a { + color:#333333; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content #emoticonsContainer { + background-color:#FFF; +} +#content #colorCodesContainer { + box-shadow: 2px 2px 2px #777; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#eaf1f6; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#e1eaf2; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#333333; +} +#content .customUser { + color:#0c95d9; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:#AA0000; +} +#content .chatBot { + color:#D31141; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#D31141; +} +#content #chatList .deleteSelected { + border-color:red; } \ No newline at end of file diff --git a/chat/css/shoutbox.css b/chat/css/shoutbox.css index d22a92a..1b7a634 100644 --- a/chat/css/shoutbox.css +++ b/chat/css/shoutbox.css @@ -90,6 +90,10 @@ font-size:0.9em; font-weight:bold; } +#ajaxChatContent #ajaxChatChatList span.customUser { + font-size:0.9em; + font-weight:bold; +} #ajaxChatContent #ajaxChatChatList span.moderator { font-size:0.9em; font-weight:bold; diff --git a/chat/css/subSilver.css b/chat/css/subSilver.css deleted file mode 100644 index 80f8b75..0000000 --- a/chat/css/subSilver.css +++ /dev/null @@ -1,117 +0,0 @@ -/* - * @package AJAX_Chat - * @author Sebastian Tschan - * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - * - * Color palette inspired by phpBB style "subSilver": - * http://www.phpbb.com/ - */ - -@import url('global.css'); -@import url('fonts.css'); -@import url('print.css'); - -@media screen,projection,handheld { - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - #loginContent { - background-color:#E5E5E5; - color:#000; - } - #loginContent h1 { - color:#006699; - } - #loginContent a { - color:#000; - } - #loginContent input, #loginContent select { - background-color:#FFF; - color:#000; - } - #loginContent #loginFormContainer #loginButton { - background-color:#F7F5F1; - color:#000; - } - #loginContent #errorContainer { - color:red; - } - - #content { - background-color:#E5E5E5; - color:#000; - } - #content h1 { - color:#006699; - } - #content a { - color:#000; - } - #content input, #content select, #content textarea { - background-color:#FFF; - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer, #content textarea{ - border-color:#006699; - background-color:#FFF; - } - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton { - background-color:#F7F5F1; - color:#000; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#DEE3E7; - } - #content .rowOdd { - background-color:#EFEFEF; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#006600; - } - #content .admin { - color:#FFA34F; - } - #content .chatBot { - color:#DD6900; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#006699; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#DEE3E7; - color:#006699; - } -} \ No newline at end of file diff --git a/chat/css/subblack2.css b/chat/css/subblack2.css deleted file mode 100644 index 3043754..0000000 --- a/chat/css/subblack2.css +++ /dev/null @@ -1,117 +0,0 @@ -/* - * @package AJAX_Chat - * @author Sebastian Tschan - * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ - * - * Color palette inspired by phpBB style "subblack2": - * http://www.phpbb.com/ - */ - -@import url('global.css'); -@import url('fonts.css'); -@import url('print.css'); - -@media screen,projection,handheld { - - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - #loginContent { - background-color:#000; - color:#FFFFCC; - } - #loginContent h1 { - color:#FFFFCC; - } - #loginContent a { - color:#FFFFCC; - } - #loginContent input, #loginContent select { - background-color:#212121; - color:#FFFFCC; - } - #loginContent #loginFormContainer #loginButton { - background-color:#212121; - color:#FFFFCC; - } - #loginContent #errorContainer { - color:red; - } - - #content { - background-color:#000; - color:#FFFFCC; - } - #content h1 { - color:#CC9900; - } - #content a { - color:#FFFFCC; - } - #content input, #content select, #content textarea { - background-color:#212121; - color:#FFFFCC; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #bbCodeContainer, #content #colorCodesContainer, #content #emoticonsContainer { - border-color:gray; - background-color:#212121; - } - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton { - background-color:#212121; - color:#FFFFCC; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#212121; - } - #content .rowOdd { - background-color:#000; - } - #content .guest { - color:gray; - } - #content .user { - color:#FFFFCC; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#CC9900; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#FFCC00; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#212121; - color:#FFCC00; - } -} \ No newline at end of file diff --git a/chat/css/vBulletin.css b/chat/css/vBulletin.css index 91a7e1a..43998a4 100644 --- a/chat/css/vBulletin.css +++ b/chat/css/vBulletin.css @@ -2,126 +2,130 @@ * @package AJAX_Chat * @author Sebastian Tschan * @author Philip Nicolcev - * @copyright (c) Sebastian Tschan - * @license Modified MIT License - * @link https://blueimp.net/ajax/ * * Color palette inspired by vBulletin style "Standard-Style": * http://www.vbulletin.com/ */ - @import url('global.css'); @import url('fonts.css'); @import url('print.css'); +@import url('custom.css'); -@media screen,projection,handheld { +/* Buttons */ +#content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { + background-color:#7192A8; + color:#fff; + border: 0; +} +#content select, #loginForm select, #loginForm input, #content textarea { + background-color:#7192A8; + color:#fff; + border: 1px solid #2F4456; +} - /* Buttons */ - #content #bbCodeContainer input, #content #logoutButton, #content #submitButton, #loginForm #loginButton { - background-color:#7192A8; - color:#fff; - border: 0; - } - #content select, #loginForm select, #loginForm input, #content textarea { - background-color:#7192A8; - color:#fff; - border: 1px solid #2F4456; - } +/* Status Icon */ +#content #statusIconContainer { + background: url('../img/loading-sprite.png') no-repeat 0px 0px; +} +#content #statusIconContainer.waiting { + background-position: 0px -22px; +} +#content #statusIconContainer.retrying { + background-position: 0px -44px; +} - /* Status Icon */ - #content #statusIconContainer { - background-image: url('../img/loading-sprite.png'); - } - #content .statusContainerOff { - background-position: 0px 0px; - } - #content .statusContainerOn { - background-position: 0px -22px; - } - #content .statusContainerAlert { - background-position: 0px -44px; - } - - #loginContent { - background-color:#E1E1E2; - color:#000; - } - #loginContent h1 { - color:#3B5485; - } - #loginContent a { - color:#3B5485; - } - #loginContent #errorContainer { - color:red; - } - #content { - background-color:#E1E1E2; - color:#000; - } - #content #headlineContainer h1 { - color:#fff; - margin-left: 20px; - } - #content #headlineContainer { - top: 0; - left: 10px; - right: 10px; - background: #2F4456; - border-radius: 0px 0px 5px 5px; - } - #content #copyright, #content #copyright a { - color: white; - } - #content a { - color:#3B5485; - } - #content input, #content select, #content textarea { - background-color:#FFF; - color:#000; - } - #content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer, #content #colorCodesContainer { - border-color:#0B198C; - background-color:#FFF; - } - #content #colorCodesContainer a { - border-color:black; - } - #content #optionsContainer input { - background-color:transparent; - } - #content .rowEven { - background-color:#E1E4F2; - } - #content .rowOdd { - background-color:#F5F5FF; - } - #content .guest { - color:gray; - } - #content .user { - color:#000; - } - #content .moderator { - color:#00AA00; - } - #content .admin { - color:red; - } - #content .chatBot { - color:#3B5485; - } - #content #chatList .chatBotErrorMessage { - color:red; - } - #content #chatList a { - color:#3B5485; - } - #content #chatList .deleteSelected { - border-color:red; - } - #content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { - background-color:#7192A8; - color:#FFF; +/* Other Theme Elements */ +.ajax-chat { + background-color:#E1E1E2; + color:#000; +} +.ajax-chat h1 { + color:#3B5485; +} +.ajax-chat a { + color:#3B5485; +} +#loginContent #errorContainer { + color:red; +} +#content #headline { + color:#fff; + padding-left: 20px; + top:0; + left:10px; + right:10px; + background:#2F4456; + border-radius: 0px 0px 5px 5px; +} +#content #copyright, #content #copyright a { + color:white; +} +#content input, #content select, #content textarea { + background-color:#FFF; + color:#000; +} +#content #chatList, #content #onlineListContainer, #content #helpContainer, #content #settingsContainer { + border-color:#0B198C; + background-color:#FFF; +} +.ajax-chat .popup { + background-color:#FFF; + border:1px solid #0B198C; +} +#content #colorCodesContainer a { + border-color:black; +} +#content #optionsContainer input { + background-color:transparent; +} +#content .rowEven, #helpList dl:nth-child(even), #settingsList dl:nth-child(even) { + background-color:#E1E4F2; +} +#content .rowOdd, #helpList dl:nth-child(odd), #settingsList dl:nth-child(odd) { + background-color:#F5F5FF; +} +#content #chatList .rowOdd.private { + background-color:#F8D0D0; +} +#content #chatList .rowEven.private { + background-color:#F8D9D0; +} +#content .guest { + color:gray; +} +#content .user { + color:#000; +} +#content .customUser { + color:#0b198c; +} +#content .moderator { + color:#00AA00; +} +#content .admin { + color:red; +} +#content .chatBot { + color:#3B5485; +} +#content #chatList .chatBotErrorMessage { + color:red; +} +#content #chatList a { + color:#3B5485; +} +#content #chatList .deleteSelected { + border-color:red; +} +#content #onlineListContainer h3, #content #helpContainer h3, #content #settingsContainer h3 { + background-color:#7192A8; + color:#FFF; +} + +@media (max-width: 700px) { + #content #headline { + left:5px; + right:5px; + padding-left:10px; } } \ No newline at end of file diff --git a/chat/img/audio.png b/chat/img/audio.png deleted file mode 100644 index fb37053165d0335cc899c6a9eefe2e059be2dd42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3966 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 Y0QrW-VE_OC diff --git a/chat/img/autoscroll.png b/chat/img/autoscroll.png deleted file mode 100644 index 7c313e5973191c7a047f3eb866b1250c07f416da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4181 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 diff --git a/chat/img/broken-image.png b/chat/img/broken-image.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2c1842fbd6c04a49cfa166d450f1c3b24ed443 GIT binary patch literal 1037 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 Rj6eVY002ovPDHLkV1hz8a+v@C diff --git a/chat/img/playback.png b/chat/img/playback.png deleted file mode 100644 index 10102d829cd4a82c14aa3bd7d3a56a2f5c35dff0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 961 zcmV;y13vtTP)b z)!%CrR}=^E@41uN*~~861ncT5ZIj(it&JE<-zq{O)DUb7hFW9Pg7u~9i}(vc1O>s` zE*NWDY8zr&v;FZ8l-efo7otg4Z9yyOQz@BEvYTXflkDuwj&pp7yX@u{snr7q?tPfg z+!me;?&YUSCk-@7}AC<$Pc7upnNE+l|g zH@9rcGBaB_i__z2KJ#U((XzEUzV7X{I{^d%_==yIE9ZmgsCO19%01`qc2?u*O4)I8RKDvu)da=dU}?j*maeG<~o!8VCg51h5Q%Yc{x~ z#%{NJX8jnL%uK+@8hCBR3Oe^qTlvMV-!>_3<-L@yM|yAc|LpVm#)J@~x~@Mew5qrl zwY9aO)oWJW`ziX1k{nHdo;0(h+mZ}b^}sSsw0E={y?r+mW69KEP19})Ax4QP9gD@d zWW}LS$jOf-NdkdNU}lE>D2Fk91TI;@u1|KCH*IWs`OFusZHr#4?9WVQ_Y=_ofI(3V z2ZKQ;59MrYDsxk5nps$u3EQ^eI1aLA2Bw)sU}*pwHoWW3+16V=pSm;{3^Fk7I}U|H z&Tujg01yx$As~oAL;z8K*^p%y%H1loxP~Ks0@u{k z6lyGpAfCXIBtb5d0RY`S-PR8mzBfD`@9}+m4|b}mnhJ-*7N$iBTvb(7fE~vH5kZzE zxMUX|Jbd6pBA=O(Bwg6nvi;MBhK3;knd#uHu%al1u@C|t)eAk9LTl@3BOV{@kuE^EJD#UMz{kifzpjVdVcK+`YLTID6N3@xlY0c&OO%pF)wFLPI*ha4wkB`t7X6;ggCCltyU|N^uU4CD1seb zpY5lor-y_2%L*;&@r3|JU`b3&%&|8Qmt%;DeHWx85kJA>rZ7W>z_g~{^n#QukBwAZr zY3hvS=Y|)tzH?@t%5biivuE%W%^xLmsbQuS!kha{Vq2)U~n863@#e zMby;P=mQ-EW*0SlICRhUjbv_KkD`q6Ny`;hrKVA_BL%a`$ohaP|I#&1NG$E|xog-sb){3x}TEs9+uX`tD2)?S6)~i$CyV zPd^xp%m#xYugbE_%7<4YNz#IFLnQR*YgYCb=W+VGcDnio$+OvTxo#2gPXpld`4qq3 zpDoKWD^@)M5Q4|W#f9JoJw?ip$1A_}EPJ+RbLz}R20dPiic4_0ZsB#`q@!QO7#!VD zUtfRMZnxhU85yza%4ht34jw!}Wo0FRBLr54JdPt}Pg7cuN$a`G40^oSo-3RO4UG0$ zrWAJ)umV`=bUFi0r?Xg=Wz4B*G&VNk^Z7!ZFzR>d>(ZE2HAaU9AAnB$-d3QvE(PX< zBm;)d&dwk(JTWn`x1pio>#?yhR8_qi2n6h*5n#odl&$AGyuEsZ?oCb5(XSF`m@H6}Q^x@% z%=bD_|D&jL@SqNz7wN5szO;;u4EO4FLSpRN>#Y?d;V}(^N>O60&RrUy{R52l-tl6f R>M8&L002ovPDHLkV1i=@C_MlG diff --git a/chat/img/users.png b/chat/img/users.png deleted file mode 100644 index bced28cfb3f5a4bf5226ac40b7eefe293987f0da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1277 zcmVgVq)SYK~ZDk zGY|Npi5R0XNQg#FBry^d5g`ywi%{AWO1ZYQ-R^~MclYesv*$aX4_zv>80x%CW+wS( z=0B7F2&UQg&4K3y>Mey>3LsED3bE&l!{$N$hl$&R9h(E6)Rw3%?M?nbonPtzH%uXq z4_UdZrugdf!?{;x3#?Cd+V0;{=V#aUCBD*Bpjt}?>WJ%QI0|h|dEPscmGhhK^9-K3 z2_fDFIQD+If7ZYX7T5Zu zZhJ%ceLf;pl>`HRO1vI&nh#s^>FXk@>2!xL9lDmvp57{C=T2j+>qW8cZotOvfl>;m z;9%wRBoa5V@_FongOrlFOt5gtqHtvOCbU2$wiy??EJUIwf8N)%wYRlxKd;@Ds?X`@pvP*p+?V z^vs~bRcg=gLwR?hmLQuLBN~eli^p*%Vl-e;v*9_i74 z6X=-1@uN?!d}uhdYX7h=WPEd3Ql&DqYEkCt8A^m8HSQpFAFgAA5D1~&+BniqBbD$f zSa}D>o1R(M2K@2ZhH`F<1jN9=1lO-gl&ydq%A@gWDJbP4a|wiIfbK!&61e#kNE;~~ zOF(e?@;W!H3EN|_es4M(rDerx@>ZJui#^yjw6wI4y?h2I6UEKNue54_=9}->k!dPqbz&s zX`JuBdlz`mNT)KNp6H}wX>+xzs&|Deg2lVmNO{woyPCq41rUO9ymXB^?ArS>bNn85 ze|eTg^#bKeT*u+!NS5Xz#m1>$I(M(y&}Q@y+A*2?S6`~_5K6fy>EHq%A36^}d+Ru* z0R!a}ICSa?u9Rr{9qQmSfb^e7x?Ts~0ZNLOVgTV6RxCWNWC4Ica)fMY6#zf|bq&+9 zxo|xVN)k*ZrfNm=8-N330JA9kT2Vtx088pLH&jp{$DFD%%)F#`c#@iMI6T>&EMSzC zVHo-hbyI+x_E{!wn#s?~fBfMk0AI0CaSt7yuu>lZIdPBg;sXLjuT2-OTl#gIw~CWm nVirG9oAw+33;5RLE};Ga6c7WIAH0-{00000NkvXXu0mjf<;zyj diff --git a/chat/index.php b/chat/index.php index a7e2fd0..d411a86 100644 --- a/chat/index.php +++ b/chat/index.php @@ -2,13 +2,14 @@ /* * @package AJAX_Chat * @author Sebastian Tschan + * @author Philip Nicolcev * @copyright (c) Sebastian Tschan * @license Modified MIT License * @link https://blueimp.net/ajax/ */ -// Suppress errors. -error_reporting(0); +// Suppress errors: +error_reporting(E_ALL); // Path to the chat directory: define('AJAX_CHAT_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); @@ -21,4 +22,3 @@ // Initialize the chat: $ajaxChat = new CustomAJAXChat(); -?> \ No newline at end of file diff --git a/chat/js/FABridge.js b/chat/js/FABridge.js index 5942457..e89180e 100644 --- a/chat/js/FABridge.js +++ b/chat/js/FABridge.js @@ -1,591 +1,591 @@ -/* -/* -Copyright 2006 Adobe Systems Incorporated - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - - -/* - * The Bridge class, responsible for navigating AS instances - */ -function FABridge(target,bridgeName) -{ - this.target = target; - this.remoteTypeCache = {}; - this.remoteInstanceCache = {}; - this.remoteFunctionCache = {}; - this.localFunctionCache = {}; - this.bridgeID = FABridge.nextBridgeID++; - this.name = bridgeName; - this.nextLocalFuncID = 0; - FABridge.instances[this.name] = this; - FABridge.idMap[this.bridgeID] = this; - - return this; -} - -// type codes for packed values -FABridge.TYPE_ASINSTANCE = 1; -FABridge.TYPE_ASFUNCTION = 2; - -FABridge.TYPE_JSFUNCTION = 3; -FABridge.TYPE_ANONYMOUS = 4; - -FABridge.initCallbacks = {} - -FABridge.argsToArray = function(args) -{ - var result = []; - for (var i = 0; i < args.length; i++) - { - result[i] = args[i]; - } - return result; -} - -function instanceFactory(objID) -{ - this.fb_instance_id = objID; - return this; -} - -function FABridge__invokeJSFunction(args) -{ - var funcID = args[0]; - var throughArgs = args.concat();//FABridge.argsToArray(arguments); - throughArgs.shift(); - - var bridge = FABridge.extractBridgeFromID(funcID); - return bridge.invokeLocalFunction(funcID, throughArgs); -} - -FABridge.addInitializationCallback = function(bridgeName, callback) -{ - var inst = FABridge.instances[bridgeName]; - if (inst != undefined) - { - callback.call(inst); - return; - } - - var callbackList = FABridge.initCallbacks[bridgeName]; - if(callbackList == null) - { - FABridge.initCallbacks[bridgeName] = callbackList = []; - } - - callbackList.push(callback); -} - -function FABridge__bridgeInitialized(bridgeName) { - var objects = document.getElementsByTagName("object"); - var ol = objects.length; - var activeObjects = []; - if (ol > 0) { - for (var i = 0; i < ol; i++) { - if (typeof objects[i].SetVariable != "undefined") { - activeObjects[activeObjects.length] = objects[i]; - } - } - } - var embeds = document.getElementsByTagName("embed"); - var el = embeds.length; - var activeEmbeds = []; - if (el > 0) { - for (var j = 0; j < el; j++) { - if (typeof embeds[j].SetVariable != "undefined") { - activeEmbeds[activeEmbeds.length] = embeds[j]; - } - } - } - var aol = activeObjects.length; - var ael = activeEmbeds.length; - var searchStr = "bridgeName="+ bridgeName; - if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) { - FABridge.attachBridge(activeObjects[0], bridgeName); - } - else if (ael == 1 && !aol) { - FABridge.attachBridge(activeEmbeds[0], bridgeName); - } - else { - var flash_found = false; - if (aol > 1) { - for (var k = 0; k < aol; k++) { - var params = activeObjects[k].childNodes; - for (var l = 0; l < params.length; l++) { - var param = params[l]; - if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) { - FABridge.attachBridge(activeObjects[k], bridgeName); - flash_found = true; - break; - } - } - if (flash_found) { - break; - } - } - } - if (!flash_found && ael > 1) { - for (var m = 0; m < ael; m++) { - var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue; - if (flashVars.indexOf(searchStr) >= 0) { - FABridge.attachBridge(activeEmbeds[m], bridgeName); - break; - } - } - } - } - return true; -} - -// used to track multiple bridge instances, since callbacks from AS are global across the page. - -FABridge.nextBridgeID = 0; -FABridge.instances = {}; -FABridge.idMap = {}; -FABridge.refCount = 0; - -FABridge.extractBridgeFromID = function(id) -{ - var bridgeID = (id >> 16); - return FABridge.idMap[bridgeID]; -} - -FABridge.attachBridge = function(instance, bridgeName) -{ - var newBridgeInstance = new FABridge(instance, bridgeName); - - FABridge[bridgeName] = newBridgeInstance; - -/* FABridge[bridgeName] = function() { - return newBridgeInstance.root(); - } -*/ - var callbacks = FABridge.initCallbacks[bridgeName]; - if (callbacks == null) - { - return; - } - for (var i = 0; i < callbacks.length; i++) - { - callbacks[i].call(newBridgeInstance); - } - delete FABridge.initCallbacks[bridgeName] -} - -// some methods can't be proxied. You can use the explicit get,set, and call methods if necessary. - -FABridge.blockedMethods = -{ - toString: true, - get: true, - set: true, - call: true -}; - -FABridge.prototype = -{ - - -// bootstrapping - - root: function() - { - return this.deserialize(this.target.getRoot()); - }, -//clears all of the AS objects in the cache maps - releaseASObjects: function() - { - return this.target.releaseASObjects(); - }, -//clears a specific object in AS from the type maps - releaseNamedASObject: function(value) - { - if(typeof(value) != "object") - { - return false; - } - else - { - var ret = this.target.releaseNamedASObject(value.fb_instance_id); - return ret; - } - }, -//create a new AS Object - create: function(className) - { - return this.deserialize(this.target.create(className)); - }, - - - // utilities - - makeID: function(token) - { - return (this.bridgeID << 16) + token; - }, - - - // low level access to the flash object - -//get a named property from an AS object - getPropertyFromAS: function(objRef, propName) - { - if (FABridge.refCount > 0) - { - throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); - } - else - { - FABridge.refCount++; - retVal = this.target.getPropFromAS(objRef, propName); - retVal = this.handleError(retVal); - FABridge.refCount--; - return retVal; - } - }, -//set a named property on an AS object - setPropertyInAS: function(objRef,propName, value) - { - if (FABridge.refCount > 0) - { - throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); - } - else - { - FABridge.refCount++; - retVal = this.target.setPropInAS(objRef,propName, this.serialize(value)); - retVal = this.handleError(retVal); - FABridge.refCount--; - return retVal; - } - }, - -//call an AS function - callASFunction: function(funcID, args) - { - if (FABridge.refCount > 0) - { - throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); - } - else - { - FABridge.refCount++; - retVal = this.target.invokeASFunction(funcID, this.serialize(args)); - retVal = this.handleError(retVal); - FABridge.refCount--; - return retVal; - } - }, -//call a method on an AS object - callASMethod: function(objID, funcName, args) - { - if (FABridge.refCount > 0) - { - throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); - } - else - { - FABridge.refCount++; - args = this.serialize(args); - retVal = this.target.invokeASMethod(objID, funcName, args); - retVal = this.handleError(retVal); - FABridge.refCount--; - return retVal; - } - }, - - // responders to remote calls from flash - - //callback from flash that executes a local JS function - //used mostly when setting js functions as callbacks on events - invokeLocalFunction: function(funcID, args) - { - var result; - var func = this.localFunctionCache[funcID]; - - if(func != undefined) - { - result = this.serialize(func.apply(null, this.deserialize(args))); - } - - return result; - }, - - // Object Types and Proxies - - // accepts an object reference, returns a type object matching the obj reference. - getTypeFromName: function(objTypeName) - { - return this.remoteTypeCache[objTypeName]; - }, - //create an AS proxy for the given object ID and type - createProxy: function(objID, typeName) - { - var objType = this.getTypeFromName(typeName); - instanceFactory.prototype = objType; - var instance = new instanceFactory(objID); - this.remoteInstanceCache[objID] = instance; - return instance; - }, - //return the proxy associated with the given object ID - getProxy: function(objID) - { - return this.remoteInstanceCache[objID]; - }, - - // accepts a type structure, returns a constructed type - addTypeDataToCache: function(typeData) - { - newType = new ASProxy(this, typeData.name); - var accessors = typeData.accessors; - for (var i = 0; i < accessors.length; i++) - { - this.addPropertyToType(newType, accessors[i]); - } - - var methods = typeData.methods; - for (var i = 0; i < methods.length; i++) - { - if (FABridge.blockedMethods[methods[i]] == undefined) - { - this.addMethodToType(newType, methods[i]); - } - } - - - this.remoteTypeCache[newType.typeName] = newType; - return newType; - }, - - //add a property to a typename; used to define the properties that can be called on an AS proxied object - addPropertyToType: function(ty, propName) - { - var c = propName.charAt(0); - var setterName; - var getterName; - if(c >= "a" && c <= "z") - { - getterName = "get" + c.toUpperCase() + propName.substr(1); - setterName = "set" + c.toUpperCase() + propName.substr(1); - } - else - { - getterName = "get" + propName; - setterName = "set" + propName; - } - ty[setterName] = function(val) - { - this.bridge.setPropertyInAS(this.fb_instance_id, propName, val); - } - ty[getterName] = function() - { - return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); - } - }, - - //add a method to a typename; used to define the methods that can be callefd on an AS proxied object - addMethodToType: function(ty, methodName) - { - ty[methodName] = function() - { - return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments))); - } - }, - - // Function Proxies - - //returns the AS proxy for the specified function ID - getFunctionProxy: function(funcID) - { - var bridge = this; - if (this.remoteFunctionCache[funcID] == null) - { - this.remoteFunctionCache[funcID] = function() - { - bridge.callASFunction(funcID, FABridge.argsToArray(arguments)); - } - } - return this.remoteFunctionCache[funcID]; - }, - - //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache - getFunctionID: function(func) - { - if (func.__bridge_id__ == undefined) - { - func.__bridge_id__ = this.makeID(this.nextLocalFuncID++); - this.localFunctionCache[func.__bridge_id__] = func; - } - return func.__bridge_id__; - }, - - // serialization / deserialization - - serialize: function(value) - { - var result = {}; - - var t = typeof(value); - //primitives are kept as such - if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined) - { - result = value; - } - else if (value instanceof Array) - { - //arrays are serializesd recursively - result = []; - for (var i = 0; i < value.length; i++) - { - result[i] = this.serialize(value[i]); - } - } - else if (t == "function") - { - //js functions are assigned an ID and stored in the local cache - result.type = FABridge.TYPE_JSFUNCTION; - result.value = this.getFunctionID(value); - } - else if (value instanceof ASProxy) - { - result.type = FABridge.TYPE_ASINSTANCE; - result.value = value.fb_instance_id; - } - else - { - result.type = FABridge.TYPE_ANONYMOUS; - result.value = value; - } - - return result; - }, - - //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors - // the unpacking is done by returning the value on each pachet for objects/arrays - deserialize: function(packedValue) - { - - var result; - - var t = typeof(packedValue); - if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined) - { - result = this.handleError(packedValue); - } - else if (packedValue instanceof Array) - { - result = []; - for (var i = 0; i < packedValue.length; i++) - { - result[i] = this.deserialize(packedValue[i]); - } - } - else if (t == "object") - { - for(var i = 0; i < packedValue.newTypes.length; i++) - { - this.addTypeDataToCache(packedValue.newTypes[i]); - } - for (var aRefID in packedValue.newRefs) - { - this.createProxy(aRefID, packedValue.newRefs[aRefID]); - } - if (packedValue.type == FABridge.TYPE_PRIMITIVE) - { - result = packedValue.value; - } - else if (packedValue.type == FABridge.TYPE_ASFUNCTION) - { - result = this.getFunctionProxy(packedValue.value); - } - else if (packedValue.type == FABridge.TYPE_ASINSTANCE) - { - result = this.getProxy(packedValue.value); - } - else if (packedValue.type == FABridge.TYPE_ANONYMOUS) - { - result = packedValue.value; - } - } - return result; - }, - //increases the reference count for the given object - addRef: function(obj) - { - this.target.incRef(obj.fb_instance_id); - }, - //decrease the reference count for the given object and release it if needed - release:function(obj) - { - this.target.releaseRef(obj.fb_instance_id); - }, - - // check the given value for the components of the hard-coded error code : __FLASHERROR - // used to marshall NPE's into flash - - handleError: function(value) - { - if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0) - { - var myErrorMessage = value.split("||"); - if(FABridge.refCount > 0 ) - { - FABridge.refCount--; - } - throw new Error(myErrorMessage[1]); - return value; - } - else - { - return value; - } - } -}; - -// The root ASProxy class that facades a flash object - -ASProxy = function(bridge, typeName) -{ - this.bridge = bridge; - this.typeName = typeName; - return this; -}; -//methods available on each ASProxy object -ASProxy.prototype = -{ - get: function(propName) - { - return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); - }, - - set: function(propName, value) - { - this.bridge.setPropertyInAS(this.fb_instance_id, propName, value); - }, - - call: function(funcName, args) - { - this.bridge.callASMethod(this.fb_instance_id, funcName, args); - }, - - addRef: function() { - this.bridge.addRef(this); - }, - - release: function() { - this.bridge.release(this); - } -}; +/* +/* +Copyright 2006 Adobe Systems Incorporated + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + + +/* + * The Bridge class, responsible for navigating AS instances + */ +function FABridge(target,bridgeName) +{ + this.target = target; + this.remoteTypeCache = {}; + this.remoteInstanceCache = {}; + this.remoteFunctionCache = {}; + this.localFunctionCache = {}; + this.bridgeID = FABridge.nextBridgeID++; + this.name = bridgeName; + this.nextLocalFuncID = 0; + FABridge.instances[this.name] = this; + FABridge.idMap[this.bridgeID] = this; + + return this; +} + +// type codes for packed values +FABridge.TYPE_ASINSTANCE = 1; +FABridge.TYPE_ASFUNCTION = 2; + +FABridge.TYPE_JSFUNCTION = 3; +FABridge.TYPE_ANONYMOUS = 4; + +FABridge.initCallbacks = {} + +FABridge.argsToArray = function(args) +{ + var result = []; + for (var i = 0; i < args.length; i++) + { + result[i] = args[i]; + } + return result; +} + +function instanceFactory(objID) +{ + this.fb_instance_id = objID; + return this; +} + +function FABridge__invokeJSFunction(args) +{ + var funcID = args[0]; + var throughArgs = args.concat();//FABridge.argsToArray(arguments); + throughArgs.shift(); + + var bridge = FABridge.extractBridgeFromID(funcID); + return bridge.invokeLocalFunction(funcID, throughArgs); +} + +FABridge.addInitializationCallback = function(bridgeName, callback) +{ + var inst = FABridge.instances[bridgeName]; + if (inst != undefined) + { + callback.call(inst); + return; + } + + var callbackList = FABridge.initCallbacks[bridgeName]; + if(callbackList == null) + { + FABridge.initCallbacks[bridgeName] = callbackList = []; + } + + callbackList.push(callback); +} + +function FABridge__bridgeInitialized(bridgeName) { + var objects = document.getElementsByTagName("object"); + var ol = objects.length; + var activeObjects = []; + if (ol > 0) { + for (var i = 0; i < ol; i++) { + if (typeof objects[i].SetVariable != "undefined") { + activeObjects[activeObjects.length] = objects[i]; + } + } + } + var embeds = document.getElementsByTagName("embed"); + var el = embeds.length; + var activeEmbeds = []; + if (el > 0) { + for (var j = 0; j < el; j++) { + if (typeof embeds[j].SetVariable != "undefined") { + activeEmbeds[activeEmbeds.length] = embeds[j]; + } + } + } + var aol = activeObjects.length; + var ael = activeEmbeds.length; + var searchStr = "bridgeName="+ bridgeName; + if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) { + FABridge.attachBridge(activeObjects[0], bridgeName); + } + else if (ael == 1 && !aol) { + FABridge.attachBridge(activeEmbeds[0], bridgeName); + } + else { + var flash_found = false; + if (aol > 1) { + for (var k = 0; k < aol; k++) { + var params = activeObjects[k].childNodes; + for (var l = 0; l < params.length; l++) { + var param = params[l]; + if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) { + FABridge.attachBridge(activeObjects[k], bridgeName); + flash_found = true; + break; + } + } + if (flash_found) { + break; + } + } + } + if (!flash_found && ael > 1) { + for (var m = 0; m < ael; m++) { + var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue; + if (flashVars.indexOf(searchStr) >= 0) { + FABridge.attachBridge(activeEmbeds[m], bridgeName); + break; + } + } + } + } + return true; +} + +// used to track multiple bridge instances, since callbacks from AS are global across the page. + +FABridge.nextBridgeID = 0; +FABridge.instances = {}; +FABridge.idMap = {}; +FABridge.refCount = 0; + +FABridge.extractBridgeFromID = function(id) +{ + var bridgeID = (id >> 16); + return FABridge.idMap[bridgeID]; +} + +FABridge.attachBridge = function(instance, bridgeName) +{ + var newBridgeInstance = new FABridge(instance, bridgeName); + + FABridge[bridgeName] = newBridgeInstance; + +/* FABridge[bridgeName] = function() { + return newBridgeInstance.root(); + } +*/ + var callbacks = FABridge.initCallbacks[bridgeName]; + if (callbacks == null) + { + return; + } + for (var i = 0; i < callbacks.length; i++) + { + callbacks[i].call(newBridgeInstance); + } + delete FABridge.initCallbacks[bridgeName] +} + +// some methods can't be proxied. You can use the explicit get,set, and call methods if necessary. + +FABridge.blockedMethods = +{ + toString: true, + get: true, + set: true, + call: true +}; + +FABridge.prototype = +{ + + +// bootstrapping + + root: function() + { + return this.deserialize(this.target.getRoot()); + }, +//clears all of the AS objects in the cache maps + releaseASObjects: function() + { + return this.target.releaseASObjects(); + }, +//clears a specific object in AS from the type maps + releaseNamedASObject: function(value) + { + if(typeof(value) != "object") + { + return false; + } + else + { + var ret = this.target.releaseNamedASObject(value.fb_instance_id); + return ret; + } + }, +//create a new AS Object + create: function(className) + { + return this.deserialize(this.target.create(className)); + }, + + + // utilities + + makeID: function(token) + { + return (this.bridgeID << 16) + token; + }, + + + // low level access to the flash object + +//get a named property from an AS object + getPropertyFromAS: function(objRef, propName) + { + if (FABridge.refCount > 0) + { + throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); + } + else + { + FABridge.refCount++; + retVal = this.target.getPropFromAS(objRef, propName); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, +//set a named property on an AS object + setPropertyInAS: function(objRef,propName, value) + { + if (FABridge.refCount > 0) + { + throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); + } + else + { + FABridge.refCount++; + retVal = this.target.setPropInAS(objRef,propName, this.serialize(value)); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, + +//call an AS function + callASFunction: function(funcID, args) + { + if (FABridge.refCount > 0) + { + throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); + } + else + { + FABridge.refCount++; + retVal = this.target.invokeASFunction(funcID, this.serialize(args)); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, +//call a method on an AS object + callASMethod: function(objID, funcName, args) + { + if (FABridge.refCount > 0) + { + throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround."); + } + else + { + FABridge.refCount++; + args = this.serialize(args); + retVal = this.target.invokeASMethod(objID, funcName, args); + retVal = this.handleError(retVal); + FABridge.refCount--; + return retVal; + } + }, + + // responders to remote calls from flash + + //callback from flash that executes a local JS function + //used mostly when setting js functions as callbacks on events + invokeLocalFunction: function(funcID, args) + { + var result; + var func = this.localFunctionCache[funcID]; + + if(func != undefined) + { + result = this.serialize(func.apply(null, this.deserialize(args))); + } + + return result; + }, + + // Object Types and Proxies + + // accepts an object reference, returns a type object matching the obj reference. + getTypeFromName: function(objTypeName) + { + return this.remoteTypeCache[objTypeName]; + }, + //create an AS proxy for the given object ID and type + createProxy: function(objID, typeName) + { + var objType = this.getTypeFromName(typeName); + instanceFactory.prototype = objType; + var instance = new instanceFactory(objID); + this.remoteInstanceCache[objID] = instance; + return instance; + }, + //return the proxy associated with the given object ID + getProxy: function(objID) + { + return this.remoteInstanceCache[objID]; + }, + + // accepts a type structure, returns a constructed type + addTypeDataToCache: function(typeData) + { + newType = new ASProxy(this, typeData.name); + var accessors = typeData.accessors; + for (var i = 0; i < accessors.length; i++) + { + this.addPropertyToType(newType, accessors[i]); + } + + var methods = typeData.methods; + for (var i = 0; i < methods.length; i++) + { + if (FABridge.blockedMethods[methods[i]] == undefined) + { + this.addMethodToType(newType, methods[i]); + } + } + + + this.remoteTypeCache[newType.typeName] = newType; + return newType; + }, + + //add a property to a typename; used to define the properties that can be called on an AS proxied object + addPropertyToType: function(ty, propName) + { + var c = propName.charAt(0); + var setterName; + var getterName; + if(c >= "a" && c <= "z") + { + getterName = "get" + c.toUpperCase() + propName.substr(1); + setterName = "set" + c.toUpperCase() + propName.substr(1); + } + else + { + getterName = "get" + propName; + setterName = "set" + propName; + } + ty[setterName] = function(val) + { + this.bridge.setPropertyInAS(this.fb_instance_id, propName, val); + } + ty[getterName] = function() + { + return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); + } + }, + + //add a method to a typename; used to define the methods that can be callefd on an AS proxied object + addMethodToType: function(ty, methodName) + { + ty[methodName] = function() + { + return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments))); + } + }, + + // Function Proxies + + //returns the AS proxy for the specified function ID + getFunctionProxy: function(funcID) + { + var bridge = this; + if (this.remoteFunctionCache[funcID] == null) + { + this.remoteFunctionCache[funcID] = function() + { + bridge.callASFunction(funcID, FABridge.argsToArray(arguments)); + } + } + return this.remoteFunctionCache[funcID]; + }, + + //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache + getFunctionID: function(func) + { + if (func.__bridge_id__ == undefined) + { + func.__bridge_id__ = this.makeID(this.nextLocalFuncID++); + this.localFunctionCache[func.__bridge_id__] = func; + } + return func.__bridge_id__; + }, + + // serialization / deserialization + + serialize: function(value) + { + var result = {}; + + var t = typeof(value); + //primitives are kept as such + if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined) + { + result = value; + } + else if (value instanceof Array) + { + //arrays are serializesd recursively + result = []; + for (var i = 0; i < value.length; i++) + { + result[i] = this.serialize(value[i]); + } + } + else if (t == "function") + { + //js functions are assigned an ID and stored in the local cache + result.type = FABridge.TYPE_JSFUNCTION; + result.value = this.getFunctionID(value); + } + else if (value instanceof ASProxy) + { + result.type = FABridge.TYPE_ASINSTANCE; + result.value = value.fb_instance_id; + } + else + { + result.type = FABridge.TYPE_ANONYMOUS; + result.value = value; + } + + return result; + }, + + //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors + // the unpacking is done by returning the value on each pachet for objects/arrays + deserialize: function(packedValue) + { + + var result; + + var t = typeof(packedValue); + if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined) + { + result = this.handleError(packedValue); + } + else if (packedValue instanceof Array) + { + result = []; + for (var i = 0; i < packedValue.length; i++) + { + result[i] = this.deserialize(packedValue[i]); + } + } + else if (t == "object") + { + for(var i = 0; i < packedValue.newTypes.length; i++) + { + this.addTypeDataToCache(packedValue.newTypes[i]); + } + for (var aRefID in packedValue.newRefs) + { + this.createProxy(aRefID, packedValue.newRefs[aRefID]); + } + if (packedValue.type == FABridge.TYPE_PRIMITIVE) + { + result = packedValue.value; + } + else if (packedValue.type == FABridge.TYPE_ASFUNCTION) + { + result = this.getFunctionProxy(packedValue.value); + } + else if (packedValue.type == FABridge.TYPE_ASINSTANCE) + { + result = this.getProxy(packedValue.value); + } + else if (packedValue.type == FABridge.TYPE_ANONYMOUS) + { + result = packedValue.value; + } + } + return result; + }, + //increases the reference count for the given object + addRef: function(obj) + { + this.target.incRef(obj.fb_instance_id); + }, + //decrease the reference count for the given object and release it if needed + release:function(obj) + { + this.target.releaseRef(obj.fb_instance_id); + }, + + // check the given value for the components of the hard-coded error code : __FLASHERROR + // used to marshall NPE's into flash + + handleError: function(value) + { + if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0) + { + var myErrorMessage = value.split("||"); + if(FABridge.refCount > 0 ) + { + FABridge.refCount--; + } + throw new Error(myErrorMessage[1]); + return value; + } + else + { + return value; + } + } +}; + +// The root ASProxy class that facades a flash object + +ASProxy = function(bridge, typeName) +{ + this.bridge = bridge; + this.typeName = typeName; + return this; +}; +//methods available on each ASProxy object +ASProxy.prototype = +{ + get: function(propName) + { + return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName)); + }, + + set: function(propName, value) + { + this.bridge.setPropertyInAS(this.fb_instance_id, propName, value); + }, + + call: function(funcName, args) + { + this.bridge.callASMethod(this.fb_instance_id, funcName, args); + }, + + addRef: function() { + this.bridge.addRef(this); + }, + + release: function() { + this.bridge.release(this); + } +}; diff --git a/chat/js/chat.js b/chat/js/chat.js index 9a93f5e..7b79f14 100644 --- a/chat/js/chat.js +++ b/chat/js/chat.js @@ -4,10 +4,10 @@ * @copyright (c) Sebastian Tschan * @license Modified MIT License * @link https://blueimp.net/ajax/ - * + * * The SELFHTML documentation has been used throughout this project: * http://selfhtml.org - * + * * Stylesheet and cookie methods have been inspired by Paul Sowden (A List Apart): * http://www.alistapart.com/stories/alternate/ */ @@ -85,21 +85,26 @@ var ajaxChat = { httpRequest: null, retryTimer: null, retryTimerDelay: null, - requestStatus: 'ok', + requestStatus: null, DOMbuffering: null, DOMbuffer: null, - DOMbufferRowClass: 'rowOdd', - - init: function(config, lang, initSettings, initStyle, initialize, initializeFunction, finalizeFunction) { + DOMbufferRowClass: null, + inUrlBBCode: null, + debug: null, + + init: function(config, lang, initSettings, initStyle, initialize, initializeFunction, finalizeFunction) { this.httpRequest = {}; this.usersList = []; this.userNamesList = []; this.userMenuCounter = 0; this.lastID = 0; this.localID = 0; - this.lang = lang; + this.lang = lang; + this.requestStatus = 'ok'; + this.DOMbufferRowClass = 'rowOdd'; + this.inUrlBBCode = false; this.initConfig(config); - this.initDirectories(); + this.initDirectories(); if(initSettings) { this.initSettings(); } @@ -112,7 +117,7 @@ var ajaxChat = { this.setLoadHandler(); } }, - + initConfig: function(config) { this.loginChannelID = config['loginChannelID']; this.loginChannelName = config['loginChannelName']; @@ -137,7 +142,7 @@ var ajaxChat = { this.chatBotName = config['chatBotName']; this.chatBotID = config['chatBotID']; this.allowUserMessageDelete = config['allowUserMessageDelete']; - this.inactiveTimeout = config['inactiveTimeout']; + this.inactiveTimeout = Math.max(config['inactiveTimeout'],2); this.privateChannelDiff = config['privateChannelDiff']; this.privateMessageDiff = config['privateMessageDiff']; this.showChannelMessages = config['showChannelMessages']; @@ -146,6 +151,7 @@ var ajaxChat = { this.socketServerHost = config['socketServerHost']; this.socketServerPort = config['socketServerPort']; this.socketServerChatID = config['socketServerChatID']; + this.debug = config['debug']; this.DOMbuffering = false; this.DOMbuffer = ""; this.retryTimerDelay = (this.inactiveTimeout*6000 - this.timerRate)/4 + this.timerRate; @@ -157,7 +163,7 @@ var ajaxChat = { this.dirs['sounds'] = this.baseURL+'sounds/'; this.dirs['flash'] = this.baseURL+'flash/'; }, - + initSettings: function() { var cookie = this.readCookie(this.sessionName + '_settings'), i, settingsArray, setting, key, value, number; @@ -209,21 +215,21 @@ var ajaxChat = { if(this.inArray(this.nonPersistentSettings, property)) { if(this.unusedSettings && this.unusedSettings[property]) { // Store the unusedSetting previously stored: - this.settings[property] = this.unusedSettings[property]; + this.settings[property] = this.unusedSettings[property]; } else { continue; } } settingsArray.push(property + '=' + this.encodeText(this.settings[property])); } - this.createCookie(this.sessionName + '_settings', settingsArray.join('&'), this.cookieExpiration); + this.createCookie(this.sessionName + '_settings', settingsArray.join('&'), this.cookieExpiration); } }, - + getSettings: function() { return this.settings; }, - + getSetting: function(key) { // Only return null if setting is null or undefined, not if it is false: for(var property in this.settings) { @@ -233,11 +239,11 @@ var ajaxChat = { } return null; }, - + setSetting: function(key, value) { this.settings[key] = value; }, - + initializeSettings: function() { if(this.settings['persistFontColor'] && this.settings['fontColor']) { // Set the inputField font color to the font color: @@ -246,17 +252,17 @@ var ajaxChat = { } } }, - - initialize: function() { + + initialize: function() { this.setUnloadHandler(); this.initializeDocumentNodes(); this.loadPageAttributes(); this.initEmoticons(); this.initColorCodes(); - this.initializeSettings(); + this.initializeSettings(); this.setSelectedStyle(); this.customInitialize(); - //preload the Alert icon (it can't display if there's no connection unless it's cached!) + // preload the Alert icon (it can't display if there's no connection unless it's cached!) this.setStatus('retrying'); if(typeof this.initializeFunction === 'function') { this.initializeFunction(); @@ -283,17 +289,17 @@ var ajaxChat = { } this.updateChat(params); }, - + setStartChatHandler: function() { if(this.dom['inputField']) { this.dom['inputField'].onfocus = function() { ajaxChat.startChat(); // Reset the onfocus event on first call: ajaxChat.dom['inputField'].onfocus = ''; - }; + }; } }, - + startChat: function() { this.chatStarted = true; if(this.dom['inputField'] && this.settings['autoFocus']) { @@ -306,24 +312,17 @@ var ajaxChat = { loadPageAttributes: function() { var htmlTag = document.getElementsByTagName('html')[0]; this.langCode = htmlTag.getAttribute('lang') ? htmlTag.getAttribute('lang') : 'en'; - this.baseDirection = htmlTag.getAttribute('dir') ? htmlTag.getAttribute('dir') : 'ltr'; + this.baseDirection = htmlTag.getAttribute('dir') ? htmlTag.getAttribute('dir') : 'ltr'; }, setLoadHandler: function() { + var self = this; // Make sure initialize() is called on page load: - var onload = window.onload; - if(typeof onload !== 'function') { - window.onload = function() { - ajaxChat.initialize(); - }; - } else { - window.onload = function() { - onload(); - ajaxChat.initialize(); - }; - } + this.addEvent(window,'load', function() { + self.initialize(); + }); }, - + setUnloadHandler: function() { // Make sure finalize() is called on page unload: var onunload = window.onunload; @@ -355,11 +354,12 @@ var ajaxChat = { domNode.innerHTML += str; } } catch(e) { + this.DOMbuffer = ''; this.addChatBotMessageToChatList('/error DOMSyntax '+id); this.updateChatlistView(); } }, - + initializeDocumentNodes: function() { this.dom = {}; for(var key in this.domIDs) { @@ -389,7 +389,7 @@ var ajaxChat = { } this.DOMbuffer = ""; }, - + initColorCodes: function() { if(this.dom['colorCodesContainer']) { this.DOMbuffer = ""; @@ -424,7 +424,7 @@ var ajaxChat = { } this.updateChat(params); }, - + updateChat: function(paramString) { var requestUrl = this.ajaxURL + '&lastID=' @@ -434,7 +434,7 @@ var ajaxChat = { } this.makeRequest(requestUrl,'GET',null); }, - + loadFlashInterface: function() { if(this.dom['flashInterfaceContainer']) { this.updateDOM( @@ -456,7 +456,7 @@ var ajaxChat = { FABridge.addInitializationCallback('ajaxChat', this.flashInterfaceLoadCompleteHandler); } }, - + flashInterfaceLoadCompleteHandler: function() { ajaxChat.initializeFlashInterface(); }, @@ -483,13 +483,13 @@ var ajaxChat = { } this.socket.connect(this.socketServerHost, this.socketServerPort); } catch(e) { - //alert(e); + this.debugMessage('socketConnect', e); } } clearTimeout(this.socketReconnectTimer); this.socketReconnectTimer = null; }, - + socketConnectHandler: function(event) { ajaxChat.socketIsConnected = true; // setTimeout is needed to avoid calling the flash interface recursively: @@ -503,7 +503,7 @@ var ajaxChat = { ajaxChat.updateChat(null); } }, - + socketDataHandler: function(event) { ajaxChat.socketUpdate(event.getData()); }, @@ -533,11 +533,11 @@ var ajaxChat = { +'"/>' ); } catch(e) { - //alert(e); + this.debugMessage('socketRegister', e); } } }, - + loadXML: function(str) { if(!arguments.callee.parser) { try { @@ -552,7 +552,7 @@ var ajaxChat = { arguments.callee.XMLDOM = new ActiveXObject('Microsoft.XMLDOM'); } arguments.callee.XMLDOM.loadXML(str); - return arguments.callee.XMLDOM; + return arguments.callee.XMLDOM; }; } else { // Safari, Konqueror: @@ -574,7 +574,7 @@ var ajaxChat = { } return arguments.callee.parser.parseFromString(str, 'text/xml'); }, - + socketUpdate: function(data) { var xmlDoc = this.loadXML(data); if(xmlDoc) { @@ -602,15 +602,15 @@ var ajaxChat = { this.settings['audioVolume'] = volume; try { if(!this.soundTransform) { - this.soundTransform = FABridge.ajaxChat.create('flash.media.SoundTransform'); + this.soundTransform = FABridge.ajaxChat.create('flash.media.SoundTransform'); } this.soundTransform.setVolume(volume); } catch(e) { - //alert(e); + this.debugMessage('setAudioVolume', e); } } }, - + loadSounds: function() { try { this.setAudioVolume(this.settings['audioVolume']); @@ -625,10 +625,10 @@ var ajaxChat = { sound.load(urlRequest); } } catch(e) { - alert(e); + this.debugMessage('loadSounds', e); } }, - + soundLoadCompleteHandler: function(event) { var sound = event.getTarget(); for(var key in ajaxChat.soundFiles) { @@ -645,7 +645,7 @@ var ajaxChat = { setTimeout(function() { ajaxChat.addChatBotMessageToChatList('/error SoundIO'); }, 0); setTimeout(ajaxChat.updateChatlistView, 1); }, - + soundPlayCompleteHandler: function(event) { // soundChannel event 'soundComplete' }, @@ -659,17 +659,21 @@ var ajaxChat = { // sndTransform:SoundTransform (default = null) return this.sounds[soundID].play(0, 0, this.soundTransform); } catch(e) { - //alert(e); + this.debugMessage('playSound', e); } } return null; }, - + playSoundOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) { + var messageParts; if(this.settings['audio'] && this.sounds && this.lastID && !this.channelSwitch) { + if(this.customSoundOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) === false) { + return; + } + messageParts = messageText.split(' ', 1); switch(userID) { case this.chatBotID: - var messageParts = messageText.split(' ', 1); switch(messageParts[0]) { case '/login': case '/channelEnter': @@ -688,10 +692,22 @@ var ajaxChat = { } break; case this.userID: - this.playSound(this.settings['soundSend']); + switch(messageParts[0]) { + case '/privmsgto': + this.playSound(this.settings['soundPrivate']); + break; + default: + this.playSound(this.settings['soundSend']); + } break; default: - this.playSound(this.settings['soundReceive']); + switch(messageParts[0]) { + case '/privmsg': + this.playSound(this.settings['soundPrivate']); + break; + default: + this.playSound(this.settings['soundReceive']); + } break; } } @@ -712,32 +728,20 @@ var ajaxChat = { setStatus: function(newStatus) { // status options are: ok, retrying, waiting - if (this.requestStatus !== 'retrying' || newStatus === 'ok') { + if (!(newStatus === 'waiting' && this.requestStatus === 'retrying')) { this.requestStatus = newStatus; } - - var statusIcon = document.getElementById('statusIconContainer'); - if (statusIcon) { - switch (this.requestStatus) { - case 'ok': - this.setClass(statusIcon, 'statusContainerOff'); - break; - case 'waiting': - this.setClass(statusIcon, 'statusContainerOn'); - break; - case 'retrying': - this.setClass(statusIcon, 'statusContainerAlert'); - break; - } + if(this.dom['statusIcon']) { + this.dom['statusIcon'].className = this.requestStatus; } }, - + forceNewRequest: function() { - ajaxChat.updateChat(null); + ajaxChat.updateChat(null); ajaxChat.setStatus('retrying'); }, - + getHttpRequest: function(identifier) { if(!this.httpRequest[identifier]) { if (window.XMLHttpRequest) { @@ -760,9 +764,10 @@ var ajaxChat = { }, makeRequest: function(url, method, data) { - var identifier; - this.setStatus('waiting'); - + var self = this, + identifier; + self.setStatus('waiting'); + try { if(data) { // Create up to 50 HTTPRequest objects: @@ -776,17 +781,17 @@ var ajaxChat = { identifier = 0; } //if the response takes longer than retryTimerDelay to give an OK status, abort the connection and start again. - this.retryTimer = setTimeout(ajaxChat.forceNewRequest, ajaxChat.retryTimerDelay); - - this.getHttpRequest(identifier).open(method, url, true); - this.getHttpRequest(identifier).onreadystatechange = function() { + self.retryTimer = setTimeout(ajaxChat.forceNewRequest, ajaxChat.retryTimerDelay); + + self.getHttpRequest(identifier).open(method, url, true); + self.getHttpRequest(identifier).onreadystatechange = function() { try { ajaxChat.handleResponse(identifier); } catch(e) { try { clearTimeout(ajaxChat.timer); } catch(e) { - //alert(e); + self.debugMessage('makeRequest::clearTimeout', e); } try { if(data) { @@ -795,30 +800,30 @@ var ajaxChat = { ajaxChat.updateChatlistView(); } } catch(e) { - //alert(e); + self.debugMessage('makeRequest::logRetry', e); } - try { + try { ajaxChat.timer = setTimeout(function() { ajaxChat.updateChat(null); }, ajaxChat.timerRate); } catch(e) { - //alert(e); + self.debugMessage('makeRequest::setTimeout', e); } } }; if(method === 'POST') { - this.getHttpRequest(identifier).setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + self.getHttpRequest(identifier).setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } - this.getHttpRequest(identifier).send(data); + self.getHttpRequest(identifier).send(data); } catch(e) { clearTimeout(this.timer); if(data) { - this.addChatBotMessageToChatList('/error ConnectionTimeout'); + self.addChatBotMessageToChatList('/error ConnectionTimeout'); ajaxChat.setStatus('retrying'); - this.updateChatlistView(); + self.updateChatlistView(); } - this.timer = setTimeout(function() { ajaxChat.updateChat(null); }, this.timerRate); + self.timer = setTimeout(function() { ajaxChat.updateChat(null); }, self.timerRate); } }, - + handleResponse: function(identifier) { var xmlDoc; if (this.getHttpRequest(identifier).readyState === 4) { @@ -835,7 +840,7 @@ var ajaxChat = { } else { this.addChatBotMessageToChatList('/error ConnectionStatus '+this.getHttpRequest(identifier).status); this.setStatus('retrying'); - this.updateChatlistView(); + this.updateChatlistView(); return false; } } @@ -846,7 +851,7 @@ var ajaxChat = { this.handleXML(xmlDoc); return true; }, - + handleXML: function(xmlDoc) { this.handleInfoMessages(xmlDoc.getElementsByTagName('info')); this.handleOnlineUsers(xmlDoc.getElementsByTagName('user')); @@ -868,10 +873,10 @@ var ajaxChat = { this.socketReconnectTimer = setTimeout(ajaxChat.socketConnect, 60000); } } - this.timer = setTimeout(function() {ajaxChat.updateChat(null);}, timeout); + this.timer = setTimeout(function() {ajaxChat.updateChat(null);}, timeout); } }, - + handleInfoMessages: function(infoNodes) { var infoType, infoData; for(var i=0; i= 0 ) { isInline = true; @@ -1078,12 +1086,12 @@ var ajaxChat = { ), false, true - ) + ); } this.showHide(menuID); this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight; }, - + getUserNodeStringItems: function(encodedUserName, userID, isInline) { var menu; if(encodedUserName !== this.encodedUserName) { @@ -1175,19 +1183,19 @@ var ajaxChat = { menu += this.getCustomUserMenuItems(encodedUserName, userID); return menu; }, - + setOnlineListRowClasses: function() { if(this.dom['onlineList']) { - var node = this.dom['onlineList'].firstChild; + var node = this.dom['onlineList'].firstChild; var rowEven = false; while(node) { - this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd')); + node.className = (rowEven ? 'rowEven' : 'rowOdd'); node = node.nextSibling; rowEven = !rowEven; } } }, - + clearChatList: function() { while(this.dom['chatList'].hasChildNodes()) { this.dom['chatList'].removeChild(this.dom['chatList'].firstChild); @@ -1210,7 +1218,7 @@ var ajaxChat = { } return arguments.callee.encodedChatBotName; }, - + addChatBotMessageToChatList: function(messageText) { this.addMessageToChatList( new Date(), @@ -1222,17 +1230,17 @@ var ajaxChat = { null ); }, - + addMessageToChatList: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) { // Prevent adding the same message twice: if(this.getMessageNode(messageID)) { return; - } + } if(!this.onNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) { return; } this.DOMbufferRowClass = this.DOMbufferRowClass === 'rowEven' ? 'rowOdd' : 'rowEven'; - this.DOMbuffer = this.DOMbuffer + + this.DOMbuffer = this.DOMbuffer + this.getChatListMessageString( dateObject, userID, userName, userRole, messageID, messageText, channelID, ip ); @@ -1243,15 +1251,17 @@ var ajaxChat = { }, getChatListMessageString: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) { - var rowClass = this.DOMbufferRowClass; - var userClass = this.getRoleClass(userRole); - var colon; + var rowClass = this.DOMbufferRowClass, + userClass = this.getRoleClass(userRole), + colon = ': '; if(messageText.indexOf('/action') === 0 || messageText.indexOf('/me') === 0 || messageText.indexOf('/privaction') === 0) { userClass += ' action'; colon = ' '; - } else { - colon = ': '; } + if (messageText.indexOf('/privmsg') === 0 || messageText.indexOf('/privmsgto') === 0 || messageText.indexOf('/privaction') === 0) { + rowClass += ' private'; + } + var dateTime = this.settings['dateFormat'] ? '' + this.formatDate(this.settings['dateFormat'], dateObject) + ' ' : ''; return '
this.settings['maxMessages']) { this.dom['chatList'].removeChild(this.dom['chatList'].firstChild); } } - + if(this.settings['autoScroll']) { - this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight; + var self = this; + setTimeout(function() { self.scrollChatList(); }, 50); } }, - + + scrollChatList: function() { + this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight; + }, + encodeText: function(text) { return encodeURIComponent(text); }, @@ -1459,7 +1477,7 @@ var ajaxChat = { this.encodeSpecialCharsCallback ); }, - + encodeSpecialCharsCallback: function(str) { switch(str) { case '&': @@ -1480,13 +1498,13 @@ var ajaxChat = { decodeSpecialChars: function(text) { var regExp = new RegExp('(&)|(<)|(>)|(')|(")', 'g'); - + return text.replace( regExp, this.decodeSpecialCharsCallback ); }, - + decodeSpecialCharsCallback: function(str) { switch(str) { case '&': @@ -1503,7 +1521,7 @@ var ajaxChat = { return str; } }, - + inArray: function(haystack, needle) { var i = haystack.length; while(i--) { @@ -1515,20 +1533,24 @@ var ajaxChat = { }, arraySearch: function(needle, haystack) { - var i = haystack.length; - while(i--) { - if(haystack[i] === needle) { - return i; + if (!Array.prototype.indexOf) { // IE<9 + var i = haystack.length; + while(i--) { + if(haystack[i] === needle) { + return i; + } } + return -1; + } else { + return haystack.indexOf(needle); } - return false; }, stripTags: function(str) { if (!arguments.callee.regExp) { arguments.callee.regExp = new RegExp('<\\/?[^>]+?>', 'g'); } - + return str.replace(arguments.callee.regExp, ''); }, @@ -1536,9 +1558,9 @@ var ajaxChat = { if (!arguments.callee.regExp) { arguments.callee.regExp = new RegExp('\\[\\/?[^\\]]+?\\]', 'g'); } - + return str.replace(arguments.callee.regExp, ''); - }, + }, escapeRegExp: function(text) { if (!arguments.callee.regExp) { @@ -1552,7 +1574,7 @@ var ajaxChat = { } return text.replace(arguments.callee.regExp, '\\$1'); }, - + addSlashes: function(text) { // Adding slashes in front of apostrophs and backslashes to ensure a valid JavaScript expression: return text.replace(/\\/g, '\\\\').replace(/\'/g, '\\\''); @@ -1564,8 +1586,8 @@ var ajaxChat = { }, formatDate: function(format, date) { - date = (date == null) ? new date() : date; - + date = (date === null) ? new date() : date; + return format .replace(/%Y/g, date.getFullYear()) .replace(/%m/g, this.addLeadingZero(date.getMonth()+1)) @@ -1574,7 +1596,7 @@ var ajaxChat = { .replace(/%i/g, this.addLeadingZero(date.getMinutes())) .replace(/%s/g, this.addLeadingZero(date.getSeconds())); }, - + addLeadingZero: function(number) { number = number.toString(); if(number.length < 2) { @@ -1585,7 +1607,7 @@ var ajaxChat = { getUserIDFromUserName: function(userName) { var index = this.arraySearch(userName, this.userNamesList); - if(index !== false) { + if(index !== -1) { return this.usersList[index]; } return null; @@ -1593,7 +1615,7 @@ var ajaxChat = { getUserNameFromUserID: function(userID) { var index = this.arraySearch(userID, this.usersList); - if(index !== false) { + if(index !== -1) { return this.userNamesList[index]; } return null; @@ -1611,14 +1633,41 @@ var ajaxChat = { return 'admin'; case 4: return 'chatBot'; + case 5: + return 'customUser'; default: return 'default'; } }, - - handleInputFieldKeyPress: function(event) { + + handleInputFieldKeyDown: function(event) { + var text, lastWord, i; + + // Enter key without shift should send messages if(event.keyCode === 13 && !event.shiftKey) { this.sendMessage(); + try { + event.preventDefault(); + } catch(e) { + event.returnValue = false; // IE<9 + } + return false; + } + // Tab should complete usernames + else if(event.keyCode === 9 && !event.shiftKey) { + text = this.dom['inputField'].value; + if(text) { + lastWord = text.match(/\w+/g).slice(-1)[0]; + + if (lastWord.length > 2) { + for (i = 0; i < this.userNamesList.length; i++) { + if(this.userNamesList[i].replace("(","").toLowerCase().indexOf(lastWord.toLowerCase()) === 0) { + this.dom['inputField'].value = text.replace(new RegExp(lastWord + '$'), this.userNamesList[i]); + break; + } + } + } + } try { event.preventDefault(); } catch(e) { @@ -1632,7 +1681,7 @@ var ajaxChat = { handleInputFieldKeyUp: function(event) { this.updateMessageLengthCounter(); }, - + updateMessageLengthCounter: function() { if(this.dom['messageLengthCounter']) { this.updateDOM( @@ -1643,7 +1692,7 @@ var ajaxChat = { ); } }, - + sendMessage: function(text) { text = text ? text : this.dom['inputField'].value; if(!text) { @@ -1655,14 +1704,14 @@ var ajaxChat = { var message = 'lastID=' + this.lastID + '&text=' - + this.encodeText(text); + + this.encodeText(text); this.makeRequest(this.ajaxURL,'POST',message); } this.dom['inputField'].value = ''; this.dom['inputField'].focus(); this.updateMessageLengthCounter(); }, - + parseInputMessage: function(text) { var textParts; if(text.charAt(0) === '/') { @@ -1689,7 +1738,7 @@ var ajaxChat = { } return text; }, - + assignFontColorToMessage: function(text) { return '[color='+this.settings['fontColor']+']'+text+'[/color]'; }, @@ -1717,7 +1766,7 @@ var ajaxChat = { } return text; }, - + parseIgnoreInputCommand: function(text, textParts) { var userName, ignoredUserNames = this.getIgnoredUserNames(), i; if(textParts.length > 1) { @@ -1765,12 +1814,12 @@ var ajaxChat = { } return this.ignoredUserNames; }, - + setIgnoredUserNames: function(ignoredUserNames) { this.ignoredUserNames = ignoredUserNames; this.setSetting('ignoredUserNames', ignoredUserNames.join(' ')); }, - + ignoreMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) { var textParts; if(userID === this.chatBotID && messageText.charAt(0) === '/') { @@ -1782,7 +1831,7 @@ var ajaxChat = { case '/roll': userName = textParts[1]; break; - } + } } } if(this.inArray(this.getIgnoredUserNames(), userName)) { @@ -1794,8 +1843,8 @@ var ajaxChat = { deleteMessage: function(messageID) { var messageNode = this.getMessageNode(messageID), originalClass, nextSibling; if(messageNode) { - originalClass = this.getClass(messageNode); - this.setClass(messageNode, originalClass+' deleteSelected'); + originalClass = messageNode.className; + this.addClass(messageNode, 'deleteSelected'); if(confirm(this.lang['deleteMessageConfirm'])) { nextSibling = messageNode.nextSibling; try { @@ -1805,10 +1854,10 @@ var ajaxChat = { } this.updateChat('&delete='+messageID); } catch(e) { - this.setClass(messageNode, originalClass); + messageNode.className = originalClass; } } else { - this.setClass(messageNode, originalClass); + messageNode.className = originalClass; } } }, @@ -1820,35 +1869,45 @@ var ajaxChat = { } if(node) { previousNode = node.previousSibling; - rowEven = (previousNode && this.getClass(previousNode) === 'rowOdd') ? true : false; + rowEven = (previousNode && previousNode.className === 'rowOdd') ? true : false; while(node) { - this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd')); + node.className = (rowEven ? 'rowEven' : 'rowOdd'); node = node.nextSibling; rowEven = !rowEven; } } }, - - getClass: function(node) { - if(typeof node.className !== 'undefined') { - return node.className; // IE + + addEvent: function(elem, type, eventHandle) { + if (!elem) + return; + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); } else { - return node.getAttribute('class'); + elem["on"+type]=eventHandle; } }, - - setClass: function(node, className) { - if(typeof node.className !== 'undefined') { - node.className = className; // IE - } else { - node.setAttribute('class', className); + + addClass: function(node, theClass) { + if (!this.hasClass(node, theClass)) { + node.className += ' ' + theClass; } }, + removeClass: function(node, theClass) { + node.className = node.className.replace( new RegExp('(?:^|\\s)' + theClass + '(?!\\S)', 'g') , '' ); + }, + + hasClass: function(node, theClass) { + return node.className.match(new RegExp('\\b' + theClass + '\\b')); + }, + scriptLinkEncode: function(text) { return this.encodeText(this.addSlashes(this.decodeSpecialChars(text))); }, - + scriptLinkDecode: function(text) { return this.encodeSpecialChars(this.removeSlashes(this.decodeText(text))); }, @@ -1865,9 +1924,9 @@ var ajaxChat = { default: arguments.callee.utf8Decode = false; return value; - } + } } else if(arguments.callee.utf8Decode) { - return this.utf8Decode(value); + return this.utf8Decode(value); } else { return value; } @@ -1880,7 +1939,7 @@ var ajaxChat = { insertMessageWrapper: function(text) { this.insertText(this.getScriptLinkValue(text), true); }, - + switchChannel: function(channel) { if(!this.chatStarted) { this.clearChatList(); @@ -1890,11 +1949,11 @@ var ajaxChat = { this.requestTeaserContent(); return; } - clearTimeout(this.timer); + clearTimeout(this.timer); var message = 'lastID=' + this.lastID + '&channelName=' - + this.encodeText(channel); + + this.encodeText(channel); this.makeRequest(this.ajaxURL,'POST',message); if(this.dom['inputField'] && this.settings['autoFocus']) { this.dom['inputField'].focus(); @@ -1906,7 +1965,7 @@ var ajaxChat = { var message = 'logout=true'; this.makeRequest(this.ajaxURL,'POST',message); }, - + handleLogout: function(url) { window.location.href = url; }, @@ -1921,10 +1980,10 @@ var ajaxChat = { updateButton: function(setting, buttonID) { var node = document.getElementById(buttonID); if(node) { - this.setClass(node, (this.getSetting(setting) ? 'button' : 'button off')); + node.className = (this.getSetting(setting) ? 'button' : 'button off'); } }, - + showHide: function(id, styleDisplay, displayInline) { var node = document.getElementById(id); if(node) { @@ -1932,16 +1991,16 @@ var ajaxChat = { node.style.display = styleDisplay; } else { if(node.style.display === 'none') { - node.style.display = (displayInline ? 'inline' : 'block'); + node.style.display = (displayInline ? 'inline' : 'block'); } else { node.style.display = 'none'; } - } + } } }, setPersistFontColor: function(bool) { - this.settings['persistFontColor'] = bool; + this.settings['persistFontColor'] = bool; if(!this.settings['persistFontColor']) { this.settings['fontColor'] = null; if(this.dom['inputField']) { @@ -1966,16 +2025,16 @@ var ajaxChat = { this.insert('[color=' + color + ']', '[/color]'); } }, - + insertText: function(text, clearInputField) { if(clearInputField) { this.dom['inputField'].value = ''; } this.insert(text, ''); }, - + insertBBCode: function(bbCode) { - switch(bbCode) { + switch(bbCode) { case 'url': var url = prompt(this.lang['urlDialog'], 'http://'); if(url) @@ -1984,7 +2043,7 @@ var ajaxChat = { this.dom['inputField'].focus(); break; default: - this.insert('[' + bbCode + ']', '[/' + bbCode + ']'); + this.insert('[' + bbCode + ']', '[/' + bbCode + ']'); } }, @@ -2001,7 +2060,7 @@ var ajaxChat = { if (insText.length === 0) { range.move('character', -endTag.length); } else { - range.moveStart('character', startTag.length + insText.length + endTag.length); + range.moveStart('character', startTag.length + insText.length + endTag.length); } range.select(); } @@ -2035,7 +2094,7 @@ var ajaxChat = { + this.dom['inputField'].value.substr(pos); } }, - + replaceText: function(text) { try{ text = this.replaceLineBreaks(text); @@ -2046,20 +2105,20 @@ var ajaxChat = { text = this.replaceHyperLinks(text); text = this.replaceEmoticons(text); } - text = this.breakLongWords(text); + text = this.breakLongWords(text); text = this.replaceCustomText(text); } catch(e){ - //alert(e); + this.debugMessage('replaceText', e); } return text; }, - + replaceCommands: function(text) { try { if(text.charAt(0) !== '/') { return text; } - var textParts = text.split(' '); + var textParts = text.split(' '); switch(textParts[0]) { case '/login': return this.replaceCommandLogin(textParts); @@ -2130,7 +2189,7 @@ var ajaxChat = { return this.replaceCustomCommands(text, textParts); } } catch(e) { - //alert(e); + this.debugMessage('replaceCommands', e); } return text; }, @@ -2138,7 +2197,7 @@ var ajaxChat = { replaceCommandLogin: function(textParts) { return '' + this.lang['login'].replace(/%s/, textParts[1]) - + ''; + + ''; }, replaceCommandLogout: function(textParts) { @@ -2147,21 +2206,21 @@ var ajaxChat = { type = textParts[2]; return '' + this.lang['logout' + type].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandChannelEnter: function(textParts) { return '' + this.lang['channelEnter'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandChannelLeave: function(textParts) { return '' + this.lang['channelLeave'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandPrivMsg: function(textParts) { var privMsgText = textParts.slice(1).join(' '); privMsgText = this.replaceBBCode(privMsgText); @@ -2172,7 +2231,7 @@ var ajaxChat = { + ' ' + privMsgText; }, - + replaceCommandPrivMsgTo: function(textParts) { var privMsgText = textParts.slice(2).join(' '); privMsgText = this.replaceBBCode(privMsgText); @@ -2183,7 +2242,7 @@ var ajaxChat = { + ' ' + privMsgText; }, - + replaceCommandPrivAction: function(textParts) { var privActionText = textParts.slice(1).join(' '); privActionText = this.replaceBBCode(privActionText); @@ -2195,7 +2254,7 @@ var ajaxChat = { + this.lang['privmsg'] + ' '; }, - + replaceCommandPrivActionTo: function(textParts) { var privActionText = textParts.slice(2).join(' '); privActionText = this.replaceBBCode(privActionText); @@ -2205,9 +2264,9 @@ var ajaxChat = { + privActionText + ' ' + this.lang['privmsgto'].replace(/%s/, textParts[1]) - + ' '; + + ' '; }, - + replaceCommandAction: function(textParts) { var actionText = textParts.slice(1).join(' '); actionText = this.replaceBBCode(actionText); @@ -2215,9 +2274,9 @@ var ajaxChat = { actionText = this.replaceEmoticons(actionText); return '' + actionText - + ''; + + ''; }, - + replaceCommandInvite: function(textParts) { var inviteText = this.lang['invite'] .replace(/%s/, textParts[1]) @@ -2233,99 +2292,99 @@ var ajaxChat = { ); return '' + inviteText - + ''; + + ''; }, - + replaceCommandInviteTo: function(textParts) { var inviteText = this.lang['inviteto'] .replace(/%s/, textParts[1]) .replace(/%s/, textParts[2]); return '' + inviteText - + ''; + + ''; }, - + replaceCommandUninvite: function(textParts) { var uninviteText = this.lang['uninvite'] .replace(/%s/, textParts[1]) .replace(/%s/, textParts[2]); return '' + uninviteText - + ''; + + ''; }, - + replaceCommandUninviteTo: function(textParts) { var uninviteText = this.lang['uninviteto'] .replace(/%s/, textParts[1]) .replace(/%s/, textParts[2]); return '' + uninviteText - + ''; + + ''; }, - + replaceCommandQueryOpen: function(textParts) { return '' + this.lang['queryOpen'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandQueryClose: function(textParts) { return '' + this.lang['queryClose'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandIgnoreAdded: function(textParts) { return '' + this.lang['ignoreAdded'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandIgnoreRemoved: function(textParts) { return '' + this.lang['ignoreRemoved'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandIgnoreList: function(textParts) { return '' + this.lang['ignoreList'] + ' ' + this.getInlineUserMenu(textParts.slice(1)) - + ''; + + ''; }, - + replaceCommandIgnoreListEmpty: function(textParts) { return '' + this.lang['ignoreListEmpty'] - + ''; + + ''; }, - + replaceCommandKick: function(textParts) { return '' + this.lang['logoutKicked'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandWho: function(textParts) { return '' + this.lang['who'] + ' ' + this.getInlineUserMenu(textParts.slice(1)) - + ''; + + ''; }, replaceCommandWhoChannel: function(textParts) { return '' + this.lang['whoChannel'].replace(/%s/, textParts[1]) + ' ' + this.getInlineUserMenu(textParts.slice(2)) - + ''; + + ''; }, - + replaceCommandWhoEmpty: function(textParts) { return '' + this.lang['whoEmpty'] - + ''; + + ''; }, - + replaceCommandList: function(textParts) { var channels = textParts.slice(1); var listChannels = []; @@ -2345,9 +2404,9 @@ var ajaxChat = { return '' + this.lang['list'] + ' ' + listChannels.join(', ') - + ''; + + ''; }, - + replaceCommandBans: function(textParts) { var users = textParts.slice(1); var listUsers = []; @@ -2365,26 +2424,26 @@ var ajaxChat = { return '' + this.lang['bans'] + ' ' + listUsers.join(', ') - + ''; + + ''; }, - + replaceCommandBansEmpty: function(textParts) { return '' + this.lang['bansEmpty'] - + ''; + + ''; }, - + replaceCommandUnban: function(textParts) { return '' + this.lang['unban'].replace(/%s/, textParts[1]) - + ''; + + ''; }, - + replaceCommandWhois: function(textParts) { return '' + this.lang['whois'].replace(/%s/, textParts[1]) + ' ' + textParts[2] - + ''; + + ''; }, replaceCommandWhereis: function(textParts) { @@ -2399,24 +2458,24 @@ var ajaxChat = { + textParts[2] + '' ) - + ''; + + ''; }, - + replaceCommandRoll: function(textParts) { var rollText = this.lang['roll'].replace(/%s/, textParts[1]); rollText = rollText.replace(/%s/, textParts[2]); rollText = rollText.replace(/%s/, textParts[3]); return '' + rollText - + ''; + + ''; }, - + replaceCommandNick: function(textParts) { return '' + this.lang['nick'].replace(/%s/, textParts[1]).replace(/%s/, textParts[2]) - + ''; + + ''; }, - + replaceCommandError: function(textParts) { var errorMessage = this.lang['error'+textParts[1]]; if(!errorMessage) { @@ -2426,7 +2485,7 @@ var ajaxChat = { } return '' + errorMessage - + ''; + + ''; }, getInlineUserMenu: function(users) { @@ -2459,7 +2518,7 @@ var ajaxChat = { var openTags, closeTags, regExpOpenTags = /<[^>\/]+?>/gm, regExpCloseTags = /<\/[^>]+?>/gm; - + openTags = str.match(regExpOpenTags); closeTags = str.match(regExpCloseTags); // Return true if the number of tags doesn't match: @@ -2470,32 +2529,32 @@ var ajaxChat = { } return false; }, - + breakLongWords: function(text) { var newText, charCounter, currentChar, withinTag, withinEntity, i; - + if(!this.settings['wordWrap']) return text; - + newText = ''; charCounter = 0; - + for(i=0; i): if(i>5 && text.substr(i-5,4) === '
0 && text.charAt(i-1) === '>') { withinTag = false; // Reset the charCounter after newline tags (
): if(i>4 && text.substr(i-5,4) === '
0 && text.charAt(i-1) === ';') { @@ -2503,7 +2562,7 @@ var ajaxChat = { // We only increase the charCounter once for the whole entiy: charCounter++; } - + if(!withinTag && !withinEntity) { // Reset the charCounter if we encounter a word boundary: if(currentChar === ' ' || currentChar === '\n' || currentChar === '\t') { @@ -2517,14 +2576,14 @@ var ajaxChat = { newText += '​'; charCounter = 0; } - } + } // Add the current char to the text: newText += currentChar; } - + return newText; }, - + replaceBBCode: function(text) { if(!this.settings['bbCode']) { // If BBCode is disabled, just strip the text from BBCode tags: @@ -2532,11 +2591,11 @@ var ajaxChat = { } // Remove the BBCode tags: return text.replace( - /\[(\w+)(?:=([^<>]*?))?\](.+?)\[\/\1\]/gm, + /\[(\w+)(?:=([^<>]*?))?\](.+?)\[\/\1\]/gm, this.replaceBBCodeCallback ); }, - + replaceBBCodeCallback: function(str, p1, p2, p3) { // Only replace predefined BBCode tags: if(!ajaxChat.inArray(ajaxChat.bbCodeTags, p1)) { @@ -2545,7 +2604,7 @@ var ajaxChat = { // Avoid invalid XHTML (unclosed tags): if(ajaxChat.containsUnclosedTags(p3)) { return str; - } + } switch(p1) { case 'color': return ajaxChat.replaceBBCodeColor(p3, p2); @@ -2568,7 +2627,7 @@ var ajaxChat = { if(this.settings['bbCodeColors']) { // Only allow predefined color codes: if(!attribute || !this.inArray(ajaxChat.colorCodes, attribute)) - return content; + return content; return '' + this.replaceBBCode(content) @@ -2576,9 +2635,9 @@ var ajaxChat = { } return content; }, - + replaceBBCodeUrl: function(content, attribute) { - var url, regExpUrl; + var url, regExpUrl, link; if(attribute) url = attribute.replace(/\s/gm, this.encodeText(' ')); else @@ -2589,15 +2648,19 @@ var ajaxChat = { ); if(!url || !url.match(regExpUrl)) return content; - return '' + this.replaceBBCode(content) + ''; + this.inUrlBBCode = false; + return link; }, - + replaceBBCodeImage: function(url) { - var regExpUrl, maxWidth, maxHeight; + var regExpUrl, maxWidth, maxHeight, link; if(this.settings['bbCodeImages']) { regExpUrl = new RegExp( this.regExpMediaUrl, @@ -2605,19 +2668,24 @@ var ajaxChat = { ); if(!url || !url.match(regExpUrl)) return url; - url = url.replace(/\s/gm, this.encodeText(' ')); + url = this.stripTags(url.replace(/\s/gm, this.encodeText(' '))); maxWidth = this.dom['chatList'].offsetWidth-50; maxHeight = this.dom['chatList'].offsetHeight-50; - return '' - +''; + link = ''; + if(!this.inUrlBBCode) { + link = '' + + link + + ''; + } + return link; } return url; }, @@ -2640,13 +2708,13 @@ var ajaxChat = { + this.replaceBBCode(content.replace(/\t|(?: )/gm, '  ')) + ''; }, - + replaceBBCodeUnderline: function(content) { return '' + this.replaceBBCode(content) + ''; }, - + replaceHyperLinks: function(text) { var regExp; if(!this.settings['hyperLinks']) { @@ -2699,11 +2767,11 @@ var ajaxChat = { arguments.callee.regExp = new RegExp(regExpStr, 'gm'); } return text.replace( - arguments.callee.regExp, + arguments.callee.regExp, this.replaceEmoticonsCallback ); }, - + replaceEmoticonsCallback: function(str, p1, p2, p3) { if (!arguments.callee.regExp) { arguments.callee.regExp = new RegExp('(="[^"]*$)|(&[^;]*$)', ''); @@ -2711,9 +2779,9 @@ var ajaxChat = { // Avoid replacing emoticons in tag attributes or XHTML entities: if(p1.match(arguments.callee.regExp)) { return str; - } + } if(p2) { - var index = ajaxChat.arraySearch(p2, ajaxChat.emoticonCodes); + var index = ajaxChat.arraySearch(p2, ajaxChat.emoticonCodes); return ajaxChat.replaceEmoticons(p1) + '_config = &$config; - - // Initialize custom configuration settings: - $this->initCustomConfig(); - } - - function initRequestVars() { - $this->_requestVars = array(); - $this->_requestVars['ajax'] = isset($_REQUEST['ajax']) ? true : false; - $this->_requestVars['userID'] = isset($_REQUEST['userID']) ? (int)$_REQUEST['userID'] : null; - $this->_requestVars['userName'] = isset($_REQUEST['userName']) ? $_REQUEST['userName'] : null; - $this->_requestVars['channelID'] = isset($_REQUEST['channelID']) ? (int)$_REQUEST['channelID'] : null; - $this->_requestVars['channelName'] = isset($_REQUEST['channelName']) ? $_REQUEST['channelName'] : null; - $this->_requestVars['text'] = isset($_POST['text']) ? $_POST['text'] : null; - $this->_requestVars['lastID'] = isset($_REQUEST['lastID']) ? (int)$_REQUEST['lastID'] : 0; - $this->_requestVars['login'] = isset($_REQUEST['login']) ? true : false; - $this->_requestVars['logout'] = isset($_REQUEST['logout']) ? true : false; - $this->_requestVars['password'] = isset($_REQUEST['password']) ? $_REQUEST['password'] : null; - $this->_requestVars['view'] = isset($_REQUEST['view']) ? $_REQUEST['view'] : null; - $this->_requestVars['year'] = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null; - $this->_requestVars['month'] = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null; - $this->_requestVars['day'] = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null; - $this->_requestVars['hour'] = isset($_REQUEST['hour']) ? (int)$_REQUEST['hour'] : null; - $this->_requestVars['search'] = isset($_REQUEST['search']) ? $_REQUEST['search'] : null; - $this->_requestVars['shoutbox'] = isset($_REQUEST['shoutbox']) ? true : false; - $this->_requestVars['getInfos'] = isset($_REQUEST['getInfos']) ? $_REQUEST['getInfos'] : null; - $this->_requestVars['lang'] = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : null; - $this->_requestVars['delete'] = isset($_REQUEST['delete']) ? (int)$_REQUEST['delete'] : null; - - // Initialize custom request variables: - $this->initCustomRequestVars(); - - // Remove slashes which have been added to user input strings if magic_quotes_gpc is On: - if(get_magic_quotes_gpc()) { - // It is safe to remove the slashes as we escape user data ourself - array_walk( - $this->_requestVars, - create_function( - '&$value, $key', - 'if(is_string($value)) $value = stripslashes($value);' - ) - ); - } - } - - function initDataBaseConnection() { - // Create a new database object: - $this->db = new AJAXChatDataBase( - $this->_config['dbConnection'] - ); - // Use a new database connection if no existing is given: - if(!$this->_config['dbConnection']['link']) { - // Connect to the database server: - $this->db->connect($this->_config['dbConnection']); - if($this->db->error()) { - echo $this->db->getError(); - die(); - } - // Select the database: - $this->db->select($this->_config['dbConnection']['name']); - if($this->db->error()) { - echo $this->db->getError(); - die(); - } - } - // Unset the dbConnection array for safety purposes: - unset($this->_config['dbConnection']); - } - - function getDataBaseTable($table) { - return ($this->db->getName() ? '`'.$this->db->getName().'`.'.$this->getConfig('dbTableNames',$table) : $this->getConfig('dbTableNames',$table)); - } - - function initSession() { - // Start the PHP session (if not already started): - $this->startSession(); - - if($this->isLoggedIn()) { - // Logout if we receive a logout request, the chat has been closed or the userID could not be revalidated: - if($this->getRequestVar('logout') || !$this->isChatOpen() || !$this->revalidateUserID()) { - $this->logout(); - return; - } - // Logout if the Session IP is not the same when logged in and ipCheck is enabled: - if($this->getConfig('ipCheck') && ($this->getSessionIP() === null || $this->getSessionIP() != $_SERVER['REMOTE_ADDR'])) { - $this->logout('IP'); - return; - } - } else if( - // Login if auto-login enabled or a login, userName or shoutbox parameter is given: - $this->getConfig('forceAutoLogin') || - $this->getRequestVar('login') || - $this->getRequestVar('userName') || - $this->getRequestVar('shoutbox') - ) { - $this->login(); - } - - // Initialize the view: - $this->initView(); - - if($this->getView() == 'chat') { - $this->initChatViewSession(); - } else if($this->getView() == 'logs') { - $this->initLogsViewSession(); - } - - if(!$this->getRequestVar('ajax') && !headers_sent()) { - // Set style cookie: - $this->setStyle(); - // Set langCode cookie: - $this->setLangCodeCookie(); - } - - $this->initCustomSession(); - } - - function initLogsViewSession() { - if($this->getConfig('socketServerEnabled')) { - if(!$this->getSessionVar('logsViewSocketAuthenticated')) { - $this->updateLogsViewSocketAuthentication(); - $this->setSessionVar('logsViewSocketAuthenticated', true); - } - } - } - - function updateLogsViewSocketAuthentication() { - if($this->getUserRole() != AJAX_CHAT_ADMIN) { - $channels = array(); - foreach($this->getChannels() as $channel) { - if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) { - continue; - } - array_push($channels, $channel); - } - array_push($channels, $this->getPrivateMessageID()); - array_push($channels, $this->getPrivateChannelID()); - } else { - // The channelID "ALL" authenticates for all channels: - $channels = array('ALL'); - } - $this->updateSocketAuthentication( - $this->getUserID(), - $this->getSocketRegistrationID(), - $channels - ); - } - - function initChatViewSession() { - // If channel is not null we are logged in to the chat view: - if($this->getChannel() !== null) { - // Check if the current user has been logged out due to inactivity: - if(!$this->isUserOnline()) { - $this->logout(); - return; - } - if($this->getRequestVar('ajax')) { - $this->initChannel(); - $this->updateOnlineStatus(); - $this->checkAndRemoveInactive(); - } - } else { - if($this->getRequestVar('ajax')) { - // Set channel, insert login messages and add to online list on first ajax request in chat view: - $this->chatViewLogin(); - } - } - } - - function isChatOpen() { - if($this->getUserRole() == AJAX_CHAT_ADMIN) - return true; - if($this->getConfig('chatClosed')) - return false; - $time = time(); - if($this->getConfig('timeZoneOffset') !== null) { - // Subtract the server timezone offset and add the config timezone offset: - $time -= date('Z', $time); - $time += $this->getConfig('timeZoneOffset'); - } - // Check the opening hours: - if($this->getConfig('openingHour') < $this->getConfig('closingHour')) - { - if(($this->getConfig('openingHour') > date('G', $time)) || ($this->getConfig('closingHour') <= date('G', $time))) - return false; - } - else - { - if(($this->getConfig('openingHour') > date('G', $time)) && ($this->getConfig('closingHour') <= date('G', $time))) - return false; - } - // Check the opening weekdays: - if(!in_array(date('w', $time), $this->getConfig('openingWeekDays'))) - return false; - return true; - } - - function handleRequest() { - if($this->getRequestVar('ajax')) { - if($this->isLoggedIn()) { - // Parse info requests (for current userName, etc.): - $this->parseInfoRequests(); - - // Parse command requests (e.g. message deletion): - $this->parseCommandRequests(); - - // Parse message requests: - $this->initMessageHandling(); - } - // Send chat messages and online user list in XML format: - $this->sendXMLMessages(); - } else { - // Display XHTML content for non-ajax requests: - $this->sendXHTMLContent(); - } - } - - function parseCommandRequests() { - if($this->getRequestVar('delete') !== null) { - $this->deleteMessage($this->getRequestVar('delete')); - } - } - - function parseInfoRequests() { - if($this->getRequestVar('getInfos')) { - $infoRequests = explode(',', $this->getRequestVar('getInfos')); - foreach($infoRequests as $infoRequest) { - $this->parseInfoRequest($infoRequest); - } - } - } - - function parseInfoRequest($infoRequest) { - switch($infoRequest) { - case 'userID': - $this->addInfoMessage($this->getUserID(), 'userID'); - break; - case 'userName': - $this->addInfoMessage($this->getUserName(), 'userName'); - break; - case 'userRole': - $this->addInfoMessage($this->getUserRole(), 'userRole'); - break; - case 'channelID': - $this->addInfoMessage($this->getChannel(), 'channelID'); - break; - case 'channelName': - $this->addInfoMessage($this->getChannelName(), 'channelName'); - break; - case 'socketRegistrationID': - $this->addInfoMessage($this->getSocketRegistrationID(), 'socketRegistrationID'); - break; - default: - $this->parseCustomInfoRequest($infoRequest); - } - } - - function sendXHTMLContent() { - $httpHeader = new AJAXChatHTTPHeader($this->getConfig('contentEncoding'), $this->getConfig('contentType')); - - $template = new AJAXChatTemplate($this, $this->getTemplateFileName(), $httpHeader->getContentType()); - - // Send HTTP header: - $httpHeader->send(); - - // Send parsed template content: - echo $template->getParsedContent(); - } - - function getTemplateFileName() { - switch($this->getView()) { - case 'chat': - return AJAX_CHAT_PATH.'lib/template/loggedIn.html'; - case 'logs': - return AJAX_CHAT_PATH.'lib/template/logs.html'; - default: - return AJAX_CHAT_PATH.'lib/template/loggedOut.html'; - } - } - - function initView() { - $this->_view = null; - // "chat" is the default view: - $view = ($this->getRequestVar('view') === null) ? 'chat' : $this->getRequestVar('view'); - if($this->hasAccessTo($view)) { - $this->_view = $view; - } - } - - function getView() { - return $this->_view; - } - - function hasAccessTo($view) { - switch($view) { - case 'chat': - case 'teaser': - if($this->isLoggedIn()) { - return true; - } - return false; - case 'logs': - if($this->isLoggedIn() && ($this->getUserRole() == AJAX_CHAT_ADMIN || - ($this->getConfig('logsUserAccess') && - ($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_USER)) - )) { - return true; - } - return false; - default: - return false; - } - } - - function login() { - // Retrieve valid login user data (from request variables or session data): - $userData = $this->getValidLoginUserData(); - - if(!$userData) { - $this->addInfoMessage('errorInvalidUser'); - return false; - } - - // If the chat is closed, only the admin may login: - if(!$this->isChatOpen() && $userData['userRole'] != AJAX_CHAT_ADMIN) { - $this->addInfoMessage('errorChatClosed'); - return false; - } - - if(!$this->getConfig('allowGuestLogins') && $userData['userRole'] == AJAX_CHAT_GUEST) { - return false; - } - - // Check if userID or userName are already listed online: - if($this->isUserOnline($userData['userID']) || $this->isUserNameInUse($userData['userName'])) { - if($userData['userRole'] == AJAX_CHAT_USER || $userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) { - // Set the registered user inactive and remove the inactive users so the user can be logged in again: - $this->setInactive($userData['userID'], $userData['userName']); - $this->removeInactive(); - } else { - $this->addInfoMessage('errorUserInUse'); - return false; - } - } - - // Check if user is banned: - if($userData['userRole'] != AJAX_CHAT_ADMIN && $this->isUserBanned($userData['userName'], $userData['userID'], $_SERVER['REMOTE_ADDR'])) { - $this->addInfoMessage('errorBanned'); - return false; - } - - // Check if the max number of users is logged in (not affecting moderators or admins): - if(!($userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) && $this->isMaxUsersLoggedIn()) { - $this->addInfoMessage('errorMaxUsersLoggedIn'); - return false; - } - - // Use a new session id (if session has been started by the chat): - $this->regenerateSessionID(); - - // Log in: - $this->setUserID($userData['userID']); - $this->setUserName($userData['userName']); - $this->setLoginUserName($userData['userName']); - $this->setUserRole($userData['userRole']); - $this->setLoggedIn(true); - $this->setLoginTimeStamp(time()); - - // IP Security check variable: - $this->setSessionIP($_SERVER['REMOTE_ADDR']); - - // The client authenticates to the socket server using a socketRegistrationID: - if($this->getConfig('socketServerEnabled')) { - $this->setSocketRegistrationID( - md5(uniqid(rand(), true)) - ); - } - - // Add userID, userName and userRole to info messages: - $this->addInfoMessage($this->getUserID(), 'userID'); - $this->addInfoMessage($this->getUserName(), 'userName'); - $this->addInfoMessage($this->getUserRole(), 'userRole'); - - // Purge logs: - if($this->getConfig('logsPurgeLogs')) { - $this->purgeLogs(); - } - - return true; - } - - function chatViewLogin() { - $this->setChannel($this->getValidRequestChannelID()); - $this->addToOnlineList(); - - // Add channelID and channelName to info messages: - $this->addInfoMessage($this->getChannel(), 'channelID'); - $this->addInfoMessage($this->getChannelName(), 'channelName'); - - // Login message: - $text = '/login '.$this->getUserName(); - $this->insertChatBotMessage( - $this->getChannel(), - $text, - null, - 1 - ); - } - - function getValidRequestChannelID() { - $channelID = $this->getRequestVar('channelID'); - $channelName = $this->getRequestVar('channelName'); - // Check the given channelID, or get channelID from channelName: - if($channelID === null) { - if($channelName !== null) { - $channelID = $this->getChannelIDFromChannelName($channelName); - // channelName might need encoding conversion: - if($channelID === null) { - $channelID = $this->getChannelIDFromChannelName( - $this->trimChannelName($channelName, $this->getConfig('contentEncoding')) - ); - } - } - } - // Validate the resulting channelID: - if(!$this->validateChannel($channelID)) { - if($this->getChannel() !== null) { - return $this->getChannel(); - } - return $this->getConfig('defaultChannelID'); - } - return $channelID; - } - - function initChannel() { - $channelID = $this->getRequestVar('channelID'); - $channelName = $this->getRequestVar('channelName'); - if($channelID !== null) { - $this->switchChannel($this->getChannelNameFromChannelID($channelID)); - } else if($channelName !== null) { - if($this->getChannelIDFromChannelName($channelName) === null) { - // channelName might need encoding conversion: - $channelName = $this->trimChannelName($channelName, $this->getConfig('contentEncoding')); - } - $this->switchChannel($channelName); - } - } - - function logout($type=null) { - // Update the socket server authentication for the user: - if($this->getConfig('socketServerEnabled')) { - $this->updateSocketAuthentication($this->getUserID()); - } - if($this->isUserOnline()) { - $this->chatViewLogout($type); - } - $this->setLoggedIn(false); - $this->destroySession(); - - // Re-initialize the view: - $this->initView(); - } - - function chatViewLogout($type) { - $this->removeFromOnlineList(); - if($type !== null) { - $type = ' '.$type; - } - // Logout message - $text = '/logout '.$this->getUserName().$type; - $this->insertChatBotMessage( - $this->getChannel(), - $text, - null, - 1 - ); - } - - function switchChannel($channelName) { - $channelID = $this->getChannelIDFromChannelName($channelName); - - if($channelID !== null && $this->getChannel() == $channelID) { - // User is already in the given channel, return: - return; - } - - // Check if we have a valid channel: - if(!$this->validateChannel($channelID)) { - // Invalid channel: - $text = '/error InvalidChannelName '.$channelName; - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - $text - ); - return; - } - - $oldChannel = $this->getChannel(); - - $this->setChannel($channelID); - $this->updateOnlineList(); - - // Channel leave message - $text = '/channelLeave '.$this->getUserName(); - $this->insertChatBotMessage( - $oldChannel, - $text, - null, - 1 - ); - - // Channel enter message - $text = '/channelEnter '.$this->getUserName(); - $this->insertChatBotMessage( - $this->getChannel(), - $text, - null, - 1 - ); - - $this->addInfoMessage($channelName, 'channelSwitch'); - $this->addInfoMessage($channelID, 'channelID'); - $this->_requestVars['lastID'] = 0; - } - - function addToOnlineList() { - $sql = 'INSERT INTO '.$this->getDataBaseTable('online').'( - userID, - userName, - userRole, - channel, - dateTime, - ip - ) - VALUES ( - '.$this->db->makeSafe($this->getUserID()).', - '.$this->db->makeSafe($this->getUserName()).', - '.$this->db->makeSafe($this->getUserRole()).', - '.$this->db->makeSafe($this->getChannel()).', - NOW(), - '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).' - );'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $this->resetOnlineUsersData(); - } - - function removeFromOnlineList() { - $sql = 'DELETE FROM - '.$this->getDataBaseTable('online').' - WHERE - userID = '.$this->db->makeSafe($this->getUserID()).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $this->removeUserFromOnlineUsersData(); - } - - function updateOnlineList() { - $sql = 'UPDATE - '.$this->getDataBaseTable('online').' - SET - userName = '.$this->db->makeSafe($this->getUserName()).', - channel = '.$this->db->makeSafe($this->getChannel()).', - dateTime = NOW(), - ip = '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).' - WHERE - userID = '.$this->db->makeSafe($this->getUserID()).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $this->resetOnlineUsersData(); - } - - function initMessageHandling() { - // Don't handle messages if we are not in chat view: - if($this->getView() != 'chat') { - return; - } - - // Check if we have been uninvited from a private or restricted channel: - if(!$this->validateChannel($this->getChannel())) { - // Switch to the default channel: - $this->switchChannel($this->getChannelNameFromChannelID($this->getConfig('defaultChannelID'))); - return; - } - - if($this->getRequestVar('text') !== null) { - $this->insertMessage($this->getRequestVar('text')); - } - } - - function insertParsedMessage($text) { - - // If a queryUserName is set, sent all messages as private messages to this userName: - if($this->getQueryUserName() !== null && strpos($text, '/') !== 0) { - $text = '/msg '.$this->getQueryUserName().' '.$text; - } - - // Parse IRC-style commands: - if(strpos($text, '/') === 0) { - $textParts = explode(' ', $text); - - switch($textParts[0]) { - - // Channel switch: - case '/join': - $this->insertParsedMessageJoin($textParts); - break; - - // Logout: - case '/quit': - $this->logout(); - break; - - // Private message: - case '/msg': - case '/describe': - $this->insertParsedMessagePrivMsg($textParts); - break; - - // Invitation: - case '/invite': - $this->insertParsedMessageInvite($textParts); - break; - - // Uninvitation: - case '/uninvite': - $this->insertParsedMessageUninvite($textParts); - break; - - // Private messaging: - case '/query': - $this->insertParsedMessageQuery($textParts); - break; - - // Kicking offending users from the chat: - case '/kick': - $this->insertParsedMessageKick($textParts); - break; - - // Listing banned users: - case '/bans': - $this->insertParsedMessageBans($textParts); - break; - - // Unban user (remove from ban list): - case '/unban': - $this->insertParsedMessageUnban($textParts); - break; - - // Describing actions: - case '/me': - case '/action': - $this->insertParsedMessageAction($textParts); - break; - - - // Listing online Users: - case '/who': - $this->insertParsedMessageWho($textParts); - break; - - // Listing available channels: - case '/list': - $this->insertParsedMessageList($textParts); - break; - - // Retrieving the channel of a User: - case '/whereis': - $this->insertParsedMessageWhereis($textParts); - break; - - // Listing information about a User: - case '/whois': - $this->insertParsedMessageWhois($textParts); - break; - - // Rolling dice: - case '/roll': - $this->insertParsedMessageRoll($textParts); - break; - - // Switching userName: - case '/nick': - $this->insertParsedMessageNick($textParts); - break; - - // Custom or unknown command: - default: - if(!$this->parseCustomCommands($text, $textParts)) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UnknownCommand '.$textParts[0] - ); - } - } - - } else { - // No command found, just insert the plain message: - $this->insertCustomMessage( - $this->getUserID(), - $this->getUserName(), - $this->getUserRole(), - $this->getChannel(), - $text - ); - } - } - - function insertParsedMessageJoin($textParts) { - if(count($textParts) == 1) { - // join with no arguments is the own private channel, if allowed: - if($this->isAllowedToCreatePrivateChannel()) { - // Private channels are identified by square brackets: - $this->switchChannel($this->getChannelNameFromChannelID($this->getPrivateChannelID())); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingChannelName' - ); - } - } else { - $this->switchChannel($textParts[1]); - } - } - - function insertParsedMessagePrivMsg($textParts) { - if($this->isAllowedToSendPrivateMessage()) { - if(count($textParts) < 3) { - if(count($textParts) == 2) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingText' - ); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } - } else { - // Get UserID from UserName: - $toUserID = $this->getIDFromName($textParts[1]); - if($toUserID === null) { - if($this->getQueryUserName() !== null) { - // Close the current query: - $this->insertMessage('/query'); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } - } else { - // Insert /privaction command if /describe is used: - $command = ($textParts[0] == '/describe') ? '/privaction' : '/privmsg'; - // Copy of private message to current User: - $this->insertCustomMessage( - $this->getUserID(), - $this->getUserName(), - $this->getUserRole(), - $this->getPrivateMessageID(), - $command.'to '.$textParts[1].' '.implode(' ', array_slice($textParts, 2)) - ); - // Private message to requested User: - $this->insertCustomMessage( - $this->getUserID(), - $this->getUserName(), - $this->getUserRole(), - $this->getPrivateMessageID($toUserID), - $command.' '.implode(' ', array_slice($textParts, 2)) - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error PrivateMessageNotAllowed' - ); - } - } - - function insertParsedMessageInvite($textParts) { - if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - $toUserID = $this->getIDFromName($textParts[1]); - if($toUserID === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // Add the invitation to the database: - $this->addInvitation($toUserID); - $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel()); - // Copy of invitation to current User: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/inviteto '.$textParts[1].' '.$invitationChannelName - ); - // Invitation to requested User: - $this->insertChatBotMessage( - $this->getPrivateMessageID($toUserID), - '/invite '.$this->getUserName().' '.$invitationChannelName - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error InviteNotAllowed' - ); - } - } - - function insertParsedMessageUninvite($textParts) { - if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - $toUserID = $this->getIDFromName($textParts[1]); - if($toUserID === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // Remove the invitation from the database: - $this->removeInvitation($toUserID); - $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel()); - // Copy of uninvitation to current User: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/uninviteto '.$textParts[1].' '.$invitationChannelName - ); - // Uninvitation to requested User: - $this->insertChatBotMessage( - $this->getPrivateMessageID($toUserID), - '/uninvite '.$this->getUserName().' '.$invitationChannelName - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UninviteNotAllowed' - ); - } - } - - function insertParsedMessageQuery($textParts) { - if($this->isAllowedToSendPrivateMessage()) { - if(count($textParts) == 1) { - if($this->getQueryUserName() !== null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/queryClose '.$this->getQueryUserName() - ); - // Close the current query: - $this->setQueryUserName(null); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error NoOpenQuery' - ); - } - } else { - if($this->getIDFromName($textParts[1]) === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - if($this->getQueryUserName() !== null) { - // Close the current query: - $this->insertMessage('/query'); - } - // Open a query to the requested user: - $this->setQueryUserName($textParts[1]); - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/queryOpen '.$textParts[1] - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error PrivateMessageNotAllowed' - ); - } - } - - function insertParsedMessageKick($textParts) { - // Only moderators/admins may kick users: - if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - // Get UserID from UserName: - $kickUserID = $this->getIDFromName($textParts[1]); - if($kickUserID === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // Check the role of the user to kick: - $kickUserRole = $this->getRoleFromID($kickUserID); - if($kickUserRole == AJAX_CHAT_ADMIN || ($kickUserRole == AJAX_CHAT_MODERATOR && $this->getUserRole() != AJAX_CHAT_ADMIN)) { - // Admins and moderators may not be kicked: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error KickNotAllowed '.$textParts[1] - ); - } else { - // Kick user and insert message: - $channel = $this->getChannelFromID($kickUserID); - $banMinutes = (count($textParts) > 2) ? $textParts[2] : null; - $this->kickUser($textParts[1], $banMinutes, $kickUserID); - // If no channel found, user logged out before he could be kicked - if($channel !== null) { - $this->insertChatBotMessage( - $channel, - '/kick '.$textParts[1], - null, - 1 - ); - // Send a copy of the message to the current user, if not in the channel: - if($channel != $this->getChannel()) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/kick '.$textParts[1], - null, - 1 - ); - } - } - } - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error CommandNotAllowed '.$textParts[0] - ); - } - } - - function insertParsedMessageBans($textParts) { - // Only moderators/admins may see the list of banned users: - if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { - $this->removeExpiredBans(); - $bannedUsers = $this->getBannedUsers(); - if(count($bannedUsers) > 0) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/bans '.implode(' ', $bannedUsers) - ); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/bansEmpty -' - ); - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error CommandNotAllowed '.$textParts[0] - ); - } - } - - function insertParsedMessageUnban($textParts) { - // Only moderators/admins may unban users: - if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { - $this->removeExpiredBans(); - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - if(!in_array($textParts[1], $this->getBannedUsers())) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // Unban user and insert message: - $this->unbanUser($textParts[1]); - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/unban '.$textParts[1] - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error CommandNotAllowed '.$textParts[0] - ); - } - } - - function insertParsedMessageAction($textParts) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingText' - ); - } else { - if($this->getQueryUserName() !== null) { - // If we are in query mode, sent the action to the query user: - $this->insertMessage('/describe '.$this->getQueryUserName().' '.implode(' ', array_slice($textParts, 1))); - } else { - $this->insertCustomMessage( - $this->getUserID(), - $this->getUserName(), - $this->getUserRole(), - $this->getChannel(), - implode(' ', $textParts) - ); - } - } - } - - function insertParsedMessageWho($textParts) { - if(count($textParts) == 1) { - if($this->isAllowedToListHiddenUsers()) { - // List online users from any channel: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/who '.implode(' ', $this->getOnlineUsers()) - ); - } else { - // Get online users for all accessible channels: - $channels = $this->getChannels(); - // Add the own private channel if allowed: - if($this->isAllowedToCreatePrivateChannel()) { - array_push($channels, $this->getPrivateChannelID()); - } - // Add the invitation channels: - foreach($this->getInvitations() as $channelID) { - if(!in_array($channelID, $channels)) { - array_push($channels, $channelID); - } - } - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/who '.implode(' ', $this->getOnlineUsers($channels)) - ); - } - } else { - $channelName = $textParts[1]; - $channelID = $this->getChannelIDFromChannelName($channelName); - if(!$this->validateChannel($channelID)) { - // Invalid channel: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error InvalidChannelName '.$channelName - ); - } else { - // Get online users for the given channel: - $onlineUsers = $this->getOnlineUsers(array($channelID)); - if(count($onlineUsers) > 0) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/whoChannel '.$channelName.' '.implode(' ', $onlineUsers) - ); - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/whoEmpty -' - ); - } - } - } - } - - function insertParsedMessageList($textParts) { - // Get the names of all accessible channels: - $channelNames = $this->getChannelNames(); - // Add the own private channel, if allowed: - if($this->isAllowedToCreatePrivateChannel()) { - array_push($channelNames, $this->getPrivateChannelName()); - } - // Add the invitation channels: - foreach($this->getInvitations() as $channelID) { - $channelName = $this->getChannelNameFromChannelID($channelID); - if($channelName !== null && !in_array($channelName, $channelNames)) { - array_push($channelNames, $channelName); - } - } - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/list '.implode(' ', $channelNames) - ); - } - - function insertParsedMessageWhereis($textParts) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - // Get UserID from UserName: - $whereisUserID = $this->getIDFromName($textParts[1]); - if($whereisUserID === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - $channelID = $this->getChannelFromID($whereisUserID); - if($this->validateChannel($channelID)) { - $channelName = $this->getChannelNameFromChannelID($channelID); - } else { - $channelName = null; - } - if($channelName === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // List user information: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/whereis '.$textParts[1].' '.$channelName - ); - } - } - } - } - - function insertParsedMessageWhois($textParts) { - // Only moderators/admins: - if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { - if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - // Get UserID from UserName: - $whoisUserID = $this->getIDFromName($textParts[1]); - if($whoisUserID === null) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameNotFound '.$textParts[1] - ); - } else { - // List user information: - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/whois '.$textParts[1].' '.$this->getIPFromID($whoisUserID) - ); - } - } - } else { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error CommandNotAllowed '.$textParts[0] - ); - } - } - - function insertParsedMessageRoll($textParts) { - if(count($textParts) == 1) { - // default is one d6: - $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6); - } else { - $diceParts = explode('d', $textParts[1]); - if(count($diceParts) == 2) { - $number = (int)$diceParts[0]; - $sides = (int)$diceParts[1]; - - // Dice number must be an integer between 1 and 100, else roll only one: - $number = ($number > 0 && $number <= 100) ? $number : 1; - - // Sides must be an integer between 1 and 100, else take 6: - $sides = ($sides > 0 && $sides <= 100) ? $sides : 6; - - $text = '/roll '.$this->getUserName().' '.$number.'d'.$sides.' '; - for($i=0; $i<$number; $i++) { - if($i != 0) - $text .= ','; - $text .= $this->rollDice($sides); - } - } else { - // if dice syntax is invalid, roll one d6: - $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6); - } - } - $this->insertChatBotMessage( - $this->getChannel(), - $text - ); - } - - function insertParsedMessageNick($textParts) { - if(!$this->getConfig('allowNickChange') || - (!$this->getConfig('allowGuestUserName') && $this->getUserRole() == AJAX_CHAT_GUEST)) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error CommandNotAllowed '.$textParts[0] - ); - } else if(count($textParts) == 1) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MissingUserName' - ); - } else { - $newUserName = implode(' ', array_slice($textParts, 1)); - if($newUserName == $this->getLoginUserName()) { - // Allow the user to regain the original login userName: - $prefix = ''; - $suffix = ''; - } else if($this->getUserRole() == AJAX_CHAT_GUEST) { - $prefix = $this->getConfig('guestUserPrefix'); - $suffix = $this->getConfig('guestUserSuffix'); - } else { - $prefix = $this->getConfig('changedNickPrefix'); - $suffix = $this->getConfig('changedNickSuffix'); - } - $maxLength = $this->getConfig('userNameMaxLength') - - $this->stringLength($prefix) - - $this->stringLength($suffix); - $newUserName = $this->trimString($newUserName, 'UTF-8', $maxLength, true); - if(!$newUserName) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error InvalidUserName' - ); - } else { - $newUserName = $prefix.$newUserName.$suffix; - if($this->isUserNameInUse($newUserName)) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error UserNameInUse' - ); - } else { - $oldUserName = $this->getUserName(); - $this->setUserName($newUserName); - $this->updateOnlineList(); - // Add info message to update the client-side stored userName: - $this->addInfoMessage($this->getUserName(), 'userName'); - $this->insertChatBotMessage( - $this->getChannel(), - '/nick '.$oldUserName.' '.$newUserName, - null, - 2 - ); - } - } - } - } - - function insertMessage($text) { - if(!$this->isAllowedToWriteMessage()) - return; - - if(!$this->floodControl()) - return; - - $text = $this->trimMessageText($text); - if($text == '') - return; - - if(!$this->onNewMessage($text)) - return; - - $text = $this->replaceCustomText($text); - - $this->insertParsedMessage($text); - } - - function deleteMessage($messageID) { - // Retrieve the channel of the given message: - $sql = 'SELECT - channel - FROM - '.$this->getDataBaseTable('messages').' - WHERE - id='.$this->db->makeSafe($messageID).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $row = $result->fetch(); - - if($row['channel'] !== null) { - $channel = $row['channel']; - - if($this->getUserRole() == AJAX_CHAT_ADMIN) { - $condition = ''; - } else if($this->getUserRole() == AJAX_CHAT_MODERATOR) { - $condition = ' AND - NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).') - AND - NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')'; - } else if($this->getUserRole() == AJAX_CHAT_USER && $this->getConfig('allowUserMessageDelete')) { - $condition = 'AND - ( - userID='.$this->db->makeSafe($this->getUserID()).' - OR - ( - channel = '.$this->db->makeSafe($this->getPrivateMessageID()).' - OR - channel = '.$this->db->makeSafe($this->getPrivateChannelID()).' - ) - AND - NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).') - AND - NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).') - )'; - } else { - return false; - } - - // Remove given message from the database: - $sql = 'DELETE FROM - '.$this->getDataBaseTable('messages').' - WHERE - id='.$this->db->makeSafe($messageID).' - '.$condition.';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - if($result->affectedRows() == 1) { - // Insert a deletion command to remove the message from the clients chatlists: - $this->insertChatBotMessage($channel, '/delete '.$messageID); - return true; - } - } - return false; - } - - function floodControl() { - // Moderators and Admins need no flood control: - if($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_ADMIN) { - return true; - } - $time = time(); - // Check the time of the last inserted message: - if($this->getInsertedMessagesRateTimeStamp()+60 < $time) { - $this->setInsertedMessagesRateTimeStamp($time); - $this->setInsertedMessagesRate(1); - } else { - // Increase the inserted messages rate: - $rate = $this->getInsertedMessagesRate()+1; - $this->setInsertedMessagesRate($rate); - // Check if message rate is too high: - if($rate > $this->getConfig('maxMessageRate')) { - $this->insertChatBotMessage( - $this->getPrivateMessageID(), - '/error MaxMessageRate' - ); - // Return false so the message is not inserted: - return false; - } - } - return true; - } - - function isAllowedToWriteMessage() { - if($this->getUserRole() != AJAX_CHAT_GUEST) - return true; - if($this->getConfig('allowGuestWrite')) - return true; - return false; - } - - function insertChatBotMessage($channelID, $messageText, $ip=null, $mode=0) { - $this->insertCustomMessage( - $this->getConfig('chatBotID'), - $this->getConfig('chatBotName'), - AJAX_CHAT_CHATBOT, - $channelID, - $messageText, - $ip, - $mode - ); - } - - function insertCustomMessage($userID, $userName, $userRole, $channelID, $text, $ip=null, $mode=0) { - // The $mode parameter is used for socket updates: - // 0 = normal messages - // 1 = channel messages (e.g. login/logout, channel enter/leave, kick) - // 2 = messages with online user updates (nick) - - $ip = $ip ? $ip : $_SERVER['REMOTE_ADDR']; - - $sql = 'INSERT INTO '.$this->getDataBaseTable('messages').'( - userID, - userName, - userRole, - channel, - dateTime, - ip, - text - ) - VALUES ( - '.$this->db->makeSafe($userID).', - '.$this->db->makeSafe($userName).', - '.$this->db->makeSafe($userRole).', - '.$this->db->makeSafe($channelID).', - NOW(), - '.$this->db->makeSafe($this->ipToStorageFormat($ip)).', - '.$this->db->makeSafe($text).' - );'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - if($this->getConfig('socketServerEnabled')) { - $this->sendSocketMessage( - $this->getSocketBroadcastMessage( - $this->db->getLastInsertedID(), - time(), - $userID, - $userName, - $userRole, - $channelID, - $text, - $mode - ) - ); - } - } - - function getSocketBroadcastMessage( - $messageID, - $timeStamp, - $userID, - $userName, - $userRole, - $channelID, - $text, - $mode - ) { - // The $mode parameter: - // 0 = normal messages - // 1 = channel messages (e.g. login/logout, channel enter/leave, kick) - // 2 = messages with online user updates (nick) - - // Get the message XML content: - $xml = ''; - if($mode) { - // Add the list of online users if the user list has been updated ($mode > 0): - $xml .= $this->getChatViewOnlineUsersXML(array($channelID)); - } - if($mode != 1 || $this->getConfig('showChannelMessages')) { - $xml .= ''; - $xml .= $this->getChatViewMessageXML( - $messageID, - $timeStamp, - $userID, - $userName, - $userRole, - $channelID, - $text - ); - $xml .= ''; - } - $xml .= ''; - return $xml; - } - - function sendSocketMessage($message) { - // Open a TCP socket connection to the socket server: - if($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) { - if(@socket_connect($socket, $this->getConfig('socketServerIP'), $this->getConfig('socketServerPort'))) { - // Append a null-byte to the string as EOL (End Of Line) character - // which is required by Flash XML socket communication: - $message .= "\0"; - @socket_write( - $socket, - $message, - strlen($message) // Using strlen to count the bytes instead of the number of UTF-8 characters - ); - } - @socket_close($socket); - } - } - - function updateSocketAuthentication($userID, $socketRegistrationID=null, $channels=null) { - // If no $socketRegistrationID or no $channels are given the authentication is removed for the given user: - $authentication = ''; - if($channels) { - foreach($channels as $channelID) { - $authentication .= ''; - } - } - $authentication .= ''; - $this->sendSocketMessage($authentication); - } - - function setSocketRegistrationID($value) { - $this->setSessionVar('SocketRegistrationID', $value); - } - - function getSocketRegistrationID() { - return $this->getSessionVar('SocketRegistrationID'); - } - - function rollDice($sides) { - // seed with microseconds since last "whole" second: - mt_srand((double)microtime()*1000000); - - return mt_rand(1, $sides); - } - - function kickUser($userName, $banMinutes=null, $userID=null) { - if($userID === null) { - $userID = $this->getIDFromName($userName); - } - if($userID === null) { - return; - } - - $banMinutes = $banMinutes ? $banMinutes : $this->getConfig('defaultBanTime'); - - if($banMinutes) { - // Ban User for the given time in minutes: - $this->banUser($userName, $banMinutes, $userID); - } - - // Remove given User from online list: - $sql = 'DELETE FROM - '.$this->getDataBaseTable('online').' - WHERE - userID = '.$this->db->makeSafe($userID).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - // Update the socket server authentication for the kicked user: - if($this->getConfig('socketServerEnabled')) { - $this->updateSocketAuthentication($userID); - } - - $this->removeUserFromOnlineUsersData($userID); - } - - function getBannedUsersData($key=null, $value=null) { - if($this->_bannedUsersData === null) { - $this->_bannedUsersData = array(); - - $sql = 'SELECT - userID, - userName, - ip - FROM - '.$this->getDataBaseTable('bans').' - WHERE - NOW() < dateTime;'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - while($row = $result->fetch()) { - $row['ip'] = $this->ipFromStorageFormat($row['ip']); - array_push($this->_bannedUsersData, $row); - } - - $result->free(); - } - - if($key) { - $bannedUsersData = array(); - foreach($this->_bannedUsersData as $bannedUserData) { - if(!isset($bannedUserData[$key])) { - return $bannedUsersData; - } - if($value) { - if($bannedUserData[$key] == $value) { - array_push($bannedUsersData, $bannedUserData); - } else { - continue; - } - } else { - array_push($bannedUsersData, $bannedUserData[$key]); - } - } - return $bannedUsersData; - } - - return $this->_bannedUsersData; - } - - function getBannedUsers() { - return $this->getBannedUsersData('userName'); - } - - function banUser($userName, $banMinutes=null, $userID=null) { - if($userID === null) { - $userID = $this->getIDFromName($userName); - } - $ip = $this->getIPFromID($userID); - if(!$ip || $userID === null) { - return; - } - - // Remove expired bans: - $this->removeExpiredBans(); - - $banMinutes = (int)$banMinutes; - if(!$banMinutes) { - // If banMinutes is not a valid integer, use the defaultBanTime: - $banMinutes = $this->getConfig('defaultBanTime'); - } - - $sql = 'INSERT INTO '.$this->getDataBaseTable('bans').'( - userID, - userName, - dateTime, - ip - ) - VALUES ( - '.$this->db->makeSafe($userID).', - '.$this->db->makeSafe($userName).', - DATE_ADD(NOW(), interval '.$this->db->makeSafe($banMinutes).' MINUTE), - '.$this->db->makeSafe($this->ipToStorageFormat($ip)).' - );'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function unbanUser($userName) { - $sql = 'DELETE FROM - '.$this->getDataBaseTable('bans').' - WHERE - userName = '.$this->db->makeSafe($userName).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function removeExpiredBans() { - $sql = 'DELETE FROM - '.$this->getDataBaseTable('bans').' - WHERE - dateTime < NOW();'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function setInactive($userID, $userName=null) { - $condition = 'userID='.$this->db->makeSafe($userID); - if($userName !== null) { - $condition .= ' OR userName='.$this->db->makeSafe($userName); - } - $sql = 'UPDATE - '.$this->getDataBaseTable('online').' - SET - dateTime = DATE_SUB(NOW(), interval '.(intval($this->getConfig('inactiveTimeout'))+1).' MINUTE) - WHERE - '.$condition.';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $this->resetOnlineUsersData(); - } - - function removeInactive() { - $sql = 'SELECT - userID, - userName, - channel - FROM - '.$this->getDataBaseTable('online').' - WHERE - NOW() > DATE_ADD(dateTime, interval '.$this->getConfig('inactiveTimeout').' MINUTE);'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - if($result->numRows() > 0) { - $condition = ''; - while($row = $result->fetch()) { - if(!empty($condition)) - $condition .= ' OR '; - // Add userID to condition for removal: - $condition .= 'userID='.$this->db->makeSafe($row['userID']); - - // Update the socket server authentication for the kicked user: - if($this->getConfig('socketServerEnabled')) { - $this->updateSocketAuthentication($row['userID']); - } - - $this->removeUserFromOnlineUsersData($row['userID']); - - // Insert logout timeout message: - $text = '/logout '.$row['userName'].' Timeout'; - $this->insertChatBotMessage( - $row['channel'], - $text, - null, - 1 - ); - } - - $result->free(); - - $sql = 'DELETE FROM - '.$this->getDataBaseTable('online').' - WHERE - '.$condition.';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - } - - function updateOnlineStatus() { - // Update online status every 50 seconds (this allows update requests to be in time): - if(!$this->getStatusUpdateTimeStamp() || ((time() - $this->getStatusUpdateTimeStamp()) > 50)) { - $this->updateOnlineList(); - $this->setStatusUpdateTimeStamp(time()); - } - } - - function checkAndRemoveInactive() { - // Remove inactive users every inactiveCheckInterval: - if(!$this->getInactiveCheckTimeStamp() || ((time() - $this->getInactiveCheckTimeStamp()) > $this->getConfig('inactiveCheckInterval')*60)) { - $this->removeInactive(); - $this->setInactiveCheckTimeStamp(time()); - } - } - - function sendXMLMessages() { - $httpHeader = new AJAXChatHTTPHeader('UTF-8', 'text/xml'); - - // Send HTTP header: - $httpHeader->send(); - - // Output XML messages: - echo $this->getXMLMessages(); - } - - function getXMLMessages() { - switch($this->getView()) { - case 'chat': - return $this->getChatViewXMLMessages(); - case 'teaser': - return $this->getTeaserViewXMLMessages(); - case 'logs': - return $this->getLogsViewXMLMessages(); - default: - return $this->getLogoutXMLMessage(); - } - } - - function getMessageCondition() { - $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')).' - AND ( - channel = '.$this->db->makeSafe($this->getChannel()).' - OR - channel = '.$this->db->makeSafe($this->getPrivateMessageID()).' - ) - AND - '; - if($this->getConfig('requestMessagesPriorChannelEnter') || - ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($this->getChannel(), $this->getConfig('requestMessagesPriorChannelEnterList')))) { - $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)'; - } else { - $condition .= 'dateTime >= FROM_UNIXTIME(' . $this->getChannelEnterTimeStamp() . ')'; - } - return $condition; - } - - function getMessageFilter() { - $filterChannelMessages = ''; - if(!$this->getConfig('showChannelMessages') || $this->getRequestVar('shoutbox')) { - $filterChannelMessages = ' AND NOT ( - text LIKE (\'/login%\') - OR - text LIKE (\'/logout%\') - OR - text LIKE (\'/channelEnter%\') - OR - text LIKE (\'/channelLeave%\') - OR - text LIKE (\'/kick%\') - )'; - } - return $filterChannelMessages; - } - - function getInfoMessagesXML() { - $xml = ''; - // Go through the info messages: - foreach($this->getInfoMessages() as $type=>$infoArray) { - foreach($infoArray as $info) { - $xml .= ''; - $xml .= 'encodeSpecialChars($info).']]>'; - $xml .= ''; - } - } - $xml .= ''; - return $xml; - } - - function getChatViewOnlineUsersXML($channelIDs) { - // Get the online users for the given channels: - $onlineUsersData = $this->getOnlineUsersData($channelIDs); - $xml = ''; - foreach($onlineUsersData as $onlineUserData) { - $xml .= 'encodeSpecialChars($onlineUserData['userName']).']]>'; - $xml .= ''; - } - $xml .= ''; - return $xml; - } - - function getLogoutXMLMessage() { - $xml = ''; - $xml .= ''; - $xml .= ''; - $xml .= ''; - $xml .= 'encodeSpecialChars($this->getConfig('logoutData')).']]>'; - $xml .= ''; - $xml .= ''; - $xml .= ''; - return $xml; - } - - function getChatViewMessageXML( - $messageID, - $timeStamp, - $userID, - $userName, - $userRole, - $channelID, - $text - ) { - $message = 'encodeSpecialChars($userName).']]>'; - $message .= 'encodeSpecialChars($text).']]>'; - $message .= ''; - return $message; - } - - function getChatViewMessagesXML() { - // Get the last messages in descending order (this optimises the LIMIT usage): - $sql = 'SELECT - id, - userID, - userName, - userRole, - channel AS channelID, - UNIX_TIMESTAMP(dateTime) AS timeStamp, - text - FROM - '.$this->getDataBaseTable('messages').' - WHERE - '.$this->getMessageCondition().' - '.$this->getMessageFilter().' - ORDER BY - id - DESC - LIMIT '.$this->getConfig('requestMessagesLimit').';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $messages = ''; - - // Add the messages in reverse order so it is ascending again: - while($row = $result->fetch()) { - $message = $this->getChatViewMessageXML( - $row['id'], - $row['timeStamp'], - $row['userID'], - $row['userName'], - $row['userRole'], - $row['channelID'], - $row['text'] - ); - $messages = $message.$messages; - } - $result->free(); - - $messages = ''.$messages.''; - return $messages; - } - - function getChatViewXMLMessages() { - $xml = ''; - $xml .= ''; - $xml .= $this->getInfoMessagesXML(); - $xml .= $this->getChatViewOnlineUsersXML(array($this->getChannel())); - $xml .= $this->getChatViewMessagesXML(); - $xml .= ''; - return $xml; - } - - function getTeaserMessageCondition() { - $channelID = $this->getValidRequestChannelID(); - $condition = 'channel = '.$this->db->makeSafe($channelID).' - AND - '; - if($this->getConfig('requestMessagesPriorChannelEnter') || - ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($channelID, $this->getConfig('requestMessagesPriorChannelEnterList')))) { - $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)'; - } else { - // Teaser content may not be shown for this channel: - $condition .= '0 = 1'; - } - return $condition; - } - - function getTeaserViewMessagesXML() { - // Get the last messages in descending order (this optimises the LIMIT usage): - $sql = 'SELECT - id, - userID, - userName, - userRole, - channel AS channelID, - UNIX_TIMESTAMP(dateTime) AS timeStamp, - text - FROM - '.$this->getDataBaseTable('messages').' - WHERE - '.$this->getTeaserMessageCondition().' - '.$this->getMessageFilter().' - ORDER BY - id - DESC - LIMIT '.$this->getConfig('requestMessagesLimit').';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $messages = ''; - - // Add the messages in reverse order so it is ascending again: - while($row = $result->fetch()) { - $message = ''; - $message .= 'encodeSpecialChars($row['userName']).']]>'; - $message .= 'encodeSpecialChars($row['text']).']]>'; - $message .= ''; - $messages = $message.$messages; - } - $result->free(); - - $messages = ''.$messages.''; - return $messages; - } - - function getTeaserViewXMLMessages() { - $xml = ''; - $xml .= ''; - $xml .= $this->getInfoMessagesXML(); - $xml .= $this->getTeaserViewMessagesXML(); - $xml .= ''; - return $xml; - } - - function getLogsViewCondition() { - $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')); - - // Check the channel condition: - switch($this->getRequestVar('channelID')) { - case '-3': - // Just display messages from all accessible channels - if($this->getUserRole() != AJAX_CHAT_ADMIN) { - $condition .= ' AND (channel = '.$this->db->makeSafe($this->getPrivateMessageID()); - $condition .= ' OR channel = '.$this->db->makeSafe($this->getPrivateChannelID()); - foreach($this->getChannels() as $channel) { - if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) { - continue; - } - $condition .= ' OR channel = '.$this->db->makeSafe($channel); - } - $condition .= ')'; - } - break; - case '-2': - if($this->getUserRole() != AJAX_CHAT_ADMIN) { - $condition .= ' AND channel = '.($this->getPrivateMessageID()); - } else { - $condition .= ' AND channel > '.($this->getConfig('privateMessageDiff')-1); - } - break; - case '-1': - if($this->getUserRole() != AJAX_CHAT_ADMIN) { - $condition .= ' AND channel = '.($this->getPrivateChannelID()); - } else { - $condition .= ' AND (channel > '.($this->getConfig('privateChannelDiff')-1).' AND channel < '.($this->getConfig('privateMessageDiff')).')'; - } - break; - default: - if(($this->getUserRole() == AJAX_CHAT_ADMIN || !$this->getConfig('logsUserAccessChannelList') || in_array($this->getRequestVar('channelID'), $this->getConfig('logsUserAccessChannelList'))) - && $this->validateChannel($this->getRequestVar('channelID'))) { - $condition .= ' AND channel = '.$this->db->makeSafe($this->getRequestVar('channelID')); - } else { - // No valid channel: - $condition .= ' AND 0 = 1'; - } - } - - // Check the period condition: - $hour = ($this->getRequestVar('hour') === null || $this->getRequestVar('hour') > 23 || $this->getRequestVar('hour') < 0) ? null : $this->getRequestVar('hour'); - $day = ($this->getRequestVar('day') === null || $this->getRequestVar('day') > 31 || $this->getRequestVar('day') < 1) ? null : $this->getRequestVar('day'); - $month = ($this->getRequestVar('month') === null || $this->getRequestVar('month') > 12 || $this->getRequestVar('month') < 1) ? null : $this->getRequestVar('month'); - $year = ($this->getRequestVar('year') === null || $this->getRequestVar('year') > date('Y') || $this->getRequestVar('year') < $this->getConfig('logsFirstYear')) ? null : $this->getRequestVar('year'); - - // If a time (hour) is given but no date (year, month, day), use the current date: - if($hour !== null) { - if($day === null) - $day = date('j'); - if($month === null) - $month = date('n'); - if($year === null) - $year = date('Y'); - } - - if($year === null) { - // No year given, so no period condition - } else if($month === null) { - // Define the given year as period: - $periodStart = mktime(0, 0, 0, 1, 1, $year); - // The last day in a month can be expressed by using 0 for the day of the next month: - $periodEnd = mktime(23, 59, 59, 13, 0, $year); - } else if($day === null) { - // Define the given month as period: - $periodStart = mktime(0, 0, 0, $month, 1, $year); - // The last day in a month can be expressed by using 0 for the day of the next month: - $periodEnd = mktime(23, 59, 59, $month+1, 0, $year); - } else if($hour === null){ - // Define the given day as period: - $periodStart = mktime(0, 0, 0, $month, $day, $year); - $periodEnd = mktime(23, 59, 59, $month, $day, $year); - } else { - // Define the given hour as period: - $periodStart = mktime($hour, 0, 0, $month, $day, $year); - $periodEnd = mktime($hour, 59, 59, $month, $day, $year); - } - - if(isset($periodStart)) - $condition .= ' AND dateTime > \''.date('Y-m-d H:i:s', $periodStart).'\' AND dateTime <= \''.date('Y-m-d H:i:s', $periodEnd).'\''; - - // Check the search condition: - if($this->getRequestVar('search')) { - if(($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) && strpos($this->getRequestVar('search'), 'ip=') === 0) { - // Search for messages with the given IP: - $ip = substr($this->getRequestVar('search'), 3); - $condition .= ' AND (ip = '.$this->db->makeSafe($this->ipToStorageFormat($ip)).')'; - } else if(strpos($this->getRequestVar('search'), 'userID=') === 0) { - // Search for messages with the given userID: - $userID = substr($this->getRequestVar('search'), 7); - $condition .= ' AND (userID = '.$this->db->makeSafe($userID).')'; - } else { - // Use the search value as regular expression on message text and username: - $condition .= ' AND (userName REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).' OR text REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).')'; - } - } - - // If no period or search condition is given, just monitor the last messages on the given channel: - if(!isset($periodStart) && !$this->getRequestVar('search')) { - $condition .= ' AND NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('logsRequestMessagesTimeDiff').' HOUR)'; - } - - return $condition; - } - - function getLogsViewMessagesXML() { - $sql = 'SELECT - id, - userID, - userName, - userRole, - channel AS channelID, - UNIX_TIMESTAMP(dateTime) AS timeStamp, - ip, - text - FROM - '.$this->getDataBaseTable('messages').' - WHERE - '.$this->getLogsViewCondition().' - ORDER BY - id - LIMIT '.$this->getConfig('logsRequestMessagesLimit').';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - $xml = ''; - while($row = $result->fetch()) { - $xml .= 'getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { - $xml .= ' ip="'.$this->ipFromStorageFormat($row['ip']).'"'; - } - $xml .= '>'; - $xml .= 'encodeSpecialChars($row['userName']).']]>'; - $xml .= 'encodeSpecialChars($row['text']).']]>'; - $xml .= ''; - } - $result->free(); - - $xml .= ''; - - return $xml; - } - - function getLogsViewXMLMessages() { - $xml = ''; - $xml .= ''; - $xml .= $this->getInfoMessagesXML(); - $xml .= $this->getLogsViewMessagesXML(); - $xml .= ''; - return $xml; - } - - function purgeLogs() { - $sql = 'DELETE FROM - '.$this->getDataBaseTable('messages').' - WHERE - dateTime < DATE_SUB(NOW(), interval '.$this->getConfig('logsPurgeTimeDiff').' DAY);'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function getInfoMessages($type=null) { - if(!isset($this->_infoMessages)) { - $this->_infoMessages = array(); - } - if($type) { - if(!isset($this->_infoMessages[$type])) { - $this->_infoMessages[$type] = array(); - } - return $this->_infoMessages[$type]; - } else { - return $this->_infoMessages; - } - } - - function addInfoMessage($info, $type='error') { - if(!isset($this->_infoMessages)) { - $this->_infoMessages = array(); - } - if(!isset($this->_infoMessages[$type])) { - $this->_infoMessages[$type] = array(); - } - if(!in_array($info, $this->_infoMessages[$type])) { - array_push($this->_infoMessages[$type], $info); - } - } - - function getRequestVars() { - return $this->_requestVars; - } - - function getRequestVar($key) { - if($this->_requestVars && isset($this->_requestVars[$key])) { - return $this->_requestVars[$key]; - } - return null; - } - - function setRequestVar($key, $value) { - if(!$this->_requestVars) { - $this->_requestVars = array(); - } - $this->_requestVars[$key] = $value; - } - - function getOnlineUsersData($channelIDs=null, $key=null, $value=null) { - if($this->_onlineUsersData === null) { - $this->_onlineUsersData = array(); - - $sql = 'SELECT - userID, - userName, - userRole, - channel, - UNIX_TIMESTAMP(dateTime) AS timeStamp, - ip - FROM - '.$this->getDataBaseTable('online').' - ORDER BY - userName;'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - while($row = $result->fetch()) { - $row['ip'] = $this->ipFromStorageFormat($row['ip']); - array_push($this->_onlineUsersData, $row); - } - - $result->free(); - } - - if($channelIDs || $key) { - $onlineUsersData = array(); - foreach($this->_onlineUsersData as $userData) { - if($channelIDs && !in_array($userData['channel'], $channelIDs)) { - continue; - } - if($key) { - if(!isset($userData[$key])) { - return $onlineUsersData; - } - if($value !== null) { - if($userData[$key] == $value) { - array_push($onlineUsersData, $userData); - } else { - continue; - } - } else { - array_push($onlineUsersData, $userData[$key]); - } - } else { - array_push($onlineUsersData, $userData); - } - } - return $onlineUsersData; - } - - return $this->_onlineUsersData; - } - - function removeUserFromOnlineUsersData($userID=null) { - if(!$this->_onlineUsersData) { - return; - } - $userID = ($userID === null) ? $this->getUserID() : $userID; - for($i=0; $i_onlineUsersData); $i++) { - if($this->_onlineUsersData[$i]['userID'] == $userID) { - array_splice($this->_onlineUsersData, $i, 1); - break; - } - } - } - - function resetOnlineUsersData() { - $this->_onlineUsersData = null; - } - - function getOnlineUsers($channelIDs=null) { - return $this->getOnlineUsersData($channelIDs, 'userName'); - } - - function getOnlineUserIDs($channelIDs=null) { - return $this->getOnlineUsersData($channelIDs, 'userID'); - } - - function startSession() { - if(!session_id()) { - // Set the session name: - session_name($this->getConfig('sessionName')); - - // Set session cookie parameters: - session_set_cookie_params( - 0, // The session is destroyed on logout anyway, so no use to set this - $this->getConfig('sessionCookiePath'), - $this->getConfig('sessionCookieDomain'), - $this->getConfig('sessionCookieSecure') - ); - - // Start the session: - session_start(); - - // We started a new session: - $this->_sessionNew = true; - } - } - - function destroySession() { - if($this->_sessionNew) { - // Delete all session variables: - $_SESSION = array(); - - // Delete the session cookie: - if (isset($_COOKIE[session_name()])) { - setcookie( - session_name(), - '', - time()-42000, - $this->getConfig('sessionCookiePath'), - $this->getConfig('sessionCookieDomain'), - $this->getConfig('sessionCookieSecure') - ); - } - - // Destroy the session: - session_destroy(); - } else { - // Unset all session variables starting with the sessionKeyPrefix: - foreach($_SESSION as $key=>$value) { - if(strpos($key, $this->getConfig('sessionKeyPrefix')) === 0) { - unset($_SESSION[$key]); - } - } - } - } - - function regenerateSessionID() { - if($this->_sessionNew) { - // Regenerate session id: - @session_regenerate_id(true); - } - } - - function getSessionVar($key, $prefix=null) { - if($prefix === null) - $prefix = $this->getConfig('sessionKeyPrefix'); - - // Return the session value if existing: - if(isset($_SESSION[$prefix.$key])) - return $_SESSION[$prefix.$key]; - else - return null; - } - - function setSessionVar($key, $value, $prefix=null) { - if($prefix === null) - $prefix = $this->getConfig('sessionKeyPrefix'); - - // Set the session value: - $_SESSION[$prefix.$key] = $value; - } - - function getSessionIP() { - return $this->getSessionVar('IP'); - } - - function setSessionIP($ip) { - $this->setSessionVar('IP', $ip); - } - - function getQueryUserName() { - return $this->getSessionVar('QueryUserName'); - } - - function setQueryUserName($userName) { - $this->setSessionVar('QueryUserName', $userName); - } - - function getInvitations() { - if($this->_invitations === null) { - $this->_invitations = array(); - - $sql = 'SELECT - channel - FROM - '.$this->getDataBaseTable('invitations').' - WHERE - userID='.$this->db->makeSafe($this->getUserID()).' - AND - DATE_SUB(NOW(), interval 1 DAY) < dateTime;'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - - while($row = $result->fetch()) { - array_push($this->_invitations, $row['channel']); - } - - $result->free(); - } - return $this->_invitations; - } - - function removeExpiredInvitations() { - $sql = 'DELETE FROM - '.$this->getDataBaseTable('invitations').' - WHERE - DATE_SUB(NOW(), interval 1 DAY) > dateTime;'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function addInvitation($userID, $channelID=null) { - $this->removeExpiredInvitations(); - - $channelID = ($channelID === null) ? $this->getChannel() : $channelID; - - $sql = 'INSERT INTO '.$this->getDataBaseTable('invitations').'( - userID, - channel, - dateTime - ) - VALUES ( - '.$this->db->makeSafe($userID).', - '.$this->db->makeSafe($channelID).', - NOW() - );'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function removeInvitation($userID, $channelID=null) { - $channelID = ($channelID === null) ? $this->getChannel() : $channelID; - - $sql = 'DELETE FROM - '.$this->getDataBaseTable('invitations').' - WHERE - userID='.$this->db->makeSafe($userID).' - AND - channel='.$this->db->makeSafe($channelID).';'; - - // Create a new SQL query: - $result = $this->db->sqlQuery($sql); - - // Stop if an error occurs: - if($result->error()) { - echo $result->getError(); - die(); - } - } - - function getUserID() { - return $this->getSessionVar('UserID'); - } - - function setUserID($id) { - $this->setSessionVar('UserID', $id); - } - - function getUserName() { - return $this->getSessionVar('UserName'); - } - - function setUserName($name) { - $this->setSessionVar('UserName', $name); - } - - function getLoginUserName() { - return $this->getSessionVar('LoginUserName'); - } - - function setLoginUserName($name) { - $this->setSessionVar('LoginUserName', $name); - } - - function getUserRole() { - $userRole = $this->getSessionVar('UserRole'); - if($userRole === null) - return AJAX_CHAT_GUEST; - return $userRole; - } - - function setUserRole($role) { - $this->setSessionVar('UserRole', $role); - } - - function getChannel() { - return $this->getSessionVar('Channel'); - } - - function setChannel($channel) { - $this->setSessionVar('Channel', $channel); - - // Save the channel enter timestamp: - $this->setChannelEnterTimeStamp(time()); - - // Update the channel authentication for the socket server: - if($this->getConfig('socketServerEnabled')) { - $this->updateSocketAuthentication( - $this->getUserID(), - $this->getSocketRegistrationID(), - array($channel,$this->getPrivateMessageID()) - ); - } - - // Reset the logs view socket authentication session var: - if($this->getSessionVar('logsViewSocketAuthenticated')) { - $this->setSessionVar('logsViewSocketAuthenticated', false); - } - } - - function isLoggedIn() { - return (bool)$this->getSessionVar('LoggedIn'); - } - - function setLoggedIn($bool) { - $this->setSessionVar('LoggedIn', $bool); - } - - function getLoginTimeStamp() { - return $this->getSessionVar('LoginTimeStamp'); - } - - function setLoginTimeStamp($time) { - $this->setSessionVar('LoginTimeStamp', $time); - } - - function getChannelEnterTimeStamp() { - return $this->getSessionVar('ChannelEnterTimeStamp'); - } - - function setChannelEnterTimeStamp($time) { - $this->setSessionVar('ChannelEnterTimeStamp', $time); - } - - function getStatusUpdateTimeStamp() { - return $this->getSessionVar('StatusUpdateTimeStamp'); - } - - function setStatusUpdateTimeStamp($time) { - $this->setSessionVar('StatusUpdateTimeStamp', $time); - } - - function getInactiveCheckTimeStamp() { - return $this->getSessionVar('InactiveCheckTimeStamp'); - } - - function setInactiveCheckTimeStamp($time) { - $this->setSessionVar('InactiveCheckTimeStamp', $time); - } - - function getInsertedMessagesRate() { - return $this->getSessionVar('InsertedMessagesRate'); - } - - function setInsertedMessagesRate($rate) { - $this->setSessionVar('InsertedMessagesRate', $rate); - } - - function getInsertedMessagesRateTimeStamp() { - return $this->getSessionVar('InsertedMessagesRateTimeStamp'); - } - - function setInsertedMessagesRateTimeStamp($time) { - $this->setSessionVar('InsertedMessagesRateTimeStamp', $time); - } - - function getLangCode() { - // Get the langCode from request or cookie: - $langCodeCookie = isset($_COOKIE[$this->getConfig('sessionName').'_lang']) ? $_COOKIE[$this->getConfig('sessionName').'_lang'] : null; - $langCode = $this->getRequestVar('lang') ? $this->getRequestVar('lang') : $langCodeCookie; - // Check if the langCode is valid: - if(!in_array($langCode, $this->getConfig('langAvailable'))) { - // Determine the user language: - $language = new AJAXChatLanguage($this->getConfig('langAvailable'), $this->getConfig('langDefault')); - $langCode = $language->getLangCode(); - } - return $langCode; - } - - function setLangCodeCookie() { - setcookie( - $this->getConfig('sessionName').'_lang', - $this->getLangCode(), - time()+60*60*24*$this->getConfig('sessionCookieLifeTime'), - $this->getConfig('sessionCookiePath'), - $this->getConfig('sessionCookieDomain'), - $this->getConfig('sessionCookieSecure') - ); - } - - function removeUnsafeCharacters($str) { - // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127: - return AJAXChatEncoding::removeUnsafeCharacters($str); - } - - function subString($str, $start=0, $length=null, $encoding='UTF-8') { - return AJAXChatString::subString($str, $start, $length, $encoding); - } - - function stringLength($str, $encoding='UTF-8') { - return AJAXChatString::stringLength($str, $encoding); - } - - function trimMessageText($text) { - return $this->trimString($text, 'UTF-8', $this->getConfig('messageTextMaxLength')); - } - - function trimUserName($userName) { - return $this->trimString($userName, null, $this->getConfig('userNameMaxLength'), true, true); - } - - function trimChannelName($channelName) { - return $this->trimString($channelName, null, null, true, true); - } - - function trimString($str, $sourceEncoding=null, $maxLength=null, $replaceWhitespace=false, $decodeEntities=false, $htmlEntitiesMap=null) { - // Make sure the string contains valid unicode: - $str = $this->convertToUnicode($str, $sourceEncoding); - - // Make sure the string contains no unsafe characters: - $str = $this->removeUnsafeCharacters($str); - - // Strip whitespace from the beginning and end of the string: - $str = trim($str); - - if($replaceWhitespace) { - // Replace any whitespace in the userName with the underscore "_": - $str = preg_replace('/\s/u', '_', $str); - } - - if($decodeEntities) { - // Decode entities: - $str = $this->decodeEntities($str, 'UTF-8', $htmlEntitiesMap); - } - - if($maxLength) { - // Cut the string to the allowed length: - $str = $this->subString($str, 0, $maxLength); - } - - return $str; - } - - function convertToUnicode($str, $sourceEncoding=null) { - if($sourceEncoding === null) { - $sourceEncoding = $this->getConfig('sourceEncoding'); - } - return $this->convertEncoding($str, $sourceEncoding, 'UTF-8'); - } - - function convertFromUnicode($str, $contentEncoding=null) { - if($contentEncoding === null) { - $contentEncoding = $this->getConfig('contentEncoding'); - } - return $this->convertEncoding($str, 'UTF-8', $contentEncoding); - } - - function convertEncoding($str, $charsetFrom, $charsetTo) { - return AJAXChatEncoding::convertEncoding($str, $charsetFrom, $charsetTo); - } - - function encodeEntities($str, $encoding='UTF-8', $convmap=null) { - return AJAXChatEncoding::encodeEntities($str, $encoding, $convmap); - } - - function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) { - return AJAXChatEncoding::decodeEntities($str, $encoding, $htmlEntitiesMap); - } - - function htmlEncode($str) { - return AJAXChatEncoding::htmlEncode($str, $this->getConfig('contentEncoding')); - } - - function encodeSpecialChars($str) { - return AJAXChatEncoding::encodeSpecialChars($str); - } - - function decodeSpecialChars($str) { - return AJAXChatEncoding::decodeSpecialChars($str); - } - - function ipToStorageFormat($ip) { - if(function_exists('inet_pton')) { - // ipv4 & ipv6: - return @inet_pton($ip); - } - // Only ipv4: - return @pack('N',@ip2long($ip)); - } - - function ipFromStorageFormat($ip) { - if(function_exists('inet_ntop')) { - // ipv4 & ipv6: - return @inet_ntop($ip); - } - // Only ipv4: - $unpacked = @unpack('Nlong',$ip); - if(isset($unpacked['long'])) { - return @long2ip($unpacked['long']); - } - return null; - } - - function getConfig($key, $subkey=null) { - if($subkey) - return $this->_config[$key][$subkey]; - else - return $this->_config[$key]; - } - - function setConfig($key, $subkey, $value) { - if($subkey) { - if(!isset($this->_config[$key])) { - $this->_config[$key] = array(); - } - $this->_config[$key][$subkey] = $value; - } else { - $this->_config[$key] = $value; - } - } - - function getLang($key=null) { - if(!$this->_lang) { - // Include the language file: - $lang = null; - require(AJAX_CHAT_PATH.'lib/lang/'.$this->getLangCode().'.php'); - $this->_lang = &$lang; - } - if($key === null) - return $this->_lang; - if(isset($this->_lang[$key])) - return $this->_lang[$key]; - return null; - } - - function getChatURL() { - if(defined('AJAX_CHAT_URL')) { - return AJAX_CHAT_URL; - } - - return - (isset($_SERVER['HTTPS']) ? 'https://' : 'http://'). - (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : ''). - (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME']. - (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443 || $_SERVER['SERVER_PORT'] == 80 ? '' : ':'.$_SERVER['SERVER_PORT']))). - substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')+1); - } - - function getIDFromName($userName) { - $userDataArray = $this->getOnlineUsersData(null,'userName',$userName); - if($userDataArray && isset($userDataArray[0])) { - return $userDataArray[0]['userID']; - } - return null; - } - - function getNameFromID($userID) { - $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); - if($userDataArray && isset($userDataArray[0])) { - return $userDataArray[0]['userName']; - } - return null; - } - - function getChannelFromID($userID) { - $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); - if($userDataArray && isset($userDataArray[0])) { - return $userDataArray[0]['channel']; - } - return null; - } - - function getIPFromID($userID) { - $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); - if($userDataArray && isset($userDataArray[0])) { - return $userDataArray[0]['ip']; - } - return null; - } - - function getRoleFromID($userID) { - $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); - if($userDataArray && isset($userDataArray[0])) { - return $userDataArray[0]['userRole']; - } - return null; - } - - function getChannelNames() { - return array_flip($this->getChannels()); - } - - function getChannelIDFromChannelName($channelName) { - if(!$channelName) - return null; - $channels = $this->getAllChannels(); - if(array_key_exists($channelName,$channels)) { - return $channels[$channelName]; - } - $channelID = null; - // Check if the requested channel is the own private channel: - if($channelName == $this->getPrivateChannelName()) { - return $this->getPrivateChannelID(); - } - // Try to retrieve a private room ID: - $strlenChannelName = $this->stringLength($channelName); - $strlenPrefix = $this->stringLength($this->getConfig('privateChannelPrefix')); - $strlenSuffix = $this->stringLength($this->getConfig('privateChannelSuffix')); - if($this->subString($channelName,0,$strlenPrefix) == $this->getConfig('privateChannelPrefix') - && $this->subString($channelName,$strlenChannelName-$strlenSuffix) == $this->getConfig('privateChannelSuffix')) { - $userName = $this->subString( - $channelName, - $strlenPrefix, - $strlenChannelName-($strlenPrefix+$strlenSuffix) - ); - $userID = $this->getIDFromName($userName); - if($userID !== null) { - $channelID = $this->getPrivateChannelID($userID); - } - } - return $channelID; - } - - function getChannelNameFromChannelID($channelID) { - foreach($this->getAllChannels() as $key=>$value) { - if($value == $channelID) { - return $key; - } - } - // Try to retrieve a private room name: - if($channelID == $this->getPrivateChannelID()) { - return $this->getPrivateChannelName(); - } - $userName = $this->getNameFromID($channelID-$this->getConfig('privateChannelDiff')); - if($userName === null) { - return null; - } - return $this->getPrivateChannelName($userName); - } - - function getChannelName() { - return $this->getChannelNameFromChannelID($this->getChannel()); - } - - function getPrivateChannelName($userName=null) { - if($userName === null) { - $userName = $this->getUserName(); - } - return $this->getConfig('privateChannelPrefix').$userName.$this->getConfig('privateChannelSuffix'); - } - - function getPrivateChannelID($userID=null) { - if($userID === null) { - $userID = $this->getUserID(); - } - return $userID + $this->getConfig('privateChannelDiff'); - } - - function getPrivateMessageID($userID=null) { - if($userID === null) { - $userID = $this->getUserID(); - } - return $userID + $this->getConfig('privateMessageDiff'); - } - - function isAllowedToSendPrivateMessage() { - if($this->getConfig('allowPrivateMessages') || $this->getUserRole() == AJAX_CHAT_ADMIN) { - return true; - } - return false; - } - - function isAllowedToCreatePrivateChannel() { - if($this->getConfig('allowPrivateChannels')) { - switch($this->getUserRole()) { - case AJAX_CHAT_USER: - return true; - case AJAX_CHAT_MODERATOR: - return true; - case AJAX_CHAT_ADMIN: - return true; - default: - return false; - } - } - return false; - } - - function isAllowedToListHiddenUsers() { - // Hidden users are users within private or restricted channels: - switch($this->getUserRole()) { - case AJAX_CHAT_MODERATOR: - return true; - case AJAX_CHAT_ADMIN: - return true; - default: - return false; - } - } - - function isUserOnline($userID=null) { - $userID = ($userID === null) ? $this->getUserID() : $userID; - $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); - if($userDataArray && count($userDataArray) > 0) { - return true; - } - return false; - } - - function isUserNameInUse($userName=null) { - $userName = ($userName === null) ? $this->getUserName() : $userName; - $userDataArray = $this->getOnlineUsersData(null,'userName',$userName); - if($userDataArray && count($userDataArray) > 0) { - return true; - } - return false; - } - - function isUserBanned($userName, $userID=null, $ip=null) { - if($userID !== null) { - $bannedUserDataArray = $this->getBannedUsersData('userID',$userID); - if($bannedUserDataArray && isset($bannedUserDataArray[0])) { - return true; - } - } - if($ip !== null) { - $bannedUserDataArray = $this->getBannedUsersData('ip',$ip); - if($bannedUserDataArray && isset($bannedUserDataArray[0])) { - return true; - } - } - $bannedUserDataArray = $this->getBannedUsersData('userName',$userName); - if($bannedUserDataArray && isset($bannedUserDataArray[0])) { - return true; - } - return false; - } - - function isMaxUsersLoggedIn() { - if(count($this->getOnlineUsersData()) >= $this->getConfig('maxUsersLoggedIn')) { - return true; - } - return false; - } - - function validateChannel($channelID) { - if($channelID === null) { - return false; - } - // Return true for normal channels the user has acces to: - if(in_array($channelID, $this->getChannels())) { - return true; - } - // Return true if the user is allowed to join his own private channel: - if($channelID == $this->getPrivateChannelID() && $this->isAllowedToCreatePrivateChannel()) { - return true; - } - // Return true if the user has been invited to a restricted or private channel: - if(in_array($channelID, $this->getInvitations())) { - return true; - } - // No valid channel, return false: - return false; - } - - function createGuestUserName() { - $maxLength = $this->getConfig('userNameMaxLength') - - $this->stringLength($this->getConfig('guestUserPrefix')) - - $this->stringLength($this->getConfig('guestUserSuffix')); - - // seed with microseconds since last "whole" second: - mt_srand((double)microtime()*1000000); - - // Create a random userName using numbers between 100000 and 999999: - $userName = substr(mt_rand(100000, 999999), 0, $maxLength); - - return $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix'); - } - - // Guest userIDs must not interfere with existing userIDs and must be lower than privateChannelDiff: - function createGuestUserID() { - // seed with microseconds since last "whole" second: - mt_srand((double)microtime()*1000000); - - return mt_rand($this->getConfig('minGuestUserID'), $this->getConfig('privateChannelDiff')-1); - } - - function getGuestUser() { - if(!$this->getConfig('allowGuestLogins')) - return null; - - if($this->getConfig('allowGuestUserName')) { - $maxLength = $this->getConfig('userNameMaxLength') - - $this->stringLength($this->getConfig('guestUserPrefix')) - - $this->stringLength($this->getConfig('guestUserSuffix')); - - // Trim guest userName: - $userName = $this->trimString($this->getRequestVar('userName'), null, $maxLength, true, true); - - // If given userName is invalid, create one: - if(!$userName) { - $userName = $this->createGuestUserName(); - } else { - // Add the guest users prefix and suffix to the given userName: - $userName = $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix'); - } - } else { - $userName = $this->createGuestUserName(); - } - - $userData = array(); - $userData['userID'] = $this->createGuestUserID(); - $userData['userName'] = $userName; - $userData['userRole'] = AJAX_CHAT_GUEST; - return $userData; - } - - function getCustomVar($key) { - if(!isset($this->_customVars)) - $this->_customVars = array(); - if(!isset($this->_customVars[$key])) - return null; - return $this->_customVars[$key]; - } - - function setCustomVar($key, $value) { - if(!isset($this->_customVars)) - $this->_customVars = array(); - $this->_customVars[$key] = $value; - } - - // Override to replace custom template tags: - // Return the replacement for the given tag (and given tagContent) - function replaceCustomTemplateTags($tag, $tagContent) { - return null; - } - - // Override to initialize custom configuration settings: - function initCustomConfig() { - } - - // Override to add custom request variables: - // Add values to the request variables array: $this->_requestVars['customVariable'] = null; - function initCustomRequestVars() { - } - - // Override to add custom session code right after the session has been started: - function initCustomSession() { - } - - // Override, to parse custom info requests: - // $infoRequest contains the current info request - // Add info responses using the method addInfoMessage($info, $type) - function parseCustomInfoRequest($infoRequest) { - } - - // Override to replace custom text: - // Return replaced text - // $text contains the whole message - function replaceCustomText(&$text) { - return $text; - } - - // Override to add custom commands: - // Return true if a custom command has been successfully parsed, else false - // $text contains the whole message, $textParts the message split up as words array - function parseCustomCommands($text, $textParts) { - return false; - } - - // Override to perform custom actions on new messages: - // Return true if message may be inserted, else false - // $text contains the whole message - function onNewMessage($text) { - return true; - } - - // Override to perform custom actions on new messages: - // Method to set the style cookie depending on user data - function setStyle() { - } - - // Override: - // Returns true if the userID of the logged in user is identical to the userID of the authentication system - // or the user is authenticated as guest in the chat and the authentication system - function revalidateUserID() { - return true; - } - - // Override: - // Returns an associative array containing userName, userID and userRole - // Returns null if login is invalid - function getValidLoginUserData() { - // Check if we have a valid registered user: - if(false) { - // Here is the place to check user authentication - } else { - // Guest users: - return $this->getGuestUser(); - } - } - - // Override: - // Store the channels the current user has access to - // Make sure channel names don't contain any whitespace - function &getChannels() { - if($this->_channels === null) { - $this->_channels = $this->getAllChannels(); - } - return $this->_channels; - } - - // Override: - // Store all existing channels - // Make sure channel names don't contain any whitespace - function &getAllChannels() { - if($this->_allChannels === null) { - $this->_allChannels = array(); - - // Default channel, public to everyone: - $this->_allChannels[$this->trimChannelName($this->getConfig('defaultChannelName'))] = $this->getConfig('defaultChannelID'); - } - return $this->_allChannels; - } - -} -?> \ No newline at end of file +initialize(); + } + + function initialize() { + // Initialize configuration settings: + $this->initConfig(); + + // Initialize the DataBase connection: + $this->initDataBaseConnection(); + + // Initialize request variables: + $this->initRequestVars(); + + // Initialize the chat session: + $this->initSession(); + + // Handle the browser request and send the response content: + $this->handleRequest(); + } + + function initConfig() { + $config = null; + if (!include(AJAX_CHAT_PATH.'lib/config.php')) { + echo('Error: Could not find a config.php file in "'.AJAX_CHAT_PATH.'"lib/". Check to make sure the file exists.'); + die(); + } + $this->_config = &$config; + + // Initialize custom configuration settings: + $this->initCustomConfig(); + } + + function initRequestVars() { + $this->_requestVars = array(); + $this->_requestVars['ajax'] = isset($_REQUEST['ajax']) ? true : false; + $this->_requestVars['userID'] = isset($_REQUEST['userID']) ? (int)$_REQUEST['userID'] : null; + $this->_requestVars['userName'] = isset($_REQUEST['userName']) ? $_REQUEST['userName'] : null; + $this->_requestVars['channelID'] = isset($_REQUEST['channelID']) ? (int)$_REQUEST['channelID'] : null; + $this->_requestVars['channelName'] = isset($_REQUEST['channelName']) ? $_REQUEST['channelName'] : null; + $this->_requestVars['text'] = isset($_POST['text']) ? $_POST['text'] : null; + $this->_requestVars['lastID'] = isset($_REQUEST['lastID']) ? (int)$_REQUEST['lastID'] : 0; + $this->_requestVars['login'] = isset($_REQUEST['login']) ? true : false; + $this->_requestVars['logout'] = isset($_REQUEST['logout']) ? true : false; + $this->_requestVars['password'] = isset($_REQUEST['password']) ? $_REQUEST['password'] : null; + $this->_requestVars['view'] = isset($_REQUEST['view']) ? $_REQUEST['view'] : null; + $this->_requestVars['year'] = isset($_REQUEST['year']) ? (int)$_REQUEST['year'] : null; + $this->_requestVars['month'] = isset($_REQUEST['month']) ? (int)$_REQUEST['month'] : null; + $this->_requestVars['day'] = isset($_REQUEST['day']) ? (int)$_REQUEST['day'] : null; + $this->_requestVars['hour'] = isset($_REQUEST['hour']) ? (int)$_REQUEST['hour'] : null; + $this->_requestVars['search'] = isset($_REQUEST['search']) ? $_REQUEST['search'] : null; + $this->_requestVars['shoutbox'] = isset($_REQUEST['shoutbox']) ? true : false; + $this->_requestVars['getInfos'] = isset($_REQUEST['getInfos']) ? $_REQUEST['getInfos'] : null; + $this->_requestVars['lang'] = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : null; + $this->_requestVars['delete'] = isset($_REQUEST['delete']) ? (int)$_REQUEST['delete'] : null; + + // Initialize custom request variables: + $this->initCustomRequestVars(); + + // Remove slashes which have been added to user input strings if magic_quotes_gpc is On: + if(get_magic_quotes_gpc()) { + // It is safe to remove the slashes as we escape user data ourself + array_walk( + $this->_requestVars, + create_function( + '&$value, $key', + 'if(is_string($value)) $value = stripslashes($value);' + ) + ); + } + } + + function initDataBaseConnection() { + // Create a new database object: + $this->db = new AJAXChatDataBase( + $this->_config['dbConnection'] + ); + // Use a new database connection if no existing is given: + if(!$this->_config['dbConnection']['link']) { + // Connect to the database server: + $this->db->connect($this->_config['dbConnection']); + if($this->db->error()) { + echo $this->db->getError(); + die(); + } + // Select the database: + $this->db->select($this->_config['dbConnection']['name']); + if($this->db->error()) { + echo $this->db->getError(); + die(); + } + } + // Unset the dbConnection array for safety purposes: + unset($this->_config['dbConnection']); + } + + function getDataBaseTable($table) { + return ($this->db->getName() ? '`'.$this->db->getName().'`.'.$this->getConfig('dbTableNames',$table) : $this->getConfig('dbTableNames',$table)); + } + + function initSession() { + // Start the PHP session (if not already started): + $this->startSession(); + + if($this->isLoggedIn()) { + // Logout if we receive a logout request, the chat has been closed or the userID could not be revalidated: + if($this->getRequestVar('logout') || !$this->isChatOpen() || !$this->revalidateUserID()) { + $this->logout(); + return; + } + // Logout if the Session IP is not the same when logged in and ipCheck is enabled: + if($this->getConfig('ipCheck') && ($this->getSessionIP() === null || $this->getSessionIP() != $_SERVER['REMOTE_ADDR'])) { + $this->logout('IP'); + return; + } + } else if( + // Login if auto-login enabled or a login, userName or shoutbox parameter is given: + $this->getConfig('forceAutoLogin') || + $this->getRequestVar('login') || + $this->getRequestVar('userName') || + $this->getRequestVar('shoutbox') + ) { + $this->login(); + } + + // Initialize the view: + $this->initView(); + + if($this->getView() == 'chat') { + $this->initChatViewSession(); + } else if($this->getView() == 'logs') { + $this->initLogsViewSession(); + } + + if(!$this->getRequestVar('ajax') && !headers_sent()) { + // Set style cookie: + $this->setStyle(); + // Set langCode cookie: + $this->setLangCodeCookie(); + } + + $this->initCustomSession(); + } + + function initLogsViewSession() { + if($this->getConfig('socketServerEnabled')) { + if(!$this->getSessionVar('logsViewSocketAuthenticated')) { + $this->updateLogsViewSocketAuthentication(); + $this->setSessionVar('logsViewSocketAuthenticated', true); + } + } + } + + function updateLogsViewSocketAuthentication() { + if($this->getUserRole() != AJAX_CHAT_ADMIN) { + $channels = array(); + foreach($this->getChannels() as $channel) { + if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) { + continue; + } + array_push($channels, $channel); + } + array_push($channels, $this->getPrivateMessageID()); + array_push($channels, $this->getPrivateChannelID()); + } else { + // The channelID "ALL" authenticates for all channels: + $channels = array('ALL'); + } + $this->updateSocketAuthentication( + $this->getUserID(), + $this->getSocketRegistrationID(), + $channels + ); + } + + function initChatViewSession() { + // If channel is not null we are logged in to the chat view: + if($this->getChannel() !== null) { + // Check if the current user has been logged out due to inactivity: + if(!$this->isUserOnline()) { + $this->logout(); + return; + } + if($this->getRequestVar('ajax')) { + $this->initChannel(); + $this->updateOnlineStatus(); + $this->checkAndRemoveInactive(); + } + } else { + if($this->getRequestVar('ajax')) { + // Set channel, insert login messages and add to online list on first ajax request in chat view: + $this->chatViewLogin(); + } + } + } + + function isChatOpen() { + if($this->getUserRole() == AJAX_CHAT_ADMIN) + return true; + if($this->getConfig('chatClosed')) + return false; + $time = time(); + if($this->getConfig('timeZoneOffset') !== null) { + // Subtract the server timezone offset and add the config timezone offset: + $time -= date('Z', $time); + $time += $this->getConfig('timeZoneOffset'); + } + // Check the opening hours: + if($this->getConfig('openingHour') < $this->getConfig('closingHour')) + { + if(($this->getConfig('openingHour') > date('G', $time)) || ($this->getConfig('closingHour') <= date('G', $time))) + return false; + } + else + { + if(($this->getConfig('openingHour') > date('G', $time)) && ($this->getConfig('closingHour') <= date('G', $time))) + return false; + } + // Check the opening weekdays: + if(!in_array(date('w', $time), $this->getConfig('openingWeekDays'))) + return false; + return true; + } + + function handleRequest() { + if($this->getRequestVar('ajax')) { + if($this->isLoggedIn()) { + // Parse info requests (for current userName, etc.): + $this->parseInfoRequests(); + + // Parse command requests (e.g. message deletion): + $this->parseCommandRequests(); + + // Parse message requests: + $this->initMessageHandling(); + } + // Send chat messages and online user list in XML format: + $this->sendXMLMessages(); + } else { + // Display XHTML content for non-ajax requests: + $this->sendXHTMLContent(); + } + } + + function parseCommandRequests() { + if($this->getRequestVar('delete') !== null) { + $this->deleteMessage($this->getRequestVar('delete')); + } + } + + function parseInfoRequests() { + if($this->getRequestVar('getInfos')) { + $infoRequests = explode(',', $this->getRequestVar('getInfos')); + foreach($infoRequests as $infoRequest) { + $this->parseInfoRequest($infoRequest); + } + } + } + + function parseInfoRequest($infoRequest) { + switch($infoRequest) { + case 'userID': + $this->addInfoMessage($this->getUserID(), 'userID'); + break; + case 'userName': + $this->addInfoMessage($this->getUserName(), 'userName'); + break; + case 'userRole': + $this->addInfoMessage($this->getUserRole(), 'userRole'); + break; + case 'channelID': + $this->addInfoMessage($this->getChannel(), 'channelID'); + break; + case 'channelName': + $this->addInfoMessage($this->getChannelName(), 'channelName'); + break; + case 'socketRegistrationID': + $this->addInfoMessage($this->getSocketRegistrationID(), 'socketRegistrationID'); + break; + default: + $this->parseCustomInfoRequest($infoRequest); + } + } + + function sendXHTMLContent() { + $httpHeader = new AJAXChatHTTPHeader($this->getConfig('contentEncoding'), $this->getConfig('contentType')); + + $template = new AJAXChatTemplate($this, $this->getTemplateFileName(), $httpHeader->getContentType()); + + // Send HTTP header: + $httpHeader->send(); + + // Send parsed template content: + echo $template->getParsedContent(); + } + + function getTemplateFileName() { + switch($this->getView()) { + case 'chat': + return AJAX_CHAT_PATH.'lib/template/loggedIn.html'; + case 'logs': + return AJAX_CHAT_PATH.'lib/template/logs.html'; + default: + return AJAX_CHAT_PATH.'lib/template/loggedOut.html'; + } + } + + function initView() { + $this->_view = null; + // "chat" is the default view: + $view = ($this->getRequestVar('view') === null) ? 'chat' : $this->getRequestVar('view'); + if($this->hasAccessTo($view)) { + $this->_view = $view; + } + } + + function getView() { + return $this->_view; + } + + function hasAccessTo($view) { + switch($view) { + case 'chat': + case 'teaser': + if($this->isLoggedIn()) { + return true; + } + return false; + case 'logs': + if($this->isLoggedIn() && ($this->getUserRole() == AJAX_CHAT_ADMIN || + ($this->getConfig('logsUserAccess') && + ($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_USER)) + )) { + return true; + } + return false; + default: + return false; + } + } + + function login() { + // Retrieve valid login user data (from request variables or session data): + $userData = $this->getValidLoginUserData(); + + if(!$userData) { + $this->addInfoMessage('errorInvalidUser'); + return false; + } + + // If the chat is closed, only the admin may login: + if(!$this->isChatOpen() && $userData['userRole'] != AJAX_CHAT_ADMIN) { + $this->addInfoMessage('errorChatClosed'); + return false; + } + + if(!$this->getConfig('allowGuestLogins') && $userData['userRole'] == AJAX_CHAT_GUEST) { + return false; + } + + // Check if userID or userName are already listed online: + if($this->isUserOnline($userData['userID']) || $this->isUserNameInUse($userData['userName'])) { + if($userData['userRole'] == AJAX_CHAT_USER || $userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) { + // Set the registered user inactive and remove the inactive users so the user can be logged in again: + $this->setInactive($userData['userID'], $userData['userName']); + $this->removeInactive(); + } else { + $this->addInfoMessage('errorUserInUse'); + return false; + } + } + + // Check if user is banned: + if($userData['userRole'] != AJAX_CHAT_ADMIN && $this->isUserBanned($userData['userName'], $userData['userID'], $_SERVER['REMOTE_ADDR'])) { + $this->addInfoMessage('errorBanned'); + return false; + } + + // Check if the max number of users is logged in (not affecting moderators or admins): + if(!($userData['userRole'] == AJAX_CHAT_MODERATOR || $userData['userRole'] == AJAX_CHAT_ADMIN) && $this->isMaxUsersLoggedIn()) { + $this->addInfoMessage('errorMaxUsersLoggedIn'); + return false; + } + + // Use a new session id (if session has been started by the chat): + $this->regenerateSessionID(); + + // Log in: + $this->setUserID($userData['userID']); + $this->setUserName($userData['userName']); + $this->setLoginUserName($userData['userName']); + $this->setUserRole($userData['userRole']); + $this->setLoggedIn(true); + $this->setLoginTimeStamp(time()); + + // IP Security check variable: + $this->setSessionIP($_SERVER['REMOTE_ADDR']); + + // The client authenticates to the socket server using a socketRegistrationID: + if($this->getConfig('socketServerEnabled')) { + $this->setSocketRegistrationID( + md5(uniqid(rand(), true)) + ); + } + + // Add userID, userName and userRole to info messages: + $this->addInfoMessage($this->getUserID(), 'userID'); + $this->addInfoMessage($this->getUserName(), 'userName'); + $this->addInfoMessage($this->getUserRole(), 'userRole'); + + // Purge logs: + if($this->getConfig('logsPurgeLogs')) { + $this->purgeLogs(); + } + + return true; + } + + function chatViewLogin() { + $this->setChannel($this->getValidRequestChannelID()); + $this->addToOnlineList(); + + // Add channelID and channelName to info messages: + $this->addInfoMessage($this->getChannel(), 'channelID'); + $this->addInfoMessage($this->getChannelName(), 'channelName'); + + // Login message: + $text = '/login '.$this->getUserName(); + $this->insertChatBotMessage( + $this->getChannel(), + $text, + null, + 1 + ); + } + + function getValidRequestChannelID() { + $channelID = $this->getRequestVar('channelID'); + $channelName = $this->getRequestVar('channelName'); + // Check the given channelID, or get channelID from channelName: + if($channelID === null) { + if($channelName !== null) { + $channelID = $this->getChannelIDFromChannelName($channelName); + // channelName might need encoding conversion: + if($channelID === null) { + $channelID = $this->getChannelIDFromChannelName( + $this->trimChannelName($channelName, $this->getConfig('contentEncoding')) + ); + } + } + } + // Validate the resulting channelID: + if(!$this->validateChannel($channelID)) { + if($this->getChannel() !== null) { + return $this->getChannel(); + } + return $this->getConfig('defaultChannelID'); + } + return $channelID; + } + + function initChannel() { + $channelID = $this->getRequestVar('channelID'); + $channelName = $this->getRequestVar('channelName'); + if($channelID !== null) { + $this->switchChannel($this->getChannelNameFromChannelID($channelID)); + } else if($channelName !== null) { + if($this->getChannelIDFromChannelName($channelName) === null) { + // channelName might need encoding conversion: + $channelName = $this->trimChannelName($channelName, $this->getConfig('contentEncoding')); + } + $this->switchChannel($channelName); + } + } + + function logout($type=null) { + // Update the socket server authentication for the user: + if($this->getConfig('socketServerEnabled')) { + $this->updateSocketAuthentication($this->getUserID()); + } + if($this->isUserOnline()) { + $this->chatViewLogout($type); + } + $this->setLoggedIn(false); + $this->destroySession(); + + // Re-initialize the view: + $this->initView(); + } + + function chatViewLogout($type) { + $this->removeFromOnlineList(); + if($type !== null) { + $type = ' '.$type; + } + // Logout message + $text = '/logout '.$this->getUserName().$type; + $this->insertChatBotMessage( + $this->getChannel(), + $text, + null, + 1 + ); + } + + function switchChannel($channelName) { + $channelID = $this->getChannelIDFromChannelName($channelName); + + if($channelID !== null && $this->getChannel() == $channelID) { + // User is already in the given channel, return: + return; + } + + // Check if we have a valid channel: + if(!$this->validateChannel($channelID)) { + // Invalid channel: + $text = '/error InvalidChannelName '.$channelName; + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + $text + ); + return; + } + + $oldChannel = $this->getChannel(); + + $this->setChannel($channelID); + $this->updateOnlineList(); + + // Channel leave message + $text = '/channelLeave '.$this->getUserName(); + $this->insertChatBotMessage( + $oldChannel, + $text, + null, + 1 + ); + + // Channel enter message + $text = '/channelEnter '.$this->getUserName(); + $this->insertChatBotMessage( + $this->getChannel(), + $text, + null, + 1 + ); + + $this->addInfoMessage($channelName, 'channelSwitch'); + $this->addInfoMessage($channelID, 'channelID'); + $this->_requestVars['lastID'] = 0; + } + + function addToOnlineList() { + $sql = 'INSERT INTO '.$this->getDataBaseTable('online').'( + userID, + userName, + userRole, + channel, + dateTime, + ip + ) + VALUES ( + '.$this->db->makeSafe($this->getUserID()).', + '.$this->db->makeSafe($this->getUserName()).', + '.$this->db->makeSafe($this->getUserRole()).', + '.$this->db->makeSafe($this->getChannel()).', + NOW(), + '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).' + );'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $this->resetOnlineUsersData(); + } + + function removeFromOnlineList() { + $sql = 'DELETE FROM + '.$this->getDataBaseTable('online').' + WHERE + userID = '.$this->db->makeSafe($this->getUserID()).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $this->removeUserFromOnlineUsersData(); + } + + function updateOnlineList() { + $sql = 'UPDATE + '.$this->getDataBaseTable('online').' + SET + userName = '.$this->db->makeSafe($this->getUserName()).', + channel = '.$this->db->makeSafe($this->getChannel()).', + dateTime = NOW(), + ip = '.$this->db->makeSafe($this->ipToStorageFormat($_SERVER['REMOTE_ADDR'])).' + WHERE + userID = '.$this->db->makeSafe($this->getUserID()).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $this->resetOnlineUsersData(); + } + + function initMessageHandling() { + // Don't handle messages if we are not in chat view: + if($this->getView() != 'chat') { + return; + } + + // Check if we have been uninvited from a private or restricted channel: + if(!$this->validateChannel($this->getChannel())) { + // Switch to the default channel: + $this->switchChannel($this->getChannelNameFromChannelID($this->getConfig('defaultChannelID'))); + return; + } + + if($this->getRequestVar('text') !== null) { + $this->insertMessage($this->getRequestVar('text')); + } + } + + function insertParsedMessage($text) { + + // If a queryUserName is set, sent all messages as private messages to this userName: + if($this->getQueryUserName() !== null && strpos($text, '/') !== 0) { + $text = '/msg '.$this->getQueryUserName().' '.$text; + } + + // Parse IRC-style commands: + if(strpos($text, '/') === 0) { + $textParts = explode(' ', $text); + + switch($textParts[0]) { + + // Channel switch: + case '/join': + $this->insertParsedMessageJoin($textParts); + break; + + // Logout: + case '/quit': + $this->logout(); + break; + + // Private message: + case '/msg': + case '/describe': + $this->insertParsedMessagePrivMsg($textParts); + break; + + // Invitation: + case '/invite': + $this->insertParsedMessageInvite($textParts); + break; + + // Uninvitation: + case '/uninvite': + $this->insertParsedMessageUninvite($textParts); + break; + + // Private messaging: + case '/query': + $this->insertParsedMessageQuery($textParts); + break; + + // Kicking offending users from the chat: + case '/kick': + $this->insertParsedMessageKick($textParts); + break; + + // Listing banned users: + case '/bans': + $this->insertParsedMessageBans($textParts); + break; + + // Unban user (remove from ban list): + case '/unban': + $this->insertParsedMessageUnban($textParts); + break; + + // Describing actions: + case '/me': + case '/action': + $this->insertParsedMessageAction($textParts); + break; + + + // Listing online Users: + case '/who': + $this->insertParsedMessageWho($textParts); + break; + + // Listing available channels: + case '/list': + $this->insertParsedMessageList($textParts); + break; + + // Retrieving the channel of a User: + case '/whereis': + $this->insertParsedMessageWhereis($textParts); + break; + + // Listing information about a User: + case '/whois': + $this->insertParsedMessageWhois($textParts); + break; + + // Rolling dice: + case '/roll': + $this->insertParsedMessageRoll($textParts); + break; + + // Switching userName: + case '/nick': + $this->insertParsedMessageNick($textParts); + break; + + // Custom or unknown command: + default: + if(!$this->parseCustomCommands($text, $textParts)) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UnknownCommand '.$textParts[0] + ); + } + } + + } else { + // No command found, just insert the plain message: + $this->insertCustomMessage( + $this->getUserID(), + $this->getUserName(), + $this->getUserRole(), + $this->getChannel(), + $text + ); + } + } + + function insertParsedMessageJoin($textParts) { + if(count($textParts) == 1) { + // join with no arguments is the own private channel, if allowed: + if($this->isAllowedToCreatePrivateChannel()) { + // Private channels are identified by square brackets: + $this->switchChannel($this->getChannelNameFromChannelID($this->getPrivateChannelID())); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingChannelName' + ); + } + } else { + $this->switchChannel($textParts[1]); + } + } + + function insertParsedMessagePrivMsg($textParts) { + if($this->isAllowedToSendPrivateMessage()) { + if(count($textParts) < 3) { + if(count($textParts) == 2) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingText' + ); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } + } else { + // Get UserID from UserName: + $toUserID = $this->getIDFromName($textParts[1]); + if($toUserID === null) { + if($this->getQueryUserName() !== null) { + // Close the current query: + $this->insertMessage('/query'); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } + } else { + // Insert /privaction command if /describe is used: + $command = ($textParts[0] == '/describe') ? '/privaction' : '/privmsg'; + // Copy of private message to current User: + $this->insertCustomMessage( + $this->getUserID(), + $this->getUserName(), + $this->getUserRole(), + $this->getPrivateMessageID(), + $command.'to '.$textParts[1].' '.implode(' ', array_slice($textParts, 2)) + ); + // Private message to requested User: + $this->insertCustomMessage( + $this->getUserID(), + $this->getUserName(), + $this->getUserRole(), + $this->getPrivateMessageID($toUserID), + $command.' '.implode(' ', array_slice($textParts, 2)) + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error PrivateMessageNotAllowed' + ); + } + } + + function insertParsedMessageInvite($textParts) { + if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + $toUserID = $this->getIDFromName($textParts[1]); + if($toUserID === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // Add the invitation to the database: + $this->addInvitation($toUserID); + $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel()); + // Copy of invitation to current User: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/inviteto '.$textParts[1].' '.$invitationChannelName + ); + // Invitation to requested User: + $this->insertChatBotMessage( + $this->getPrivateMessageID($toUserID), + '/invite '.$this->getUserName().' '.$invitationChannelName + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error InviteNotAllowed' + ); + } + } + + function insertParsedMessageUninvite($textParts) { + if($this->getChannel() == $this->getPrivateChannelID() || in_array($this->getChannel(), $this->getChannels())) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + $toUserID = $this->getIDFromName($textParts[1]); + if($toUserID === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // Remove the invitation from the database: + $this->removeInvitation($toUserID); + $invitationChannelName = $this->getChannelNameFromChannelID($this->getChannel()); + // Copy of uninvitation to current User: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/uninviteto '.$textParts[1].' '.$invitationChannelName + ); + // Uninvitation to requested User: + $this->insertChatBotMessage( + $this->getPrivateMessageID($toUserID), + '/uninvite '.$this->getUserName().' '.$invitationChannelName + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UninviteNotAllowed' + ); + } + } + + function insertParsedMessageQuery($textParts) { + if($this->isAllowedToSendPrivateMessage()) { + if(count($textParts) == 1) { + if($this->getQueryUserName() !== null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/queryClose '.$this->getQueryUserName() + ); + // Close the current query: + $this->setQueryUserName(null); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error NoOpenQuery' + ); + } + } else { + if($this->getIDFromName($textParts[1]) === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + if($this->getQueryUserName() !== null) { + // Close the current query: + $this->insertMessage('/query'); + } + // Open a query to the requested user: + $this->setQueryUserName($textParts[1]); + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/queryOpen '.$textParts[1] + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error PrivateMessageNotAllowed' + ); + } + } + + function insertParsedMessageKick($textParts) { + // Only moderators/admins may kick users: + if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + // Get UserID from UserName: + $kickUserID = $this->getIDFromName($textParts[1]); + if($kickUserID === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // Check the role of the user to kick: + $kickUserRole = $this->getRoleFromID($kickUserID); + if($kickUserRole == AJAX_CHAT_ADMIN || ($kickUserRole == AJAX_CHAT_MODERATOR && $this->getUserRole() != AJAX_CHAT_ADMIN)) { + // Admins and moderators may not be kicked: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error KickNotAllowed '.$textParts[1] + ); + } else { + // Kick user and insert message: + $channel = $this->getChannelFromID($kickUserID); + $banMinutes = (count($textParts) > 2) ? $textParts[2] : null; + $this->kickUser($textParts[1], $banMinutes, $kickUserID); + // If no channel found, user logged out before he could be kicked + if($channel !== null) { + $this->insertChatBotMessage( + $channel, + '/kick '.$textParts[1], + null, + 1 + ); + // Send a copy of the message to the current user, if not in the channel: + if($channel != $this->getChannel()) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/kick '.$textParts[1], + null, + 1 + ); + } + } + } + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error CommandNotAllowed '.$textParts[0] + ); + } + } + + function insertParsedMessageBans($textParts) { + // Only moderators/admins may see the list of banned users: + if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { + $this->removeExpiredBans(); + $bannedUsers = $this->getBannedUsers(); + if(count($bannedUsers) > 0) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/bans '.implode(' ', $bannedUsers) + ); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/bansEmpty -' + ); + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error CommandNotAllowed '.$textParts[0] + ); + } + } + + function insertParsedMessageUnban($textParts) { + // Only moderators/admins may unban users: + if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { + $this->removeExpiredBans(); + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + if(!in_array($textParts[1], $this->getBannedUsers())) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // Unban user and insert message: + $this->unbanUser($textParts[1]); + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/unban '.$textParts[1] + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error CommandNotAllowed '.$textParts[0] + ); + } + } + + function insertParsedMessageAction($textParts) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingText' + ); + } else { + if($this->getQueryUserName() !== null) { + // If we are in query mode, sent the action to the query user: + $this->insertMessage('/describe '.$this->getQueryUserName().' '.implode(' ', array_slice($textParts, 1))); + } else { + $this->insertCustomMessage( + $this->getUserID(), + $this->getUserName(), + $this->getUserRole(), + $this->getChannel(), + implode(' ', $textParts) + ); + } + } + } + + function insertParsedMessageWho($textParts) { + if(count($textParts) == 1) { + if($this->isAllowedToListHiddenUsers()) { + // List online users from any channel: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/who '.implode(' ', $this->getOnlineUsers()) + ); + } else { + // Get online users for all accessible channels: + $channels = $this->getChannels(); + // Add the own private channel if allowed: + if($this->isAllowedToCreatePrivateChannel()) { + array_push($channels, $this->getPrivateChannelID()); + } + // Add the invitation channels: + foreach($this->getInvitations() as $channelID) { + if(!in_array($channelID, $channels)) { + array_push($channels, $channelID); + } + } + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/who '.implode(' ', $this->getOnlineUsers($channels)) + ); + } + } else { + $channelName = $textParts[1]; + $channelID = $this->getChannelIDFromChannelName($channelName); + if(!$this->validateChannel($channelID)) { + // Invalid channel: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error InvalidChannelName '.$channelName + ); + } else { + // Get online users for the given channel: + $onlineUsers = $this->getOnlineUsers(array($channelID)); + if(count($onlineUsers) > 0) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/whoChannel '.$channelName.' '.implode(' ', $onlineUsers) + ); + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/whoEmpty -' + ); + } + } + } + } + + function insertParsedMessageList($textParts) { + // Get the names of all accessible channels: + $channelNames = $this->getChannelNames(); + // Add the own private channel, if allowed: + if($this->isAllowedToCreatePrivateChannel()) { + array_push($channelNames, $this->getPrivateChannelName()); + } + // Add the invitation channels: + foreach($this->getInvitations() as $channelID) { + $channelName = $this->getChannelNameFromChannelID($channelID); + if($channelName !== null && !in_array($channelName, $channelNames)) { + array_push($channelNames, $channelName); + } + } + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/list '.implode(' ', $channelNames) + ); + } + + function insertParsedMessageWhereis($textParts) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + // Get UserID from UserName: + $whereisUserID = $this->getIDFromName($textParts[1]); + if($whereisUserID === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + $channelID = $this->getChannelFromID($whereisUserID); + if($this->validateChannel($channelID)) { + $channelName = $this->getChannelNameFromChannelID($channelID); + } else { + $channelName = null; + } + if($channelName === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // List user information: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/whereis '.$textParts[1].' '.$channelName + ); + } + } + } + } + + function insertParsedMessageWhois($textParts) { + // Only moderators/admins: + if($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { + if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + // Get UserID from UserName: + $whoisUserID = $this->getIDFromName($textParts[1]); + if($whoisUserID === null) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameNotFound '.$textParts[1] + ); + } else { + // List user information: + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/whois '.$textParts[1].' '.$this->getIPFromID($whoisUserID) + ); + } + } + } else { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error CommandNotAllowed '.$textParts[0] + ); + } + } + + function insertParsedMessageRoll($textParts) { + if(count($textParts) == 1) { + // default is one d6: + $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6); + } else { + $diceParts = explode('d', $textParts[1]); + if(count($diceParts) == 2) { + $number = (int)$diceParts[0]; + $sides = (int)$diceParts[1]; + + // Dice number must be an integer between 1 and 100, else roll only one: + $number = ($number > 0 && $number <= 100) ? $number : 1; + + // Sides must be an integer between 1 and 100, else take 6: + $sides = ($sides > 0 && $sides <= 100) ? $sides : 6; + + $text = '/roll '.$this->getUserName().' '.$number.'d'.$sides.' '; + for($i=0; $i<$number; $i++) { + if($i != 0) + $text .= ','; + $text .= $this->rollDice($sides); + } + } else { + // if dice syntax is invalid, roll one d6: + $text = '/roll '.$this->getUserName().' 1d6 '.$this->rollDice(6); + } + } + $this->insertChatBotMessage( + $this->getChannel(), + $text + ); + } + + function insertParsedMessageNick($textParts) { + if(!$this->getConfig('allowNickChange') || + (!$this->getConfig('allowGuestUserName') && $this->getUserRole() == AJAX_CHAT_GUEST)) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error CommandNotAllowed '.$textParts[0] + ); + } else if(count($textParts) == 1) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MissingUserName' + ); + } else { + $newUserName = implode(' ', array_slice($textParts, 1)); + if($newUserName == $this->getLoginUserName()) { + // Allow the user to regain the original login userName: + $prefix = ''; + $suffix = ''; + } else if($this->getUserRole() == AJAX_CHAT_GUEST) { + $prefix = $this->getConfig('guestUserPrefix'); + $suffix = $this->getConfig('guestUserSuffix'); + } else { + $prefix = $this->getConfig('changedNickPrefix'); + $suffix = $this->getConfig('changedNickSuffix'); + } + $maxLength = $this->getConfig('userNameMaxLength') + - $this->stringLength($prefix) + - $this->stringLength($suffix); + $newUserName = $this->trimString($newUserName, 'UTF-8', $maxLength, true); + if(!$newUserName) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error InvalidUserName' + ); + } else { + $newUserName = $prefix.$newUserName.$suffix; + if($this->isUserNameInUse($newUserName)) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error UserNameInUse' + ); + } else { + $oldUserName = $this->getUserName(); + $this->setUserName($newUserName); + $this->updateOnlineList(); + // Add info message to update the client-side stored userName: + $this->addInfoMessage($this->getUserName(), 'userName'); + $this->insertChatBotMessage( + $this->getChannel(), + '/nick '.$oldUserName.' '.$newUserName, + null, + 2 + ); + } + } + } + } + + function insertMessage($text) { + if(!$this->isAllowedToWriteMessage()) + return; + + if(!$this->floodControl()) + return; + + $text = $this->trimMessageText($text); + if($text == '') + return; + + if(!$this->onNewMessage($text)) + return; + + $text = $this->replaceCustomText($text); + + $this->insertParsedMessage($text); + } + + function deleteMessage($messageID) { + // Retrieve the channel of the given message: + $sql = 'SELECT + channel + FROM + '.$this->getDataBaseTable('messages').' + WHERE + id='.$this->db->makeSafe($messageID).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $row = $result->fetch(); + + if($row['channel'] !== null) { + $channel = $row['channel']; + + if($this->getUserRole() == AJAX_CHAT_ADMIN) { + $condition = ''; + } else if($this->getUserRole() == AJAX_CHAT_MODERATOR) { + $condition = ' AND + NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).') + AND + NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).')'; + } else if($this->getUserRole() == AJAX_CHAT_USER && $this->getConfig('allowUserMessageDelete')) { + $condition = 'AND + ( + userID='.$this->db->makeSafe($this->getUserID()).' + OR + ( + channel = '.$this->db->makeSafe($this->getPrivateMessageID()).' + OR + channel = '.$this->db->makeSafe($this->getPrivateChannelID()).' + ) + AND + NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_ADMIN).') + AND + NOT (userRole='.$this->db->makeSafe(AJAX_CHAT_CHATBOT).') + )'; + } else { + return false; + } + + // Remove given message from the database: + $sql = 'DELETE FROM + '.$this->getDataBaseTable('messages').' + WHERE + id='.$this->db->makeSafe($messageID).' + '.$condition.';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + if($result->affectedRows() == 1) { + // Insert a deletion command to remove the message from the clients chatlists: + $this->insertChatBotMessage($channel, '/delete '.$messageID); + return true; + } + } + return false; + } + + function floodControl() { + // Moderators and Admins need no flood control: + if($this->getUserRole() == AJAX_CHAT_MODERATOR || $this->getUserRole() == AJAX_CHAT_ADMIN) { + return true; + } + $time = time(); + // Check the time of the last inserted message: + if($this->getInsertedMessagesRateTimeStamp()+60 < $time) { + $this->setInsertedMessagesRateTimeStamp($time); + $this->setInsertedMessagesRate(1); + } else { + // Increase the inserted messages rate: + $rate = $this->getInsertedMessagesRate()+1; + $this->setInsertedMessagesRate($rate); + // Check if message rate is too high: + if($rate > $this->getConfig('maxMessageRate')) { + $this->insertChatBotMessage( + $this->getPrivateMessageID(), + '/error MaxMessageRate' + ); + // Return false so the message is not inserted: + return false; + } + } + return true; + } + + function isAllowedToWriteMessage() { + if($this->getUserRole() != AJAX_CHAT_GUEST) + return true; + if($this->getConfig('allowGuestWrite')) + return true; + return false; + } + + function insertChatBotMessage($channelID, $messageText, $ip=null, $mode=0) { + $this->insertCustomMessage( + $this->getConfig('chatBotID'), + $this->getConfig('chatBotName'), + AJAX_CHAT_CHATBOT, + $channelID, + $messageText, + $ip, + $mode + ); + } + + function insertCustomMessage($userID, $userName, $userRole, $channelID, $text, $ip=null, $mode=0) { + // The $mode parameter is used for socket updates: + // 0 = normal messages + // 1 = channel messages (e.g. login/logout, channel enter/leave, kick) + // 2 = messages with online user updates (nick) + + $ip = $ip ? $ip : $_SERVER['REMOTE_ADDR']; + + $sql = 'INSERT INTO '.$this->getDataBaseTable('messages').'( + userID, + userName, + userRole, + channel, + dateTime, + ip, + text + ) + VALUES ( + '.$this->db->makeSafe($userID).', + '.$this->db->makeSafe($userName).', + '.$this->db->makeSafe($userRole).', + '.$this->db->makeSafe($channelID).', + NOW(), + '.$this->db->makeSafe($this->ipToStorageFormat($ip)).', + '.$this->db->makeSafe($text).' + );'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + if($this->getConfig('socketServerEnabled')) { + $this->sendSocketMessage( + $this->getSocketBroadcastMessage( + $this->db->getLastInsertedID(), + time(), + $userID, + $userName, + $userRole, + $channelID, + $text, + $mode + ) + ); + } + } + + function getSocketBroadcastMessage( + $messageID, + $timeStamp, + $userID, + $userName, + $userRole, + $channelID, + $text, + $mode + ) { + // The $mode parameter: + // 0 = normal messages + // 1 = channel messages (e.g. login/logout, channel enter/leave, kick) + // 2 = messages with online user updates (nick) + + // Get the message XML content: + $xml = ''; + if($mode) { + // Add the list of online users if the user list has been updated ($mode > 0): + $xml .= $this->getChatViewOnlineUsersXML(array($channelID)); + } + if($mode != 1 || $this->getConfig('showChannelMessages')) { + $xml .= ''; + $xml .= $this->getChatViewMessageXML( + $messageID, + $timeStamp, + $userID, + $userName, + $userRole, + $channelID, + $text + ); + $xml .= ''; + } + $xml .= ''; + return $xml; + } + + function sendSocketMessage($message) { + // Open a TCP socket connection to the socket server: + if($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) { + if(@socket_connect($socket, $this->getConfig('socketServerIP'), $this->getConfig('socketServerPort'))) { + // Append a null-byte to the string as EOL (End Of Line) character + // which is required by Flash XML socket communication: + $message .= "\0"; + @socket_write( + $socket, + $message, + strlen($message) // Using strlen to count the bytes instead of the number of UTF-8 characters + ); + } + @socket_close($socket); + } + } + + function updateSocketAuthentication($userID, $socketRegistrationID=null, $channels=null) { + // If no $socketRegistrationID or no $channels are given the authentication is removed for the given user: + $authentication = ''; + if($channels) { + foreach($channels as $channelID) { + $authentication .= ''; + } + } + $authentication .= ''; + $this->sendSocketMessage($authentication); + } + + function setSocketRegistrationID($value) { + $this->setSessionVar('SocketRegistrationID', $value); + } + + function getSocketRegistrationID() { + return $this->getSessionVar('SocketRegistrationID'); + } + + function rollDice($sides) { + return mt_rand(1, $sides); + } + + function kickUser($userName, $banMinutes=null, $userID=null) { + if($userID === null) { + $userID = $this->getIDFromName($userName); + } + if($userID === null) { + return; + } + + $banMinutes = ($banMinutes !== null) ? $banMinutes : $this->getConfig('defaultBanTime'); + + if($banMinutes) { + // Ban User for the given time in minutes: + $this->banUser($userName, $banMinutes, $userID); + } + + // Remove given User from online list: + $sql = 'DELETE FROM + '.$this->getDataBaseTable('online').' + WHERE + userID = '.$this->db->makeSafe($userID).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + // Update the socket server authentication for the kicked user: + if($this->getConfig('socketServerEnabled')) { + $this->updateSocketAuthentication($userID); + } + + $this->removeUserFromOnlineUsersData($userID); + } + + function getBannedUsersData($key=null, $value=null) { + if($this->_bannedUsersData === null) { + $this->_bannedUsersData = array(); + + $sql = 'SELECT + userID, + userName, + ip + FROM + '.$this->getDataBaseTable('bans').' + WHERE + NOW() < dateTime;'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + while($row = $result->fetch()) { + $row['ip'] = $this->ipFromStorageFormat($row['ip']); + array_push($this->_bannedUsersData, $row); + } + + $result->free(); + } + + if($key) { + $bannedUsersData = array(); + foreach($this->_bannedUsersData as $bannedUserData) { + if(!isset($bannedUserData[$key])) { + return $bannedUsersData; + } + if($value) { + if($bannedUserData[$key] == $value) { + array_push($bannedUsersData, $bannedUserData); + } else { + continue; + } + } else { + array_push($bannedUsersData, $bannedUserData[$key]); + } + } + return $bannedUsersData; + } + + return $this->_bannedUsersData; + } + + function getBannedUsers() { + return $this->getBannedUsersData('userName'); + } + + function banUser($userName, $banMinutes=null, $userID=null) { + if($userID === null) { + $userID = $this->getIDFromName($userName); + } + $ip = $this->getIPFromID($userID); + if(!$ip || $userID === null) { + return; + } + + // Remove expired bans: + $this->removeExpiredBans(); + + $banMinutes = (int)$banMinutes; + if(!$banMinutes) { + // If banMinutes is not a valid integer, use the defaultBanTime: + $banMinutes = $this->getConfig('defaultBanTime'); + } + + $sql = 'INSERT INTO '.$this->getDataBaseTable('bans').'( + userID, + userName, + dateTime, + ip + ) + VALUES ( + '.$this->db->makeSafe($userID).', + '.$this->db->makeSafe($userName).', + DATE_ADD(NOW(), interval '.$this->db->makeSafe($banMinutes).' MINUTE), + '.$this->db->makeSafe($this->ipToStorageFormat($ip)).' + );'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function unbanUser($userName) { + $sql = 'DELETE FROM + '.$this->getDataBaseTable('bans').' + WHERE + userName = '.$this->db->makeSafe($userName).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function removeExpiredBans() { + $sql = 'DELETE FROM + '.$this->getDataBaseTable('bans').' + WHERE + dateTime < NOW();'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function setInactive($userID, $userName=null) { + $condition = 'userID='.$this->db->makeSafe($userID); + if($userName !== null) { + $condition .= ' OR userName='.$this->db->makeSafe($userName); + } + $sql = 'UPDATE + '.$this->getDataBaseTable('online').' + SET + dateTime = DATE_SUB(NOW(), interval '.(intval($this->getConfig('inactiveTimeout'))+1).' MINUTE) + WHERE + '.$condition.';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $this->resetOnlineUsersData(); + } + + function removeInactive() { + $sql = 'SELECT + userID, + userName, + channel + FROM + '.$this->getDataBaseTable('online').' + WHERE + NOW() > DATE_ADD(dateTime, interval '.$this->getConfig('inactiveTimeout').' MINUTE);'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + if($result->numRows() > 0) { + $condition = ''; + while($row = $result->fetch()) { + if(!empty($condition)) + $condition .= ' OR '; + // Add userID to condition for removal: + $condition .= 'userID='.$this->db->makeSafe($row['userID']); + + // Update the socket server authentication for the kicked user: + if($this->getConfig('socketServerEnabled')) { + $this->updateSocketAuthentication($row['userID']); + } + + $this->removeUserFromOnlineUsersData($row['userID']); + + // Insert logout timeout message: + $text = '/logout '.$row['userName'].' Timeout'; + $this->insertChatBotMessage( + $row['channel'], + $text, + null, + 1 + ); + } + + $result->free(); + + $sql = 'DELETE FROM + '.$this->getDataBaseTable('online').' + WHERE + '.$condition.';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + } + + function updateOnlineStatus() { + // Update online status every 50 seconds (this allows update requests to be in time): + if(!$this->getStatusUpdateTimeStamp() || ((time() - $this->getStatusUpdateTimeStamp()) > 50)) { + $this->updateOnlineList(); + $this->setStatusUpdateTimeStamp(time()); + } + } + + function checkAndRemoveInactive() { + // Remove inactive users every inactiveCheckInterval: + if(!$this->getInactiveCheckTimeStamp() || ((time() - $this->getInactiveCheckTimeStamp()) > $this->getConfig('inactiveCheckInterval')*60)) { + $this->removeInactive(); + $this->setInactiveCheckTimeStamp(time()); + } + } + + function sendXMLMessages() { + $httpHeader = new AJAXChatHTTPHeader('UTF-8', 'text/xml'); + + // Send HTTP header: + $httpHeader->send(); + + // Output XML messages: + echo $this->getXMLMessages(); + } + + function getXMLMessages() { + switch($this->getView()) { + case 'chat': + return $this->getChatViewXMLMessages(); + case 'teaser': + return $this->getTeaserViewXMLMessages(); + case 'logs': + return $this->getLogsViewXMLMessages(); + default: + return $this->getLogoutXMLMessage(); + } + } + + function getMessageCondition() { + $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')).' + AND ( + channel = '.$this->db->makeSafe($this->getChannel()).' + OR + channel = '.$this->db->makeSafe($this->getPrivateMessageID()).' + ) + AND + '; + if($this->getConfig('requestMessagesPriorChannelEnter') || + ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($this->getChannel(), $this->getConfig('requestMessagesPriorChannelEnterList')))) { + $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)'; + } else { + $condition .= 'dateTime >= FROM_UNIXTIME(' . $this->getChannelEnterTimeStamp() . ')'; + } + return $condition; + } + + function getMessageFilter() { + $filterChannelMessages = ''; + if(!$this->getConfig('showChannelMessages') || $this->getRequestVar('shoutbox')) { + $filterChannelMessages = ' AND NOT ( + text LIKE (\'/login%\') + OR + text LIKE (\'/logout%\') + OR + text LIKE (\'/channelEnter%\') + OR + text LIKE (\'/channelLeave%\') + OR + text LIKE (\'/kick%\') + )'; + } + return $filterChannelMessages; + } + + function getInfoMessagesXML() { + $xml = ''; + // Go through the info messages: + foreach($this->getInfoMessages() as $type=>$infoArray) { + foreach($infoArray as $info) { + $xml .= ''; + $xml .= 'encodeSpecialChars($info).']]>'; + $xml .= ''; + } + } + $xml .= ''; + return $xml; + } + + function getChatViewOnlineUsersXML($channelIDs) { + // Get the online users for the given channels: + $onlineUsersData = $this->getOnlineUsersData($channelIDs); + $xml = ''; + foreach($onlineUsersData as $onlineUserData) { + $xml .= 'encodeSpecialChars($onlineUserData['userName']).']]>'; + $xml .= ''; + } + $xml .= ''; + return $xml; + } + + function getLogoutXMLMessage() { + $xml = ''; + $xml .= ''; + $xml .= ''; + $xml .= ''; + $xml .= 'encodeSpecialChars($this->getConfig('logoutData')).']]>'; + $xml .= ''; + $xml .= ''; + $xml .= ''; + return $xml; + } + + function getChatViewMessageXML( + $messageID, + $timeStamp, + $userID, + $userName, + $userRole, + $channelID, + $text + ) { + $message = 'encodeSpecialChars($userName).']]>'; + $message .= 'encodeSpecialChars($text).']]>'; + $message .= ''; + return $message; + } + + function getChatViewMessagesXML() { + // Get the last messages in descending order (this optimises the LIMIT usage): + $sql = 'SELECT + id, + userID, + userName, + userRole, + channel AS channelID, + UNIX_TIMESTAMP(dateTime) AS timeStamp, + text + FROM + '.$this->getDataBaseTable('messages').' + WHERE + '.$this->getMessageCondition().' + '.$this->getMessageFilter().' + ORDER BY + id + DESC + LIMIT '.$this->getConfig('requestMessagesLimit').';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $messages = ''; + + // Add the messages in reverse order so it is ascending again: + while($row = $result->fetch()) { + $message = $this->getChatViewMessageXML( + $row['id'], + $row['timeStamp'], + $row['userID'], + $row['userName'], + $row['userRole'], + $row['channelID'], + $row['text'] + ); + $messages = $message.$messages; + } + $result->free(); + + $messages = ''.$messages.''; + return $messages; + } + + function getChatViewXMLMessages() { + $xml = ''; + $xml .= ''; + $xml .= $this->getInfoMessagesXML(); + $xml .= $this->getChatViewOnlineUsersXML(array($this->getChannel())); + $xml .= $this->getChatViewMessagesXML(); + $xml .= ''; + return $xml; + } + + function getTeaserMessageCondition() { + $channelID = $this->getValidRequestChannelID(); + $condition = 'channel = '.$this->db->makeSafe($channelID).' + AND + '; + if($this->getConfig('requestMessagesPriorChannelEnter') || + ($this->getConfig('requestMessagesPriorChannelEnterList') && in_array($channelID, $this->getConfig('requestMessagesPriorChannelEnterList')))) { + $condition .= 'NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('requestMessagesTimeDiff').' HOUR)'; + } else { + // Teaser content may not be shown for this channel: + $condition .= '0 = 1'; + } + return $condition; + } + + function getTeaserViewMessagesXML() { + // Get the last messages in descending order (this optimises the LIMIT usage): + $sql = 'SELECT + id, + userID, + userName, + userRole, + channel AS channelID, + UNIX_TIMESTAMP(dateTime) AS timeStamp, + text + FROM + '.$this->getDataBaseTable('messages').' + WHERE + '.$this->getTeaserMessageCondition().' + '.$this->getMessageFilter().' + ORDER BY + id + DESC + LIMIT '.$this->getConfig('requestMessagesLimit').';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $messages = ''; + + // Add the messages in reverse order so it is ascending again: + while($row = $result->fetch()) { + $message = ''; + $message .= 'encodeSpecialChars($row['userName']).']]>'; + $message .= 'encodeSpecialChars($row['text']).']]>'; + $message .= ''; + $messages = $message.$messages; + } + $result->free(); + + $messages = ''.$messages.''; + return $messages; + } + + function getTeaserViewXMLMessages() { + $xml = ''; + $xml .= ''; + $xml .= $this->getInfoMessagesXML(); + $xml .= $this->getTeaserViewMessagesXML(); + $xml .= ''; + return $xml; + } + + function getLogsViewCondition() { + $condition = 'id > '.$this->db->makeSafe($this->getRequestVar('lastID')); + + // Check the channel condition: + switch($this->getRequestVar('channelID')) { + case '-3': + // Just display messages from all accessible channels + if($this->getUserRole() != AJAX_CHAT_ADMIN) { + $condition .= ' AND (channel = '.$this->db->makeSafe($this->getPrivateMessageID()); + $condition .= ' OR channel = '.$this->db->makeSafe($this->getPrivateChannelID()); + foreach($this->getChannels() as $channel) { + if($this->getConfig('logsUserAccessChannelList') && !in_array($channel, $this->getConfig('logsUserAccessChannelList'))) { + continue; + } + $condition .= ' OR channel = '.$this->db->makeSafe($channel); + } + $condition .= ')'; + } + break; + case '-2': + if($this->getUserRole() != AJAX_CHAT_ADMIN) { + $condition .= ' AND channel = '.($this->getPrivateMessageID()); + } else { + $condition .= ' AND channel > '.($this->getConfig('privateMessageDiff')-1); + } + break; + case '-1': + if($this->getUserRole() != AJAX_CHAT_ADMIN) { + $condition .= ' AND channel = '.($this->getPrivateChannelID()); + } else { + $condition .= ' AND (channel > '.($this->getConfig('privateChannelDiff')-1).' AND channel < '.($this->getConfig('privateMessageDiff')).')'; + } + break; + default: + if(($this->getUserRole() == AJAX_CHAT_ADMIN || !$this->getConfig('logsUserAccessChannelList') || in_array($this->getRequestVar('channelID'), $this->getConfig('logsUserAccessChannelList'))) + && $this->validateChannel($this->getRequestVar('channelID'))) { + $condition .= ' AND channel = '.$this->db->makeSafe($this->getRequestVar('channelID')); + } else { + // No valid channel: + $condition .= ' AND 0 = 1'; + } + } + + // Check the period condition: + $hour = ($this->getRequestVar('hour') === null || $this->getRequestVar('hour') > 23 || $this->getRequestVar('hour') < 0) ? null : $this->getRequestVar('hour'); + $day = ($this->getRequestVar('day') === null || $this->getRequestVar('day') > 31 || $this->getRequestVar('day') < 1) ? null : $this->getRequestVar('day'); + $month = ($this->getRequestVar('month') === null || $this->getRequestVar('month') > 12 || $this->getRequestVar('month') < 1) ? null : $this->getRequestVar('month'); + $year = ($this->getRequestVar('year') === null || $this->getRequestVar('year') > date('Y') || $this->getRequestVar('year') < $this->getConfig('logsFirstYear')) ? null : $this->getRequestVar('year'); + + // If a time (hour) is given but no date (year, month, day), use the current date: + if($hour !== null) { + if($day === null) + $day = date('j'); + if($month === null) + $month = date('n'); + if($year === null) + $year = date('Y'); + } + + if($year === null) { + // No year given, so no period condition + } else if($month === null) { + // Define the given year as period: + $periodStart = mktime(0, 0, 0, 1, 1, $year); + // The last day in a month can be expressed by using 0 for the day of the next month: + $periodEnd = mktime(23, 59, 59, 13, 0, $year); + } else if($day === null) { + // Define the given month as period: + $periodStart = mktime(0, 0, 0, $month, 1, $year); + // The last day in a month can be expressed by using 0 for the day of the next month: + $periodEnd = mktime(23, 59, 59, $month+1, 0, $year); + } else if($hour === null){ + // Define the given day as period: + $periodStart = mktime(0, 0, 0, $month, $day, $year); + $periodEnd = mktime(23, 59, 59, $month, $day, $year); + } else { + // Define the given hour as period: + $periodStart = mktime($hour, 0, 0, $month, $day, $year); + $periodEnd = mktime($hour, 59, 59, $month, $day, $year); + } + + if(isset($periodStart)) + $condition .= ' AND dateTime > \''.date('Y-m-d H:i:s', $periodStart).'\' AND dateTime <= \''.date('Y-m-d H:i:s', $periodEnd).'\''; + + // Check the search condition: + if($this->getRequestVar('search')) { + if(($this->getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) && strpos($this->getRequestVar('search'), 'ip=') === 0) { + // Search for messages with the given IP: + $ip = substr($this->getRequestVar('search'), 3); + $condition .= ' AND (ip = '.$this->db->makeSafe($this->ipToStorageFormat($ip)).')'; + } else if(strpos($this->getRequestVar('search'), 'userID=') === 0) { + // Search for messages with the given userID: + $userID = substr($this->getRequestVar('search'), 7); + $condition .= ' AND (userID = '.$this->db->makeSafe($userID).')'; + } else { + // Use the search value as regular expression on message text and username: + $condition .= ' AND (userName REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).' OR text REGEXP '.$this->db->makeSafe($this->getRequestVar('search')).')'; + } + } + + // If no period or search condition is given, just monitor the last messages on the given channel: + if(!isset($periodStart) && !$this->getRequestVar('search')) { + $condition .= ' AND NOW() < DATE_ADD(dateTime, interval '.$this->getConfig('logsRequestMessagesTimeDiff').' HOUR)'; + } + + return $condition; + } + + function getLogsViewMessagesXML() { + $sql = 'SELECT + id, + userID, + userName, + userRole, + channel AS channelID, + UNIX_TIMESTAMP(dateTime) AS timeStamp, + ip, + text + FROM + '.$this->getDataBaseTable('messages').' + WHERE + '.$this->getLogsViewCondition().' + ORDER BY + id + LIMIT '.$this->getConfig('logsRequestMessagesLimit').';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + $xml = ''; + while($row = $result->fetch()) { + $xml .= 'getUserRole() == AJAX_CHAT_ADMIN || $this->getUserRole() == AJAX_CHAT_MODERATOR) { + $xml .= ' ip="'.$this->ipFromStorageFormat($row['ip']).'"'; + } + $xml .= '>'; + $xml .= 'encodeSpecialChars($row['userName']).']]>'; + $xml .= 'encodeSpecialChars($row['text']).']]>'; + $xml .= ''; + } + $result->free(); + + $xml .= ''; + + return $xml; + } + + function getLogsViewXMLMessages() { + $xml = ''; + $xml .= ''; + $xml .= $this->getInfoMessagesXML(); + $xml .= $this->getLogsViewMessagesXML(); + $xml .= ''; + return $xml; + } + + function purgeLogs() { + $sql = 'DELETE FROM + '.$this->getDataBaseTable('messages').' + WHERE + dateTime < DATE_SUB(NOW(), interval '.$this->getConfig('logsPurgeTimeDiff').' DAY);'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function getInfoMessages($type=null) { + if(!isset($this->_infoMessages)) { + $this->_infoMessages = array(); + } + if($type) { + if(!isset($this->_infoMessages[$type])) { + $this->_infoMessages[$type] = array(); + } + return $this->_infoMessages[$type]; + } else { + return $this->_infoMessages; + } + } + + function addInfoMessage($info, $type='error') { + if(!isset($this->_infoMessages)) { + $this->_infoMessages = array(); + } + if(!isset($this->_infoMessages[$type])) { + $this->_infoMessages[$type] = array(); + } + if(!in_array($info, $this->_infoMessages[$type])) { + array_push($this->_infoMessages[$type], $info); + } + } + + function getRequestVars() { + return $this->_requestVars; + } + + function getRequestVar($key) { + if($this->_requestVars && isset($this->_requestVars[$key])) { + return $this->_requestVars[$key]; + } + return null; + } + + function setRequestVar($key, $value) { + if(!$this->_requestVars) { + $this->_requestVars = array(); + } + $this->_requestVars[$key] = $value; + } + + function getOnlineUsersData($channelIDs=null, $key=null, $value=null) { + if($this->_onlineUsersData === null) { + $this->_onlineUsersData = array(); + + $sql = 'SELECT + userID, + userName, + userRole, + channel, + UNIX_TIMESTAMP(dateTime) AS timeStamp, + ip + FROM + '.$this->getDataBaseTable('online').' + ORDER BY + LOWER(userName);'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + while($row = $result->fetch()) { + $row['ip'] = $this->ipFromStorageFormat($row['ip']); + array_push($this->_onlineUsersData, $row); + } + + $result->free(); + } + + if($channelIDs || $key) { + $onlineUsersData = array(); + foreach($this->_onlineUsersData as $userData) { + if($channelIDs && !in_array($userData['channel'], $channelIDs)) { + continue; + } + if($key) { + if(!isset($userData[$key])) { + return $onlineUsersData; + } + if($value !== null) { + if($userData[$key] == $value) { + array_push($onlineUsersData, $userData); + } else { + continue; + } + } else { + array_push($onlineUsersData, $userData[$key]); + } + } else { + array_push($onlineUsersData, $userData); + } + } + return $onlineUsersData; + } + + return $this->_onlineUsersData; + } + + function removeUserFromOnlineUsersData($userID=null) { + if(!$this->_onlineUsersData) { + return; + } + $userID = ($userID === null) ? $this->getUserID() : $userID; + for($i=0; $i_onlineUsersData); $i++) { + if($this->_onlineUsersData[$i]['userID'] == $userID) { + array_splice($this->_onlineUsersData, $i, 1); + break; + } + } + } + + function resetOnlineUsersData() { + $this->_onlineUsersData = null; + } + + function getOnlineUsers($channelIDs=null) { + return $this->getOnlineUsersData($channelIDs, 'userName'); + } + + function getOnlineUserIDs($channelIDs=null) { + return $this->getOnlineUsersData($channelIDs, 'userID'); + } + + function startSession() { + if(!session_id()) { + // Set the session name: + session_name($this->getConfig('sessionName')); + + // Set session cookie parameters: + session_set_cookie_params( + 0, // The session is destroyed on logout anyway, so no use to set this + $this->getConfig('sessionCookiePath'), + $this->getConfig('sessionCookieDomain'), + $this->getConfig('sessionCookieSecure') + ); + + // Start the session: + session_start(); + + // We started a new session: + $this->_sessionNew = true; + } + } + + function destroySession() { + if($this->_sessionNew) { + // Delete all session variables: + $_SESSION = array(); + + // Delete the session cookie: + if (isset($_COOKIE[session_name()])) { + setcookie( + session_name(), + '', + time()-42000, + $this->getConfig('sessionCookiePath'), + $this->getConfig('sessionCookieDomain'), + $this->getConfig('sessionCookieSecure') + ); + } + + // Destroy the session: + session_destroy(); + } else { + // Unset all session variables starting with the sessionKeyPrefix: + foreach($_SESSION as $key=>$value) { + if(strpos($key, $this->getConfig('sessionKeyPrefix')) === 0) { + unset($_SESSION[$key]); + } + } + } + } + + function regenerateSessionID() { + if($this->_sessionNew) { + // Regenerate session id: + @session_regenerate_id(true); + } + } + + function getSessionVar($key, $prefix=null) { + if($prefix === null) + $prefix = $this->getConfig('sessionKeyPrefix'); + + // Return the session value if existing: + if(isset($_SESSION[$prefix.$key])) + return $_SESSION[$prefix.$key]; + else + return null; + } + + function setSessionVar($key, $value, $prefix=null) { + if($prefix === null) + $prefix = $this->getConfig('sessionKeyPrefix'); + + // Set the session value: + $_SESSION[$prefix.$key] = $value; + } + + function getSessionIP() { + return $this->getSessionVar('IP'); + } + + function setSessionIP($ip) { + $this->setSessionVar('IP', $ip); + } + + function getQueryUserName() { + return $this->getSessionVar('QueryUserName'); + } + + function setQueryUserName($userName) { + $this->setSessionVar('QueryUserName', $userName); + } + + function getInvitations() { + if($this->_invitations === null) { + $this->_invitations = array(); + + $sql = 'SELECT + channel + FROM + '.$this->getDataBaseTable('invitations').' + WHERE + userID='.$this->db->makeSafe($this->getUserID()).' + AND + DATE_SUB(NOW(), interval 1 DAY) < dateTime;'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + + while($row = $result->fetch()) { + array_push($this->_invitations, $row['channel']); + } + + $result->free(); + } + return $this->_invitations; + } + + function removeExpiredInvitations() { + $sql = 'DELETE FROM + '.$this->getDataBaseTable('invitations').' + WHERE + DATE_SUB(NOW(), interval 1 DAY) > dateTime;'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function addInvitation($userID, $channelID=null) { + $this->removeExpiredInvitations(); + + $channelID = ($channelID === null) ? $this->getChannel() : $channelID; + + $sql = 'INSERT INTO '.$this->getDataBaseTable('invitations').'( + userID, + channel, + dateTime + ) + VALUES ( + '.$this->db->makeSafe($userID).', + '.$this->db->makeSafe($channelID).', + NOW() + );'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function removeInvitation($userID, $channelID=null) { + $channelID = ($channelID === null) ? $this->getChannel() : $channelID; + + $sql = 'DELETE FROM + '.$this->getDataBaseTable('invitations').' + WHERE + userID='.$this->db->makeSafe($userID).' + AND + channel='.$this->db->makeSafe($channelID).';'; + + // Create a new SQL query: + $result = $this->db->sqlQuery($sql); + + // Stop if an error occurs: + if($result->error()) { + echo $result->getError(); + die(); + } + } + + function getUserID() { + return $this->getSessionVar('UserID'); + } + + function setUserID($id) { + $this->setSessionVar('UserID', $id); + } + + function getUserName() { + return $this->getSessionVar('UserName'); + } + + function setUserName($name) { + $this->setSessionVar('UserName', $name); + } + + function getLoginUserName() { + return $this->getSessionVar('LoginUserName'); + } + + function setLoginUserName($name) { + $this->setSessionVar('LoginUserName', $name); + } + + function getUserRole() { + $userRole = $this->getSessionVar('UserRole'); + if($userRole === null) + return AJAX_CHAT_GUEST; + return $userRole; + } + + function setUserRole($role) { + $this->setSessionVar('UserRole', $role); + } + + function getChannel() { + return $this->getSessionVar('Channel'); + } + + function setChannel($channel) { + $this->setSessionVar('Channel', $channel); + + // Save the channel enter timestamp: + $this->setChannelEnterTimeStamp(time()); + + // Update the channel authentication for the socket server: + if($this->getConfig('socketServerEnabled')) { + $this->updateSocketAuthentication( + $this->getUserID(), + $this->getSocketRegistrationID(), + array($channel,$this->getPrivateMessageID()) + ); + } + + // Reset the logs view socket authentication session var: + if($this->getSessionVar('logsViewSocketAuthenticated')) { + $this->setSessionVar('logsViewSocketAuthenticated', false); + } + } + + function isLoggedIn() { + return (bool)$this->getSessionVar('LoggedIn'); + } + + function setLoggedIn($bool) { + $this->setSessionVar('LoggedIn', $bool); + } + + function getLoginTimeStamp() { + return $this->getSessionVar('LoginTimeStamp'); + } + + function setLoginTimeStamp($time) { + $this->setSessionVar('LoginTimeStamp', $time); + } + + function getChannelEnterTimeStamp() { + return $this->getSessionVar('ChannelEnterTimeStamp'); + } + + function setChannelEnterTimeStamp($time) { + $this->setSessionVar('ChannelEnterTimeStamp', $time); + } + + function getStatusUpdateTimeStamp() { + return $this->getSessionVar('StatusUpdateTimeStamp'); + } + + function setStatusUpdateTimeStamp($time) { + $this->setSessionVar('StatusUpdateTimeStamp', $time); + } + + function getInactiveCheckTimeStamp() { + return $this->getSessionVar('InactiveCheckTimeStamp'); + } + + function setInactiveCheckTimeStamp($time) { + $this->setSessionVar('InactiveCheckTimeStamp', $time); + } + + function getInsertedMessagesRate() { + return $this->getSessionVar('InsertedMessagesRate'); + } + + function setInsertedMessagesRate($rate) { + $this->setSessionVar('InsertedMessagesRate', $rate); + } + + function getInsertedMessagesRateTimeStamp() { + return $this->getSessionVar('InsertedMessagesRateTimeStamp'); + } + + function setInsertedMessagesRateTimeStamp($time) { + $this->setSessionVar('InsertedMessagesRateTimeStamp', $time); + } + + function getLangCode() { + // Get the langCode from request or cookie: + $langCodeCookie = isset($_COOKIE[$this->getConfig('sessionName').'_lang']) ? $_COOKIE[$this->getConfig('sessionName').'_lang'] : null; + $langCode = $this->getRequestVar('lang') ? $this->getRequestVar('lang') : $langCodeCookie; + // Check if the langCode is valid: + if(!in_array($langCode, $this->getConfig('langAvailable'))) { + // Determine the user language: + $language = new AJAXChatLanguage($this->getConfig('langAvailable'), $this->getConfig('langDefault')); + $langCode = $language->getLangCode(); + } + return $langCode; + } + + function setLangCodeCookie() { + setcookie( + $this->getConfig('sessionName').'_lang', + $this->getLangCode(), + time()+60*60*24*$this->getConfig('sessionCookieLifeTime'), + $this->getConfig('sessionCookiePath'), + $this->getConfig('sessionCookieDomain'), + $this->getConfig('sessionCookieSecure') + ); + } + + function removeUnsafeCharacters($str) { + // Remove NO-WS-CTL, non-whitespace control characters (RFC 2822), decimal 1–8, 11–12, 14–31, and 127: + return AJAXChatEncoding::removeUnsafeCharacters($str); + } + + function subString($str, $start=0, $length=null, $encoding='UTF-8') { + return AJAXChatString::subString($str, $start, $length, $encoding); + } + + function stringLength($str, $encoding='UTF-8') { + return AJAXChatString::stringLength($str, $encoding); + } + + function trimMessageText($text) { + return $this->trimString($text, 'UTF-8', $this->getConfig('messageTextMaxLength')); + } + + function trimUserName($userName) { + return $this->trimString($userName, null, $this->getConfig('userNameMaxLength'), true, true); + } + + function trimChannelName($channelName) { + return $this->trimString($channelName, null, null, true, true); + } + + function trimString($str, $sourceEncoding=null, $maxLength=null, $replaceWhitespace=false, $decodeEntities=false, $htmlEntitiesMap=null) { + // Make sure the string contains valid unicode: + $str = $this->convertToUnicode($str, $sourceEncoding); + + // Make sure the string contains no unsafe characters: + $str = $this->removeUnsafeCharacters($str); + + // Strip whitespace from the beginning and end of the string: + $str = trim($str); + + if($replaceWhitespace) { + // Replace any whitespace in the userName with the underscore "_": + $str = preg_replace('/\s/u', '_', $str); + } + + if($decodeEntities) { + // Decode entities: + $str = $this->decodeEntities($str, 'UTF-8', $htmlEntitiesMap); + } + + if($maxLength) { + // Cut the string to the allowed length: + $str = $this->subString($str, 0, $maxLength); + } + + return $str; + } + + function convertToUnicode($str, $sourceEncoding=null) { + if($sourceEncoding === null) { + $sourceEncoding = $this->getConfig('sourceEncoding'); + } + return $this->convertEncoding($str, $sourceEncoding, 'UTF-8'); + } + + function convertFromUnicode($str, $contentEncoding=null) { + if($contentEncoding === null) { + $contentEncoding = $this->getConfig('contentEncoding'); + } + return $this->convertEncoding($str, 'UTF-8', $contentEncoding); + } + + function convertEncoding($str, $charsetFrom, $charsetTo) { + return AJAXChatEncoding::convertEncoding($str, $charsetFrom, $charsetTo); + } + + function encodeEntities($str, $encoding='UTF-8', $convmap=null) { + return AJAXChatEncoding::encodeEntities($str, $encoding, $convmap); + } + + function decodeEntities($str, $encoding='UTF-8', $htmlEntitiesMap=null) { + return AJAXChatEncoding::decodeEntities($str, $encoding, $htmlEntitiesMap); + } + + function htmlEncode($str) { + return AJAXChatEncoding::htmlEncode($str, $this->getConfig('contentEncoding')); + } + + function encodeSpecialChars($str) { + return AJAXChatEncoding::encodeSpecialChars($str); + } + + function decodeSpecialChars($str) { + return AJAXChatEncoding::decodeSpecialChars($str); + } + + function ipToStorageFormat($ip) { + if(function_exists('inet_pton')) { + // ipv4 & ipv6: + return @inet_pton($ip); + } + // Only ipv4: + return @pack('N',@ip2long($ip)); + } + + function ipFromStorageFormat($ip) { + if(function_exists('inet_ntop')) { + // ipv4 & ipv6: + return @inet_ntop($ip); + } + // Only ipv4: + $unpacked = @unpack('Nlong',$ip); + if(isset($unpacked['long'])) { + return @long2ip($unpacked['long']); + } + return null; + } + + function getConfig($key, $subkey=null) { + if($subkey) + return $this->_config[$key][$subkey]; + else + return $this->_config[$key]; + } + + function setConfig($key, $subkey, $value) { + if($subkey) { + if(!isset($this->_config[$key])) { + $this->_config[$key] = array(); + } + $this->_config[$key][$subkey] = $value; + } else { + $this->_config[$key] = $value; + } + } + + function getLang($key=null) { + if(!$this->_lang) { + // Include the language file: + $lang = null; + require(AJAX_CHAT_PATH.'lib/lang/'.$this->getLangCode().'.php'); + $this->_lang = &$lang; + } + if($key === null) + return $this->_lang; + if(isset($this->_lang[$key])) + return $this->_lang[$key]; + return null; + } + + function getChatURL() { + if(defined('AJAX_CHAT_URL')) { + return AJAX_CHAT_URL; + } + + return + (isset($_SERVER['HTTPS']) ? 'https://' : 'http://'). + (isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : ''). + (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME']. + (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443 || $_SERVER['SERVER_PORT'] == 80 ? '' : ':'.$_SERVER['SERVER_PORT']))). + substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')+1); + } + + function getIDFromName($userName) { + $userDataArray = $this->getOnlineUsersData(null,'userName',$userName); + if($userDataArray && isset($userDataArray[0])) { + return $userDataArray[0]['userID']; + } + return null; + } + + function getNameFromID($userID) { + $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); + if($userDataArray && isset($userDataArray[0])) { + return $userDataArray[0]['userName']; + } + return null; + } + + function getChannelFromID($userID) { + $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); + if($userDataArray && isset($userDataArray[0])) { + return $userDataArray[0]['channel']; + } + return null; + } + + function getIPFromID($userID) { + $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); + if($userDataArray && isset($userDataArray[0])) { + return $userDataArray[0]['ip']; + } + return null; + } + + function getRoleFromID($userID) { + $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); + if($userDataArray && isset($userDataArray[0])) { + return $userDataArray[0]['userRole']; + } + return null; + } + + function getChannelNames() { + return array_flip($this->getChannels()); + } + + function getChannelIDFromChannelName($channelName) { + if(!$channelName) + return null; + $channels = $this->getAllChannels(); + if(array_key_exists($channelName,$channels)) { + return $channels[$channelName]; + } + $channelID = null; + // Check if the requested channel is the own private channel: + if($channelName == $this->getPrivateChannelName()) { + return $this->getPrivateChannelID(); + } + // Try to retrieve a private room ID: + $strlenChannelName = $this->stringLength($channelName); + $strlenPrefix = $this->stringLength($this->getConfig('privateChannelPrefix')); + $strlenSuffix = $this->stringLength($this->getConfig('privateChannelSuffix')); + if($this->subString($channelName,0,$strlenPrefix) == $this->getConfig('privateChannelPrefix') + && $this->subString($channelName,$strlenChannelName-$strlenSuffix) == $this->getConfig('privateChannelSuffix')) { + $userName = $this->subString( + $channelName, + $strlenPrefix, + $strlenChannelName-($strlenPrefix+$strlenSuffix) + ); + $userID = $this->getIDFromName($userName); + if($userID !== null) { + $channelID = $this->getPrivateChannelID($userID); + } + } + return $channelID; + } + + function getChannelNameFromChannelID($channelID) { + foreach($this->getAllChannels() as $key=>$value) { + if($value == $channelID) { + return $key; + } + } + // Try to retrieve a private room name: + if($channelID == $this->getPrivateChannelID()) { + return $this->getPrivateChannelName(); + } + $userName = $this->getNameFromID($channelID-$this->getConfig('privateChannelDiff')); + if($userName === null) { + return null; + } + return $this->getPrivateChannelName($userName); + } + + function getChannelName() { + return $this->getChannelNameFromChannelID($this->getChannel()); + } + + function getPrivateChannelName($userName=null) { + if($userName === null) { + $userName = $this->getUserName(); + } + return $this->getConfig('privateChannelPrefix').$userName.$this->getConfig('privateChannelSuffix'); + } + + function getPrivateChannelID($userID=null) { + if($userID === null) { + $userID = $this->getUserID(); + } + return $userID + $this->getConfig('privateChannelDiff'); + } + + function getPrivateMessageID($userID=null) { + if($userID === null) { + $userID = $this->getUserID(); + } + return $userID + $this->getConfig('privateMessageDiff'); + } + + function isAllowedToSendPrivateMessage() { + if($this->getConfig('allowPrivateMessages') || $this->getUserRole() == AJAX_CHAT_ADMIN) { + return true; + } + return false; + } + + function isAllowedToCreatePrivateChannel() { + if($this->getConfig('allowPrivateChannels')) { + switch($this->getUserRole()) { + case AJAX_CHAT_USER: + return true; + case AJAX_CHAT_MODERATOR: + return true; + case AJAX_CHAT_ADMIN: + return true; + default: + return false; + } + } + return false; + } + + function isAllowedToListHiddenUsers() { + // Hidden users are users within private or restricted channels: + switch($this->getUserRole()) { + case AJAX_CHAT_MODERATOR: + return true; + case AJAX_CHAT_ADMIN: + return true; + default: + return false; + } + } + + function isUserOnline($userID=null) { + $userID = ($userID === null) ? $this->getUserID() : $userID; + $userDataArray = $this->getOnlineUsersData(null,'userID',$userID); + if($userDataArray && count($userDataArray) > 0) { + return true; + } + return false; + } + + function isUserNameInUse($userName=null) { + $userName = ($userName === null) ? $this->getUserName() : $userName; + $userDataArray = $this->getOnlineUsersData(null,'userName',$userName); + if($userDataArray && count($userDataArray) > 0) { + return true; + } + return false; + } + + function isUserBanned($userName, $userID=null, $ip=null) { + if($userID !== null) { + $bannedUserDataArray = $this->getBannedUsersData('userID',$userID); + if($bannedUserDataArray && isset($bannedUserDataArray[0])) { + return true; + } + } + if($ip !== null) { + $bannedUserDataArray = $this->getBannedUsersData('ip',$ip); + if($bannedUserDataArray && isset($bannedUserDataArray[0])) { + return true; + } + } + $bannedUserDataArray = $this->getBannedUsersData('userName',$userName); + if($bannedUserDataArray && isset($bannedUserDataArray[0])) { + return true; + } + return false; + } + + function isMaxUsersLoggedIn() { + if(count($this->getOnlineUsersData()) >= $this->getConfig('maxUsersLoggedIn')) { + return true; + } + return false; + } + + function validateChannel($channelID) { + if($channelID === null) { + return false; + } + // Return true for normal channels the user has acces to: + if(in_array($channelID, $this->getChannels())) { + return true; + } + // Return true if the user is allowed to join his own private channel: + if($channelID == $this->getPrivateChannelID() && $this->isAllowedToCreatePrivateChannel()) { + return true; + } + // Return true if the user has been invited to a restricted or private channel: + if(in_array($channelID, $this->getInvitations())) { + return true; + } + // No valid channel, return false: + return false; + } + + function createGuestUserName() { + $maxLength = $this->getConfig('userNameMaxLength') + - $this->stringLength($this->getConfig('guestUserPrefix')) + - $this->stringLength($this->getConfig('guestUserSuffix')); + + // seed with microseconds since last "whole" second: + mt_srand((double)microtime()*1000000); + + // Create a random userName using numbers between 100000 and 999999: + $userName = substr(mt_rand(100000, 999999), 0, $maxLength); + + return $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix'); + } + + // Guest userIDs must not interfere with existing userIDs and must be lower than privateChannelDiff: + function createGuestUserID() { + // seed with microseconds since last "whole" second: + mt_srand((double)microtime()*1000000); + + return mt_rand($this->getConfig('minGuestUserID'), $this->getConfig('privateChannelDiff')-1); + } + + function getGuestUser() { + if(!$this->getConfig('allowGuestLogins')) + return null; + + if($this->getConfig('allowGuestUserName')) { + $maxLength = $this->getConfig('userNameMaxLength') + - $this->stringLength($this->getConfig('guestUserPrefix')) + - $this->stringLength($this->getConfig('guestUserSuffix')); + + // Trim guest userName: + $userName = $this->trimString($this->getRequestVar('userName'), null, $maxLength, true, true); + + // If given userName is invalid, create one: + if(!$userName) { + $userName = $this->createGuestUserName(); + } else { + // Add the guest users prefix and suffix to the given userName: + $userName = $this->getConfig('guestUserPrefix').$userName.$this->getConfig('guestUserSuffix'); + } + } else { + $userName = $this->createGuestUserName(); + } + + $userData = array(); + $userData['userID'] = $this->createGuestUserID(); + $userData['userName'] = $userName; + $userData['userRole'] = AJAX_CHAT_GUEST; + return $userData; + } + + function getCustomVar($key) { + if(!isset($this->_customVars)) + $this->_customVars = array(); + if(!isset($this->_customVars[$key])) + return null; + return $this->_customVars[$key]; + } + + function setCustomVar($key, $value) { + if(!isset($this->_customVars)) + $this->_customVars = array(); + $this->_customVars[$key] = $value; + } + + // Override to replace custom template tags: + // Return the replacement for the given tag (and given tagContent) + function replaceCustomTemplateTags($tag, $tagContent) { + return null; + } + + // Override to initialize custom configuration settings: + function initCustomConfig() { + } + + // Override to add custom request variables: + // Add values to the request variables array: $this->_requestVars['customVariable'] = null; + function initCustomRequestVars() { + } + + // Override to add custom session code right after the session has been started: + function initCustomSession() { + } + + // Override, to parse custom info requests: + // $infoRequest contains the current info request + // Add info responses using the method addInfoMessage($info, $type) + function parseCustomInfoRequest($infoRequest) { + } + + // Override to replace custom text: + // Return replaced text + // $text contains the whole message + function replaceCustomText(&$text) { + return $text; + } + + // Override to add custom commands: + // Return true if a custom command has been successfully parsed, else false + // $text contains the whole message, $textParts the message split up as words array + function parseCustomCommands($text, $textParts) { + return false; + } + + // Override to perform custom actions on new messages: + // Return true if message may be inserted, else false + // $text contains the whole message + function onNewMessage($text) { + return true; + } + + // Override to perform custom actions on new messages: + // Method to set the style cookie depending on user data + function setStyle() { + } + + // Override: + // Returns true if the userID of the logged in user is identical to the userID of the authentication system + // or the user is authenticated as guest in the chat and the authentication system + function revalidateUserID() { + return true; + } + + // Override: + // Returns an associative array containing userName, userID and userRole + // Returns null if login is invalid + function getValidLoginUserData() { + // Check if we have a valid registered user: + if(false) { + // Here is the place to check user authentication + } else { + // Guest users: + return $this->getGuestUser(); + } + } + + // Override: + // Store the channels the current user has access to + // Make sure channel names don't contain any whitespace + function &getChannels() { + if($this->_channels === null) { + $this->_channels = $this->getAllChannels(); + } + return $this->_channels; + } + + // Override: + // Store all existing channels + // Make sure channel names don't contain any whitespace + function &getAllChannels() { + if($this->_allChannels === null) { + $this->_allChannels = array(); + + // Default channel, public to everyone: + $this->_allChannels[$this->trimChannelName($this->getConfig('defaultChannelName'))] = $this->getConfig('defaultChannelID'); + } + return $this->_allChannels; + } + +} +?> diff --git a/chat/lib/class/AJAXChatDataBase.php b/chat/lib/class/AJAXChatDataBase.php index 2cfe621..2143c5a 100644 --- a/chat/lib/class/AJAXChatDataBase.php +++ b/chat/lib/class/AJAXChatDataBase.php @@ -12,7 +12,7 @@ class AJAXChatDataBase { var $_db; - function AJAXChatDataBase(&$dbConnectionConfig) { + function __construct(&$dbConnectionConfig) { switch($dbConnectionConfig['type']) { case 'mysqli': $this->_db = new AJAXChatDatabaseMySQLi($dbConnectionConfig); diff --git a/chat/lib/class/AJAXChatHTTPHeader.php b/chat/lib/class/AJAXChatHTTPHeader.php index f7cff10..7340bfc 100644 --- a/chat/lib/class/AJAXChatHTTPHeader.php +++ b/chat/lib/class/AJAXChatHTTPHeader.php @@ -14,7 +14,7 @@ class AJAXChatHTTPHeader { var $_constant; var $_noCache; - function AJAXChatHTTPHeader($encoding='UTF-8', $contentType=null, $noCache=true) { + function __construct($encoding='UTF-8', $contentType=null, $noCache=true) { if($contentType) { $this->_contentType = $contentType.'; charset='.$encoding; $this->_constant = true; diff --git a/chat/lib/class/AJAXChatLanguage.php b/chat/lib/class/AJAXChatLanguage.php index ce29450..b197247 100644 --- a/chat/lib/class/AJAXChatLanguage.php +++ b/chat/lib/class/AJAXChatLanguage.php @@ -15,7 +15,7 @@ class AJAXChatLanguage { var $_strictMode; var $_langCode; - function AJAXChatLanguage($availableLangCodes, $defaultLangCode, $langCode=null, $strictMode=false) { + function __construct($availableLangCodes, $defaultLangCode, $langCode=null, $strictMode=false) { $this->_regExpAcceptLangCode = '/^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i'; $this->_availableLangCodes = $availableLangCodes; $this->_defaultLangCode = $defaultLangCode; diff --git a/chat/lib/class/AJAXChatMySQLDataBase.php b/chat/lib/class/AJAXChatMySQLDataBase.php index 4ed6020..6dca348 100644 --- a/chat/lib/class/AJAXChatMySQLDataBase.php +++ b/chat/lib/class/AJAXChatMySQLDataBase.php @@ -15,7 +15,7 @@ class AJAXChatDataBaseMySQL { var $_error = ''; var $_dbName; - function AJAXChatDataBaseMySQL(&$dbConnectionConfig) { + function __construct(&$dbConnectionConfig) { $this->_connectionID = $dbConnectionConfig['link']; $this->_dbName = $dbConnectionConfig['name']; } diff --git a/chat/lib/class/AJAXChatMySQLQuery.php b/chat/lib/class/AJAXChatMySQLQuery.php index 188a1f5..f2f3fd4 100644 --- a/chat/lib/class/AJAXChatMySQLQuery.php +++ b/chat/lib/class/AJAXChatMySQLQuery.php @@ -17,7 +17,7 @@ class AJAXChatMySQLQuery { var $_error = ''; // Constructor: - function AJAXChatMySQLQuery($sql, $connectionID = null) { + function __construct($sql, $connectionID = null) { $this->_sql = trim($sql); $this->_connectionID = $connectionID; if($this->_connectionID) { diff --git a/chat/lib/class/AJAXChatMySQLiDataBase.php b/chat/lib/class/AJAXChatMySQLiDataBase.php index 9c64a37..9bc611e 100644 --- a/chat/lib/class/AJAXChatMySQLiDataBase.php +++ b/chat/lib/class/AJAXChatMySQLiDataBase.php @@ -15,7 +15,7 @@ class AJAXChatDataBaseMySQLi { var $_error = ''; var $_dbName; - function AJAXChatDataBaseMySQLi(&$dbConnectionConfig) { + function __construct(&$dbConnectionConfig) { $this->_connectionID = $dbConnectionConfig['link']; $this->_dbName = $dbConnectionConfig['name']; } diff --git a/chat/lib/class/AJAXChatMySQLiQuery.php b/chat/lib/class/AJAXChatMySQLiQuery.php index a55d5f8..f81afd8 100644 --- a/chat/lib/class/AJAXChatMySQLiQuery.php +++ b/chat/lib/class/AJAXChatMySQLiQuery.php @@ -17,7 +17,7 @@ class AJAXChatMySQLiQuery { var $_error = ''; // Constructor: - function AJAXChatMySQLiQuery($sql, $connectionID) { + function __construct($sql, $connectionID) { $this->_sql = trim($sql); $this->_connectionID = $connectionID; $this->_result = $this->_connectionID->query($this->_sql); diff --git a/chat/lib/class/AJAXChatTemplate.php b/chat/lib/class/AJAXChatTemplate.php index e4d22d8..16e53a7 100644 --- a/chat/lib/class/AJAXChatTemplate.php +++ b/chat/lib/class/AJAXChatTemplate.php @@ -18,7 +18,7 @@ class AJAXChatTemplate { var $_parsedContent; // Constructor: - function AJAXChatTemplate(&$ajaxChat, $templateFile, $contentType=null) { + function __construct(&$ajaxChat, $templateFile, $contentType=null) { $this->ajaxChat = $ajaxChat; $this->_regExpTemplateTags = '/\[(\w+?)(?:(?:\/)|(?:\](.+?)\[\/\1))\]/s'; $this->_templateFile = $templateFile; diff --git a/chat/lib/config.php b/chat/lib/config.php index 13562da..06fa63f 100644 --- a/chat/lib/config.php +++ b/chat/lib/config.php @@ -8,6 +8,8 @@ */ // Define AJAX Chat user roles: +define('AJAX_CHAT_BANNED', 6); +define('AJAX_CHAT_CUSTOM', 5); define('AJAX_CHAT_CHATBOT', 4); define('AJAX_CHAT_ADMIN', 3); define('AJAX_CHAT_MODERATOR', 2); @@ -55,7 +57,7 @@ ); // Available styles: -$config['styleAvailable'] = array('beige','black','grey','Oxygen','Lithium','Sulfur','Cobalt','Mercury','Uranium','Plum','prosilver','subblack2','subSilver','Core','MyBB','vBulletin'); +$config['styleAvailable'] = array('beige','black','grey','Oxygen','Lithium','Sulfur','Cobalt','Mercury','Uranium','Pine','Plum','prosilver','Core','MyBB','vBulletin','XenForo'); // Default style: $config['styleDefault'] = 'MyBB'; @@ -206,4 +208,4 @@ $config['socketServerPort'] = 1935; // This ID can be used to distinguish between different chat installations using the same socket server: $config['socketServerChatID'] = 0; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ar.php b/chat/lib/lang/ar.php index af9c830..b04e55c 100644 --- a/chat/lib/lang/ar.php +++ b/chat/lib/lang/ar.php @@ -1,124 +1,127 @@ - \ No newline at end of file + +$lang = array(); +$lang['title'] = 'AJAX Chat'; +$lang['userName'] = 'اسم المستخدم'; +$lang['password'] = 'كلمة المرور'; +$lang['login'] = 'دخول'; +$lang['logout'] = 'خروج'; +$lang['channel'] = 'الغرÙØ©'; +$lang['style'] = 'الشكل'; +$lang['language'] = 'اللغة'; +$lang['inputLineBreak'] = 'Press SHIFT+ENTER to input a line break'; +$lang['messageSubmit'] = 'ارسل'; +$lang['registeredUsers'] = 'الأعضاء المسجلين'; +$lang['onlineUsers'] = 'الأعضاء المتواجدين'; +$lang['toggleAutoScroll'] = 'Autoscroll on/off'; +$lang['toggleAudio'] = 'Sound on/off'; +$lang['toggleHelp'] = 'Show/hide help'; +$lang['toggleSettings'] = 'Show/hide settings'; +$lang['toggleOnlineList'] = 'Show/hide online list'; +$lang['bbCodeLabelBold'] = 'b'; +$lang['bbCodeLabelItalic'] = 'i'; +$lang['bbCodeLabelUnderline'] = 'u'; +$lang['bbCodeLabelQuote'] = 'اقتباس'; +$lang['bbCodeLabelCode'] = 'كود'; +$lang['bbCodeLabelURL'] = 'رابط'; +$lang['bbCodeLabelImg'] = 'Image'; +$lang['bbCodeLabelColor'] = 'لون الخط'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; +$lang['bbCodeTitleBold'] = 'نص عريض: [b]نص[/b]'; +$lang['bbCodeTitleItalic'] = 'نص مائل: [i]نص[/i]'; +$lang['bbCodeTitleUnderline'] = 'نص تحته خط: [u]نص[/u]'; +$lang['bbCodeTitleQuote'] = 'نص مقتبس: [quote]نص[/quote] او [quote=الكاتب]نص[/quote]'; +$lang['bbCodeTitleCode'] = 'عرض الكود: [code]كود[/code]'; +$lang['bbCodeTitleURL'] = 'ادحال رابط: [url]http://example.org[/url] او [url=http://example.org]نص[/url]'; +$lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; +$lang['bbCodeTitleColor'] = 'لون النص: [color=red]نص[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; +$lang['help'] = 'مساعدة'; +$lang['helpItemDescJoin'] = 'دخول الغرÙØ©:'; +$lang['helpItemCodeJoin'] = '/join اسم الغرÙØ©'; +$lang['helpItemDescJoinCreate'] = 'انشاء غرÙØ© خاصة (للمسجلين Ùقط):'; +$lang['helpItemCodeJoinCreate'] = '/join'; +$lang['helpItemDescInvite'] = 'دعوة احد (لغرÙØ© خاصة مثلا):'; +$lang['helpItemCodeInvite'] = '/invite username'; +$lang['helpItemDescUninvite'] = 'الغاء الدعوة:'; +$lang['helpItemCodeUninvite'] = '/uninvite Username'; +$lang['helpItemDescLogout'] = 'خروج:'; +$lang['helpItemCodeLogout'] = '/quit'; +$lang['helpItemDescPrivateMessage'] = 'رسالة خاصة:'; +$lang['helpItemCodePrivateMessage'] = '/msg Username نص'; +$lang['helpItemDescQueryOpen'] = 'Ùتح ناÙذة خاصة:'; +$lang['helpItemCodeQueryOpen'] = '/query Username'; +$lang['helpItemDescQueryClose'] = 'غلق الناÙذة الخاصة:'; +$lang['helpItemCodeQueryClose'] = '/query'; +$lang['helpItemDescAction'] = 'وص٠الحدث:'; +$lang['helpItemCodeAction'] = '/action نص'; +$lang['helpItemDescDescribe'] = 'وص٠حدث برسالة خاصة:'; +$lang['helpItemCodeDescribe'] = '/describe Username نص'; +$lang['helpItemDescIgnore'] = 'تجاهل/قبول رسائل خاصة من:'; +$lang['helpItemCodeIgnore'] = '/ignore Username'; +$lang['helpItemDescIgnoreList'] = 'الأعضاء المتجاهلين:'; +$lang['helpItemCodeIgnoreList'] = '/ignore'; +$lang['helpItemDescWhereis'] = 'Display user channel:'; +$lang['helpItemCodeWhereis'] = '/whereis Username'; +$lang['helpItemDescKick'] = 'حظر مستخدمين (للمديرين Ùقط):'; +$lang['helpItemCodeKick'] = '/kick Username [دقائق الحظر]'; +$lang['helpItemDescUnban'] = 'الغاء حظر عضو (للمديرين Ùقط):'; +$lang['helpItemCodeUnban'] = '/unban Username'; +$lang['helpItemDescBans'] = 'الأعضاء المحظورين (للمديرين Ùقط):'; +$lang['helpItemCodeBans'] = '/bans'; +$lang['helpItemDescWhois'] = 'عرض الأى بى للمستخدم (المديرين Ùقط):'; +$lang['helpItemCodeWhois'] = '/whois Username'; +$lang['helpItemDescWho'] = 'الأعضاء المتواجدين:'; +$lang['helpItemCodeWho'] = '/who [Channelname]'; +$lang['helpItemDescList'] = 'القنوات المتواÙرة:'; +$lang['helpItemCodeList'] = '/list'; +$lang['helpItemDescRoll'] = 'Roll dice:'; +$lang['helpItemCodeRoll'] = '/roll [number]d[sides]'; +$lang['helpItemDescNick'] = 'Change username:'; +$lang['helpItemCodeNick'] = '/nick Username'; +$lang['settings'] = 'Settings'; +$lang['settingsBBCode'] = 'Enable BBCode:'; +$lang['settingsBBCodeImages'] = 'Enable image BBCode:'; +$lang['settingsBBCodeColors'] = 'Enable font color BBCode:'; +$lang['settingsHyperLinks'] = 'Enable hyperlinks:'; +$lang['settingsLineBreaks'] = 'Enable line breaks:'; +$lang['settingsEmoticons'] = 'Enable emoticons:'; +$lang['settingsAutoFocus'] = 'Automatically set the focus on the input field:'; +$lang['settingsMaxMessages'] = 'Maximum number of messages in the chatlist:'; +$lang['settingsWordWrap'] = 'Enable wrapping of long words:'; +$lang['settingsMaxWordLength'] = 'Maximum length of a word before it gets wrapped:'; +$lang['settingsDateFormat'] = 'Format of date and time display:'; +$lang['settingsPersistFontColor'] = 'Persist font color:'; +$lang['settingsAudioVolume'] = 'Sound Volume:'; +$lang['settingsSoundReceive'] = 'Sound for incoming messages:'; +$lang['settingsSoundSend'] = 'Sound for outgoing messages:'; +$lang['settingsSoundEnter'] = 'Sound for login and channel enter messages:'; +$lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; +$lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; +$lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; +$lang['settingsBlink'] = 'Blink window title on new messages:'; +$lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; +$lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; +$lang['playSelectedSound'] = 'Play selected sound'; +$lang['requiresJavaScript'] = 'يجب دعم الجاÙØ© سكريبت لهذا الشات.'; +$lang['errorInvalidUser'] = 'اسم مستخدم خطأ.'; +$lang['errorUserInUse'] = 'اسم المستخدم مستخدم.'; +$lang['errorBanned'] = 'المستخدم او عنوان الأى بى محظور.'; +$lang['errorMaxUsersLoggedIn'] = 'الشات به الحد الأقصى من الأعضاء المسجلين.'; +$lang['errorChatClosed'] = 'الشات مغلق حاليا.'; +$lang['logsTitle'] = 'سحل الشات'; +$lang['logsDate'] = 'التاريخ'; +$lang['logsTime'] = 'الوقت'; +$lang['logsSearch'] = 'بحث'; +$lang['logsPrivateChannels'] = 'القنوات الخاصة'; +$lang['logsPrivateMessages'] = 'الرسائل الخاصة'; +?> diff --git a/chat/lib/lang/bg.php b/chat/lib/lang/bg.php index 46d6af1..1a5e43d 100644 --- a/chat/lib/lang/bg.php +++ b/chat/lib/lang/bg.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Картинка'; $lang['bbCodeLabelColor'] = 'ЦвÑÑ‚ на шрифта'; +$lang['bbCodeLabelEmoticon'] = 'УÑмивките'; $lang['bbCodeTitleBold'] = 'Получер текÑÑ‚: [b]текÑÑ‚[/b]'; $lang['bbCodeTitleItalic'] = 'КурÑивен текÑÑ‚: [i]текÑÑ‚[/i]'; $lang['bbCodeTitleUnderline'] = 'Подчертан текÑÑ‚: [u]текÑÑ‚[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'URL: [url]http://example.org[/url] или [url=http://example.org]текÑÑ‚[/url]'; $lang['bbCodeTitleImg'] = 'Вмъкване на картинка: [img]http://primer.org/kartinka.jpg[/img]'; $lang['bbCodeTitleColor'] = 'ЦвÑÑ‚ на шрифта: [color=red]текÑÑ‚[/color]'; +$lang['bbCodeTitleEmoticon'] = 'ÑпиÑък УÑмивките'; $lang['help'] = 'Помощ'; $lang['helpItemDescJoin'] = 'ПриÑъединÑване към канал:'; $lang['helpItemCodeJoin'] = '/join име_на_канал'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Звук за ÑъобщениÑта за излизане от чата или от канала:'; $lang['settingsSoundChatBot'] = 'Звук за ÑъобщениÑта на чатбота:'; $lang['settingsSoundError'] = 'Звук за ÑъобщениÑта за грешки:'; +$lang['settingsSoundPrivate'] = 'Звук за лични за ÑъобщениÑта:'; $lang['settingsBlink'] = 'Примигване на прозоречното заглавие при нови ÑъобщениÑ:'; $lang['settingsBlinkInterval'] = 'Интервал на примигване в милиÑекунди:'; $lang['settingsBlinkIntervalNumber'] = 'Брой пъти на примигване:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'ТърÑене'; $lang['logsPrivateChannels'] = 'Лични канали'; $lang['logsPrivateMessages'] = 'Лични ÑъобщениÑ'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ca.php b/chat/lib/lang/ca.php index e45c376..d059a3b 100644 --- a/chat/lib/lang/ca.php +++ b/chat/lib/lang/ca.php @@ -1,125 +1,128 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/cy.php b/chat/lib/lang/cy.php index dea446d..9e47e45 100644 --- a/chat/lib/lang/cy.php +++ b/chat/lib/lang/cy.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/cz.php b/chat/lib/lang/cz.php index cc6868c..4eb3ca2 100644 --- a/chat/lib/lang/cz.php +++ b/chat/lib/lang/cz.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Obrázek'; $lang['bbCodeLabelColor'] = 'Barva písma'; +$lang['bbCodeLabelEmoticon'] = 'Smajlíky'; $lang['bbCodeTitleBold'] = 'TuÄnÄ›: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Kurzívou: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Podtržené: [u]text[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Vložit URL: [url]http://example.org[/url] nebo [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Vložit obrázek: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Barva písma: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smajlíky list'; $lang['help'] = 'NápovÄ›da'; $lang['helpItemDescJoin'] = 'Vstup do místnosti:'; $lang['helpItemCodeJoin'] = '/join Místnost'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Zvuk pÅ™i odhlášení nebo odchodu z místnosti:'; $lang['settingsSoundChatBot'] = 'Zvuk pÅ™i zprávÄ› chatbota:'; $lang['settingsSoundError'] = 'Zvuk pÅ™i chybové zprávÄ›:'; +$lang['settingsSoundPrivate'] = 'Zvuk soukromých zpráv:'; $lang['settingsBlink'] = 'Blikání titulku okna pÅ™i příchozí zprávÄ›:'; $lang['settingsBlinkInterval'] = 'Interval blikání v milisekundách:'; $lang['settingsBlinkIntervalNumber'] = 'PoÄet bliknutí:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Hledej'; $lang['logsPrivateChannels'] = 'Soukromé místnosti'; $lang['logsPrivateMessages'] = 'Soukromé zprávy'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/da.php b/chat/lib/lang/da.php index 55e7eff..d710eb6 100644 --- a/chat/lib/lang/da.php +++ b/chat/lib/lang/da.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Billede'; $lang['bbCodeLabelColor'] = 'Font Farve'; +$lang['bbCodeLabelEmoticon'] = 'Smileys'; $lang['bbCodeTitleBold'] = 'Fed tekst: [b]tekstt[/b]'; $lang['bbCodeTitleItalic'] = 'Kursiv tekst: [i]tekst[/i]'; $lang['bbCodeTitleUnderline'] = 'Understreget tekst: [u]tekst[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Indsæt URL: [url]http://example.org[/url] eller [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Indsæt image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Font Farve: [color=red]tekst[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smileys list'; $lang['help'] = 'Hjælp'; $lang['helpItemDescJoin'] = 'Deltag i en kanal:'; $lang['helpItemCodeJoin'] = '/join Kanalnavn'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Lyd ved login og forlad kanal beskeder:'; $lang['settingsSoundChatBot'] = 'Lyd ved ChatBot beskeder:'; $lang['settingsSoundError'] = 'Lyd ved fejlmeddelse:'; +$lang['settingsSoundPrivate'] = 'Lyd ved privat beskeder:'; $lang['settingsBlink'] = 'Blink vindue titel ved nye beskeder:'; $lang['settingsBlinkInterval'] = 'Blink interval i millisekonder:'; $lang['settingsBlinkIntervalNumber'] = 'Antal blink intervaler:'; diff --git a/chat/lib/lang/de.php b/chat/lib/lang/de.php index f345d10..9522648 100644 --- a/chat/lib/lang/de.php +++ b/chat/lib/lang/de.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Bild'; $lang['bbCodeLabelColor'] = 'Schriftfarbe'; +$lang['bbCodeLabelEmoticon'] = 'Smileys'; $lang['bbCodeTitleBold'] = 'Fett: [b]Text[/b]'; $lang['bbCodeTitleItalic'] = 'Kursiv: [i]Text[/i]'; $lang['bbCodeTitleUnderline'] = 'Unterstrichen: [u]Text[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Link einfügen: [url]http://example.org[/url] oder [url=http://example.org]Text[/url]'; $lang['bbCodeTitleImg'] = 'Bild einfügen: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Schriftfarbe: [color=red]Text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smileys list'; $lang['help'] = 'Hilfe'; $lang['helpItemDescJoin'] = 'Raum betreten:'; $lang['helpItemCodeJoin'] = '/join Raumname'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Klang für Logouts und das Verlassen von Räumen:'; $lang['settingsSoundChatBot'] = 'Klang für Chatbot Nachrichten:'; $lang['settingsSoundError'] = 'Klang für Fehlermeldungen:'; +$lang['settingsSoundPrivate'] = 'Klang für private Nachrichten:'; $lang['settingsBlink'] = 'Blinkender Fenstertitel bei neuen Nachrichten:'; $lang['settingsBlinkInterval'] = 'Blink-Intervall in Millisekunden:'; $lang['settingsBlinkIntervalNumber'] = 'Anzahl der Blink-Intervalle:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Suche'; $lang['logsPrivateChannels'] = 'Private Räume'; $lang['logsPrivateMessages'] = 'Private Nachrichten'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/el.php b/chat/lib/lang/el.php index 526c31b..a906ca8 100644 --- a/chat/lib/lang/el.php +++ b/chat/lib/lang/el.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'ΧÏώμα γÏαμματοσειÏάς'; +$lang['bbCodeLabelEmoticon'] = 'Smilies list'; $lang['bbCodeTitleBold'] = 'Έντονο κείμενο: [b]κείμενο[/b]'; $lang['bbCodeTitleItalic'] = 'Πλάγια γÏαφή: [i]κείμενο[/i]'; $lang['bbCodeTitleUnderline'] = 'ΥπογÏαμμισμένο κείμενο: [u]κείμενο[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Εισαγωγή URL: [url]http://example.org[/url] ή [url=http://example.org]κείμενο[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'ΧÏώμα γÏαμματοσειÏάς: [color=red]κείμενο[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = 'Βοήθεια'; $lang['helpItemDescJoin'] = 'Είσοδος σε ένα κανάλι:'; $lang['helpItemCodeJoin'] = '/join όνομα_καναλιοÏ'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Ήχος για μηνÏματα αποχώÏισης και αποσÏνδεσης:'; $lang['settingsSoundChatBot'] = 'Ήχος για μηνÏματα του chatbot:'; $lang['settingsSoundError'] = 'Ήχος για μηνÏματα λάθους:'; +$lang['settingsSoundPrivate'] = 'Ήχος για Ï€Ïοσωπικά μηνÏματα:'; $lang['settingsBlink'] = 'Αναβόσβημα τίτλου σε νέα μηνÏματα:'; $lang['settingsBlinkInterval'] = 'Ρυθμός αναβοσβήματος σε χιλιοστά του δευτεÏόλεπτου:'; $lang['settingsBlinkIntervalNumber'] = 'ΑÏιθμός αναβοσβήματος οθόνης:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Αναζήτηση'; $lang['logsPrivateChannels'] = 'ΠÏιβέ κανάλια'; $lang['logsPrivateMessages'] = 'Ï€Ïοσωπικά μηνÏματα'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/en.php b/chat/lib/lang/en.php index cb9492b..97e18cf 100644 --- a/chat/lib/lang/en.php +++ b/chat/lib/lang/en.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Font Color'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Bold text: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Italic text: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Underline text: [u]text[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Insert URL: [url]http://example.org[/url] or [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Font Color: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Help'; $lang['helpItemDescJoin'] = 'Join a channel:'; $lang['helpItemCodeJoin'] = '/join Channelname'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; $lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; $lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'Blink window title on new messages:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Search'; $lang['logsPrivateChannels'] = 'Private Channels'; $lang['logsPrivateMessages'] = 'Private Messages'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/es.php b/chat/lib/lang/es.php index 27b9b72..afc91c8 100644 --- a/chat/lib/lang/es.php +++ b/chat/lib/lang/es.php @@ -1,124 +1,127 @@ - \ No newline at end of file + +$lang = array(); +$lang['title'] = 'AJAX Chat'; +$lang['userName'] = 'Usuario'; +$lang['password'] = 'Contraseña'; +$lang['login'] = 'Conectar'; +$lang['logout'] = 'Desconectar'; +$lang['channel'] = 'Canal'; +$lang['style'] = 'Estilo'; +$lang['language'] = 'Idioma'; +$lang['inputLineBreak'] = 'Pulse SHIFT+ENTER para insertar un salto de línea'; +$lang['messageSubmit'] = 'Enviar'; +$lang['registeredUsers'] = 'Usuarios Registrados'; +$lang['onlineUsers'] = 'Usuarios Conectados'; +$lang['toggleAutoScroll'] = 'Autoscroll on/off'; +$lang['toggleAudio'] = 'Sonido on/off'; +$lang['toggleHelp'] = 'Mostrar/ocultar ayuda'; +$lang['toggleSettings'] = 'Mostrar/ocultar configuración'; +$lang['toggleOnlineList'] = 'Mostrar/ocultar lista conectados'; +$lang['bbCodeLabelBold'] = 'b'; +$lang['bbCodeLabelItalic'] = 'i'; +$lang['bbCodeLabelUnderline'] = 'u'; +$lang['bbCodeLabelQuote'] = 'Citar'; +$lang['bbCodeLabelCode'] = 'Código'; +$lang['bbCodeLabelURL'] = 'URL'; +$lang['bbCodeLabelImg'] = 'Imagen'; +$lang['bbCodeLabelColor'] = 'Color de Fuente'; +$lang['bbCodeLabelEmoticon'] = 'Emoticonos listo'; +$lang['bbCodeTitleBold'] = 'Texto Negrita: [b]texto[/b]'; +$lang['bbCodeTitleItalic'] = 'Texto Cursiva: [i]texto[/i]'; +$lang['bbCodeTitleUnderline'] = 'Texto Subrayado: [u]texto[/u]'; +$lang['bbCodeTitleQuote'] = 'Texto Citado: [quote]texto[/quote] o [quote=author]text[/quote]'; +$lang['bbCodeTitleCode'] = 'Mostrar código: [code]código[/code]'; +$lang['bbCodeTitleURL'] = 'Insertar URL: [url]http://example.org[/url] or [url=http://example.org]texto[/url]'; +$lang['bbCodeTitleImg'] = 'Insertar imagen: [img]http://example.org/imagen.jpg[/img]'; +$lang['bbCodeTitleColor'] = 'Color de Fuente: [color=red]texto[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticonos list'; +$lang['help'] = 'Ayuda'; +$lang['helpItemDescJoin'] = 'Entrar en canal:'; +$lang['helpItemCodeJoin'] = '/join nombre del canal'; +$lang['helpItemDescJoinCreate'] = 'Crear un canal privado (Solo usuarios registrados):'; +$lang['helpItemCodeJoinCreate'] = '/join'; +$lang['helpItemDescInvite'] = 'Invitar a alguien (por ejemplo a un canal privado):'; +$lang['helpItemCodeInvite'] = '/invite Usuario'; +$lang['helpItemDescUninvite'] = 'Anular invitación:'; +$lang['helpItemCodeUninvite'] = '/uninvite Usuario'; +$lang['helpItemDescLogout'] = 'Cerrar sesión:'; +$lang['helpItemCodeLogout'] = '/quit'; +$lang['helpItemDescPrivateMessage'] = 'Mensaje Privado:'; +$lang['helpItemCodePrivateMessage'] = '/msg Usuario Texto'; +$lang['helpItemDescQueryOpen'] = 'Abrir un privado:'; +$lang['helpItemCodeQueryOpen'] = '/query Usuario'; +$lang['helpItemDescQueryClose'] = 'Cerrar privado:'; +$lang['helpItemCodeQueryClose'] = '/query'; +$lang['helpItemDescAction'] = 'Describir acción:'; +$lang['helpItemCodeAction'] = '/action Texto'; +$lang['helpItemDescDescribe'] = 'Describir acción en mensaje privado:'; +$lang['helpItemCodeDescribe'] = '/describe Usuario Texto'; +$lang['helpItemDescIgnore'] = 'Ignorar/Aceptar mensajes de usuarios:'; +$lang['helpItemCodeIgnore'] = '/ignore Usuario'; +$lang['helpItemDescIgnoreList'] = 'Mostrar usuarios ignorados:'; +$lang['helpItemCodeIgnoreList'] = '/ignore'; +$lang['helpItemDescWhereis'] = 'Mostrar canal del usuario:'; +$lang['helpItemCodeWhereis'] = '/whereis Usuario'; +$lang['helpItemDescKick'] = 'Patear usuario (Solo moderadores):'; +$lang['helpItemCodeKick'] = '/kick Usuario [Minutos baneado]'; +$lang['helpItemDescUnban'] = 'Quitar ban usuario (Solo moderadores):'; +$lang['helpItemCodeUnban'] = '/unban Usuario'; +$lang['helpItemDescBans'] = 'Listar usuarios baneados (Solo moderadores):'; +$lang['helpItemCodeBans'] = '/bans'; +$lang['helpItemDescWhois'] = 'Mostrar ips de usuarios (Solo moderadores):'; +$lang['helpItemCodeWhois'] = '/whois Usuario'; +$lang['helpItemDescWho'] = 'Mostrar usuarios conectados:'; +$lang['helpItemCodeWho'] = '/who [Channelname]'; +$lang['helpItemDescList'] = 'Lista de canales disponibles:'; +$lang['helpItemCodeList'] = '/list'; +$lang['helpItemDescRoll'] = 'Tirar dado:'; +$lang['helpItemCodeRoll'] = '/roll [numero]de[lados]'; +$lang['helpItemDescNick'] = 'Cambiar nombre de usuario:'; +$lang['helpItemCodeNick'] = '/nick Usuario'; +$lang['settings'] = 'Configuración'; +$lang['settingsBBCode'] = 'Permitir BBCode:'; +$lang['settingsBBCodeImages'] = 'Permitir BBCode de imagen:'; +$lang['settingsBBCodeColors'] = 'Permitir BBCode de color de fuente:'; +$lang['settingsHyperLinks'] = 'Permitir enlaces:'; +$lang['settingsLineBreaks'] = 'Permitir saltos de línea:'; +$lang['settingsEmoticons'] = 'Permitir emoticonos:'; +$lang['settingsAutoFocus'] = 'Seleccionar el cuadro de ingreso automáticamente:'; +$lang['settingsMaxMessages'] = 'Máximo número de mensajes en la lista del chat:'; +$lang['settingsWordWrap'] = 'Permitir la separación del las palabras largas:'; +$lang['settingsMaxWordLength'] = 'Máximo tamaño de una palabara antes de que se separe:'; +$lang['settingsDateFormat'] = 'Formato de la fecha y hora a mostrar:'; +$lang['settingsPersistFontColor'] = 'Mantener el color de la fuente:'; +$lang['settingsAudioVolume'] = 'Volumen Sonido:'; +$lang['settingsSoundReceive'] = 'Sonido para mensajes entrantes:'; +$lang['settingsSoundSend'] = 'Sonido para mensajes salientes:'; +$lang['settingsSoundEnter'] = 'Sonido para mensajes de conexión y entradas al canal:'; +$lang['settingsSoundLeave'] = 'Sonido para mensajes de desconexión y salidas del canal:'; +$lang['settingsSoundChatBot'] = 'Sonido para mensajes del Chatbot:'; +$lang['settingsSoundError'] = 'Sonido para mensajes de error:'; +$lang['settingsSoundPrivate'] = 'Sonido para mensajes privados:'; +$lang['settingsBlink'] = 'Parpadeo del título de la ventana con nuevos mensajes:'; +$lang['settingsBlinkInterval'] = 'Intervalo de parpadeo en milisegundos:'; +$lang['settingsBlinkIntervalNumber'] = 'Número de intervalos de parpadeo:'; +$lang['playSelectedSound'] = 'Reproducir sonido seleccionado'; +$lang['requiresJavaScript'] = 'Necesita tener activado el Javascript en su navegador..'; +$lang['errorInvalidUser'] = 'Usuario Invalido.'; +$lang['errorUserInUse'] = 'Este nombre de usuario esta siendo utilizado en este momento.'; +$lang['errorBanned'] = 'El Usuario o la IP esta baneada..'; +$lang['errorMaxUsersLoggedIn'] = 'El Chat ha alcanzado el número máximo de usuarios conectados.'; +$lang['errorChatClosed'] = 'El Chat está cerrado en estos momentos.'; +$lang['logsTitle'] = 'AJAX Chat - Logs'; +$lang['logsDate'] = 'Fecha'; +$lang['logsTime'] = 'Hora'; +$lang['logsSearch'] = 'Buscar'; +$lang['logsPrivateChannels'] = 'Canales Privados'; +$lang['logsPrivateMessages'] = 'Mensajes Privados'; +?> diff --git a/chat/lib/lang/et.php b/chat/lib/lang/et.php index f1169fe..bd438db 100644 --- a/chat/lib/lang/et.php +++ b/chat/lib/lang/et.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Pilt'; $lang['bbCodeLabelColor'] = 'Fondi värv'; +$lang['bbCodeLabelEmoticon'] = 'Emotikonid'; $lang['bbCodeTitleBold'] = 'Rasvases kirjas tekst: [b]tekst[/b]'; $lang['bbCodeTitleItalic'] = 'Kaldkirjas tekst: [i]tekst[/i]'; $lang['bbCodeTitleUnderline'] = 'Underline text: [u]tekst[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Lisa URL: [url]http://näide.org[/url] või [url=http://näide.org]tekst[/url]'; $lang['bbCodeTitleImg'] = 'Lisa pilt: [img]http://näide.org/pilt.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Fondi värv: [color=red]tekst[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emotikonid nimekiri'; $lang['help'] = 'Abi'; $lang['helpItemDescJoin'] = 'Liitu kanaliga:'; $lang['helpItemCodeJoin'] = '/join Kanalinimi'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Heli väljumise ja kanalitest lahkumise sõnumitel:'; $lang['settingsSoundChatBot'] = 'Chatboti sõnumite heli:'; $lang['settingsSoundError'] = 'Veateate heli:'; +$lang['settingsSoundPrivate'] = 'Privaatsõnum sõnumite heli:'; $lang['settingsBlink'] = 'Vilguta akna tiitlit uute sõnumite saabumisel:'; $lang['settingsBlinkInterval'] = 'Vilgutamise intervall millisekundites:'; $lang['settingsBlinkIntervalNumber'] = 'Vilksatuste arv intervallis:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Otsi'; $lang['logsPrivateChannels'] = 'Privaat-kanalid'; $lang['logsPrivateMessages'] = 'Privaat-sõnumid'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/fa.php b/chat/lib/lang/fa.php index 0dc3cb1..0c64586 100644 --- a/chat/lib/lang/fa.php +++ b/chat/lib/lang/fa.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'تصویر'; $lang['bbCodeLabelColor'] = 'رنگ خط'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = 'متن درشت: [b]متن[/b]'; $lang['bbCodeTitleItalic'] = 'متن کج: [i]متن[/i]'; $lang['bbCodeTitleUnderline'] = 'زیر خط دار: [u]متن[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'وارد کردن آدرس: [url]http://example.org[/url] یا [url=http://example.org]متن[/url]'; $lang['bbCodeTitleImg'] = 'وارد کردن تصویر: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'رنگ متن: [color=red]متن[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = 'Ú©Ù…Ú©'; $lang['helpItemDescJoin'] = 'ورود به اطاق:'; $lang['helpItemCodeJoin'] = '/join نام اطاق'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; $lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; $lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'Blink window title on new messages:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; diff --git a/chat/lib/lang/fi.php b/chat/lib/lang/fi.php index 73466b4..e30782b 100644 --- a/chat/lib/lang/fi.php +++ b/chat/lib/lang/fi.php @@ -35,6 +35,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Kuva'; $lang['bbCodeLabelColor'] = 'Fontin väri'; +$lang['bbCodeLabelEmoticon'] = 'Hymiöt'; $lang['bbCodeTitleBold'] = 'Lihavoitu teksti: [b]teksti[/b]'; $lang['bbCodeTitleItalic'] = 'Kursivoitu teksti: [i]teksti[/i]'; $lang['bbCodeTitleUnderline'] = 'Alleviivattu teksti: [u]teksti[/u]'; @@ -43,6 +44,7 @@ $lang['bbCodeTitleURL'] = 'Lisää linkki: [url]http://example.org[/url] tai [url=http://example.org]teksti[/url]'; $lang['bbCodeTitleImg'] = 'Lisää kuva: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Kirjaisimen väri: [color=red]teksti[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Hymiöt lista'; $lang['help'] = 'Ohje'; $lang['helpItemDescJoin'] = 'Liity kanavalle:'; $lang['helpItemCodeJoin'] = '/join KanavanNimi'; @@ -106,6 +108,7 @@ $lang['settingsSoundLeave'] = 'Ääni poistumiseen keskustelusta ja kanavalta:'; $lang['settingsSoundChatBot'] = 'Ääni chatbotin viesteille:'; $lang['settingsSoundError'] = 'Ääni virheilmoituksille:'; +$lang['settingsSoundPrivate'] = 'Ääni varten yksityiset viesteille:'; $lang['settingsBlink'] = 'Vilkuta ikkunan nimeä uusista viesteistä:'; $lang['settingsBlinkInterval'] = 'Vilkuttamisen aika millisekunneissa:'; $lang['settingsBlinkIntervalNumber'] = 'Vilkutuksen viive:'; diff --git a/chat/lib/lang/fr.php b/chat/lib/lang/fr.php index 52ffaf1..ac14e15 100644 --- a/chat/lib/lang/fr.php +++ b/chat/lib/lang/fr.php @@ -1,125 +1,128 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/gl.php b/chat/lib/lang/gl.php index 54b8a8e..7491cb9 100644 --- a/chat/lib/lang/gl.php +++ b/chat/lib/lang/gl.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Imagen'; $lang['bbCodeLabelColor'] = 'Color fonte'; +$lang['bbCodeLabelEmoticon'] = 'Emoticonos'; $lang['bbCodeTitleBold'] = 'Texto negriña: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Texto cursiva: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Texto subraiado: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Insertar URL: [url]http://example.org[/url] or [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Insertar imaxe: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Cor fonte: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticonos lista'; $lang['help'] = 'Axuda'; $lang['helpItemDescJoin'] = 'Entrar na canle:'; $lang['helpItemCodeJoin'] = '/join nome da canle'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Son para logout :'; $lang['settingsSoundChatBot'] = 'Son para mensaxes chat:'; $lang['settingsSoundError'] = 'Son para errores:'; +$lang['settingsSoundPrivate'] = 'Son para mensaxes privadas:'; $lang['settingsBlink'] = 'Parpadeo en ventá con novas mensaxes:'; $lang['settingsBlinkInterval'] = 'Intervalo parpadeos (milisegundos):'; $lang['settingsBlinkIntervalNumber'] = 'Número de parpadeos:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Buscar'; $lang['logsPrivateChannels'] = 'Canles privadas'; $lang['logsPrivateMessages'] = 'mensaxes privadas'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/he.php b/chat/lib/lang/he.php index 39fa799..80f3ba0 100644 --- a/chat/lib/lang/he.php +++ b/chat/lib/lang/he.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'כתובת ×ינטרנט'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'צבע גופן'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'טקסט מודגש: [b]טקסט[/b]'; $lang['bbCodeTitleItalic'] = 'טקסט נטוי: [i]טקסט[/i]'; $lang['bbCodeTitleUnderline'] = 'טקסט מודגש קו: [u]טקסט[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'הכנס כתובת: [url]http://www.example.org[/url] ×ו[url=http://www.example.org]טקסט[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'צבע גופן: [color=צבע]טקסט[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'עזרה'; $lang['helpItemDescJoin'] = 'הצטרף לערוץ:'; $lang['helpItemCodeJoin'] = '/join ×©× ×¢×¨×•×¥'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; $lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; $lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'Blink window title on new messages:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'חיפוש'; $lang['logsPrivateChannels'] = '×¢×¨×•×¦×™× ×¤×¨×˜×™×™×'; $lang['logsPrivateMessages'] = 'הודעות פרטיות'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/hr.php b/chat/lib/lang/hr.php index ed04510..49bb6e8 100644 --- a/chat/lib/lang/hr.php +++ b/chat/lib/lang/hr.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Slika'; $lang['bbCodeLabelColor'] = 'Boja'; +$lang['bbCodeLabelEmoticon'] = 'Emotikone'; $lang['bbCodeTitleBold'] = 'Snažan tekst: [b]tekst[/b]'; $lang['bbCodeTitleItalic'] = 'Kurziv: [i]tekst[/i]'; $lang['bbCodeTitleUnderline'] = 'PodvuÄeni tekst: [u]tekst[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Umetanje URL: [url]http://primjer.org[/url] ili [url=http://primjer.org]tekst[/url]'; $lang['bbCodeTitleImg'] = 'Umetanje slike: [img]http://primjer.org/slika.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Boja fonta: [color=red]tekst[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emotikone popis'; $lang['help'] = 'Pomoć'; $lang['helpItemDescJoin'] = 'Pridruživanje kanalu:'; $lang['helpItemCodeJoin'] = '/join kanal'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Zvuk za odjavljivanje i poruke napuÅ¡tanja kanala:'; $lang['settingsSoundChatBot'] = 'Zvuk za poruke brbljobota:'; $lang['settingsSoundError'] = 'Zvuk za poruke pogreÅ¡ke:'; +$lang['settingsSoundPrivate'] = 'Zvuk za poruke privatni:'; $lang['settingsBlink'] = 'Treptanje naslova prozora kod novih poruka:'; $lang['settingsBlinkInterval'] = 'Trajanje treptanja (u milisekundama):'; $lang['settingsBlinkIntervalNumber'] = 'Broj treptanja:'; diff --git a/chat/lib/lang/hu.php b/chat/lib/lang/hu.php index 5f21741..146b381 100644 --- a/chat/lib/lang/hu.php +++ b/chat/lib/lang/hu.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Kép'; $lang['bbCodeLabelColor'] = 'Szöveg szín'; +$lang['bbCodeLabelEmoticon'] = 'Hangulatjelek'; $lang['bbCodeTitleBold'] = 'Félkövér szöveg: [b]szöveg[/b]'; $lang['bbCodeTitleItalic'] = 'DÅ‘lt szöveg: [i]szöveg[/i]'; $lang['bbCodeTitleUnderline'] = 'Aláhúzott szöveg: [u]szöveg[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'URL beszúrása: [url]http://example.org[/url] vagy [url=http://example.org]szöveg[/url]'; $lang['bbCodeTitleImg'] = 'Kép beszúrása: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Szöveg szín: [color=red]szöveg[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Hangulatjelek lista'; $lang['help'] = 'Segítség'; $lang['helpItemDescJoin'] = 'Belépés a szobába:'; $lang['helpItemCodeJoin'] = '/join Szobanév'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Kilépés szobaüzenetek hangja:'; $lang['settingsSoundChatBot'] = 'ChatBot üzenetek hangja:'; $lang['settingsSoundError'] = 'Hibaüzenetek hangja:'; +$lang['settingsSoundPrivate'] = 'Privát üzenetek hangja:'; $lang['settingsBlink'] = 'Ablak fejléce villogjon új üzenet esetén:'; $lang['settingsBlinkInterval'] = 'A villogás intervallumának hossza századmásodpercekben:'; $lang['settingsBlinkIntervalNumber'] = 'Villogási intervallumok száma:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Keresés'; $lang['logsPrivateChannels'] = 'Privát szobák'; $lang['logsPrivateMessages'] = 'Privát üzenetek'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/in.php b/chat/lib/lang/in.php index 175cc90..8940d1d 100644 --- a/chat/lib/lang/in.php +++ b/chat/lib/lang/in.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Gambar'; $lang['bbCodeLabelColor'] = 'Warna Huruf'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Huruf Tebal: [b]kata[/b]'; $lang['bbCodeTitleItalic'] = 'Huruf Miring: [i]kata[/i]'; $lang['bbCodeTitleUnderline'] = 'Garis Bawah: [u]kata[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'Sisip URL: [url]http://example.org[/url] or [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Sisip gambar: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Warna Huruf: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Help'; $lang['helpItemDescJoin'] = 'Gabung Channel:'; $lang['helpItemCodeJoin'] = '/join NamaChannel'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'Suara pada saat keluar Channel:'; $lang['settingsSoundChatBot'] = 'Suara pada saat ChatBot:'; $lang['settingsSoundError'] = 'Suara pada saat terdapat kesalahan:'; +$lang['settingsSoundPrivate'] = 'Suara pada saat privasi:'; $lang['settingsBlink'] = 'Kedipkan Judul Jendela pada saat ada pesan baru:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Jumlah interval kedipan:'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = 'Cari'; $lang['logsPrivateChannels'] = 'Saluran-saluran privasi'; $lang['logsPrivateMessages'] = 'Pesan Pribadi'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/it.php b/chat/lib/lang/it.php index abcd4f9..6901053 100644 --- a/chat/lib/lang/it.php +++ b/chat/lib/lang/it.php @@ -35,6 +35,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Colore Testo'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Grassetto: [b]testo[/b]'; $lang['bbCodeTitleItalic'] = 'Corsivo: [i]testo[/i]'; $lang['bbCodeTitleUnderline'] = 'Sottolineato: [u]testo[/u]'; @@ -43,6 +44,7 @@ $lang['bbCodeTitleURL'] = 'Inserire URL: [url]http://example.org/[/url] oppure [url=http://example.org/]testo[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Colore Testo: [color=red]testo[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Aiuto'; $lang['helpItemDescJoin'] = 'Entra nel canale:'; $lang['helpItemCodeJoin'] = '/join NomeCanale'; @@ -106,6 +108,7 @@ $lang['settingsSoundLeave'] = 'Suono per uscita:'; $lang['settingsSoundChatBot'] = 'Suono per messaggi robot:'; $lang['settingsSoundError'] = 'Suono per messaggi errore:'; +$lang['settingsSoundPrivate'] = 'Suono per messaggi privati:'; $lang['settingsBlink'] = 'Lampeggio nuovi messaggi:'; $lang['settingsBlinkInterval'] = 'Intervallo lampeggio:'; $lang['settingsBlinkIntervalNumber'] = 'Numero massimo lampeggi:'; @@ -122,4 +125,4 @@ $lang['logsSearch'] = 'Cerca'; $lang['logsPrivateChannels'] = 'Canali Privati'; $lang['logsPrivateMessages'] = 'Messaggi privati'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ja.php b/chat/lib/lang/ja.php index 075fc4f..efe3080 100644 --- a/chat/lib/lang/ja.php +++ b/chat/lib/lang/ja.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'フォントカラー'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = 'ボールド(太字): [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'イタリック(斜体): [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'アンダーライン: [u]text[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'URLリンク: [url]http://example.org[/url] or [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'ç”»åƒ: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'フォントカラー: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = 'ヘルプ'; $lang['helpItemDescJoin'] = 'ãƒãƒ£ãƒ³ãƒãƒ«ã®å¤‰æ›´ :'; $lang['helpItemCodeJoin'] = '/join ãƒãƒ£ãƒ³ãƒãƒ«å'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = 'サウンド - ログアウトã€ãƒãƒ£ãƒ³ãƒãƒ«é€€å®¤ :'; $lang['settingsSoundChatBot'] = 'サウンド - ãƒãƒ£ãƒƒãƒˆãƒœãƒƒãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ :'; $lang['settingsSoundError'] = 'サウンド - エラーメッセージ :'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'æ–°ç€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®åˆ°ç€æ™‚ã«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚¿ã‚¤ãƒˆãƒ«ã‚’点滅ã•ã›ã‚‹ :'; $lang['settingsBlinkInterval'] = '点滅ã®é–“隔(ミリ秒) :'; $lang['settingsBlinkIntervalNumber'] = '点滅ã®å›žæ•° :'; @@ -120,4 +123,4 @@ $lang['logsSearch'] = '検索'; $lang['logsPrivateChannels'] = '二人ãりモード'; $lang['logsPrivateMessages'] = 'プライベートメッセージ'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ka.php b/chat/lib/lang/ka.php index d92d508..96cb954 100644 --- a/chat/lib/lang/ka.php +++ b/chat/lib/lang/ka.php @@ -1,4 +1,4 @@ - \ No newline at end of file +?> diff --git a/chat/lib/lang/kr.php b/chat/lib/lang/kr.php index 687dd6e..1dc4c1e 100644 --- a/chat/lib/lang/kr.php +++ b/chat/lib/lang/kr.php @@ -1,4 +1,4 @@ - \ No newline at end of file +?> diff --git a/chat/lib/lang/mk.php b/chat/lib/lang/mk.php index f43bcfb..d713ad3 100644 --- a/chat/lib/lang/mk.php +++ b/chat/lib/lang/mk.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Боја на фонт'; +$lang['bbCodeLabelEmoticon'] = 'емоции'; $lang['bbCodeTitleBold'] = 'Задебелен текÑÑ‚: [b]текÑÑ‚[/b]'; $lang['bbCodeTitleItalic'] = 'ЗакоÑен текÑÑ‚: [i]текÑÑ‚[/i]'; $lang['bbCodeTitleUnderline'] = 'Подцртан текÑÑ‚: [u]текÑÑ‚[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'URL: [url]http://example.org[/url] или [url=http://example.org]текÑÑ‚[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Боја на заглавие: [color=red]текÑÑ‚[/color]'; +$lang['bbCodeTitleEmoticon'] = 'емоции лиÑта'; $lang['help'] = 'Помош'; $lang['helpItemDescJoin'] = 'ПриÑоединување кон канал:'; $lang['helpItemCodeJoin'] = '/join име_на_канал'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Звук за пораки за излез од четот или од каналот:'; $lang['settingsSoundChatBot'] = 'Звук за пораки на чатботот:'; $lang['settingsSoundError'] = 'Звук за пораки за грешки:'; +$lang['settingsSoundPrivate'] = 'Звук за пораки за приватни:'; $lang['settingsBlink'] = 'Жмигање на заглавието на прозорецот при нови пораки:'; $lang['settingsBlinkInterval'] = 'Интервал на жмигање во милиÑекунди:'; $lang['settingsBlinkIntervalNumber'] = 'Број пати на жмигање:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Пребарување'; $lang['logsPrivateChannels'] = 'Приватни канали'; $lang['logsPrivateMessages'] = 'Приватни пораки'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/nl-be.php b/chat/lib/lang/nl-be.php index db01b98..8449aeb 100644 --- a/chat/lib/lang/nl-be.php +++ b/chat/lib/lang/nl-be.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/nl.php b/chat/lib/lang/nl.php index c7dcc4b..f984db5 100644 --- a/chat/lib/lang/nl.php +++ b/chat/lib/lang/nl.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/no.php b/chat/lib/lang/no.php index 52fe4af..855efd5 100644 --- a/chat/lib/lang/no.php +++ b/chat/lib/lang/no.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/pl.php b/chat/lib/lang/pl.php index 92a1716..dd041f1 100644 --- a/chat/lib/lang/pl.php +++ b/chat/lib/lang/pl.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/pt-br.php b/chat/lib/lang/pt-br.php index 034a5fb..8837a1e 100644 --- a/chat/lib/lang/pt-br.php +++ b/chat/lib/lang/pt-br.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Imagem'; $lang['bbCodeLabelColor'] = 'Cor da fonte'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Texto negrito: [b]texto[/b]'; $lang['bbCodeTitleItalic'] = 'Texto itálico: [i]texto[/i]'; $lang['bbCodeTitleUnderline'] = 'Texto sublinhado: [u]texto[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Inserir URL: [url]http://example.org[/url] or [url=http://example.org]texto[/url]'; $lang['bbCodeTitleImg'] = 'Inserir imagem: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Cor da fonte: [color=red]texto[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Ajuda'; $lang['helpItemDescJoin'] = 'Entrar em um canal:'; $lang['helpItemCodeJoin'] = '/join Nome do Canal'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Som para logout e avisos de saida em canais:'; $lang['settingsSoundChatBot'] = 'Som para mensagens do chatbot:'; $lang['settingsSoundError'] = 'Som para mensagens de erro:'; +$lang['settingsSoundPrivate'] = 'Som para mensagens do privado:'; $lang['settingsBlink'] = 'Título da janela do piscamento em mensagens novas:'; $lang['settingsBlinkInterval'] = 'Intervalo do piscamento nos milissegundos:'; $lang['settingsBlinkIntervalNumber'] = 'Número de intervalos do piscamento:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Pesquisar'; $lang['logsPrivateChannels'] = 'Canais privados'; $lang['logsPrivateMessages'] = 'Mensagens privadas'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/pt-pt.php b/chat/lib/lang/pt-pt.php index e3399eb..0576b30 100644 --- a/chat/lib/lang/pt-pt.php +++ b/chat/lib/lang/pt-pt.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Imagem'; $lang['bbCodeLabelColor'] = 'Cor da fonte'; +$lang['bbCodeLabelEmoticon'] = 'Smileys'; $lang['bbCodeTitleBold'] = 'Texto a negrito: [b]texto[/b]'; $lang['bbCodeTitleItalic'] = 'Texto itálico: [i]texto[/i]'; $lang['bbCodeTitleUnderline'] = 'Texto sublinhado: [u]texto[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Inserir URL: [url]http://example.org[/url] ou [url=http://example.org]texto[/url]'; $lang['bbCodeTitleImg'] = 'Inserir imagem: [img]http://example.org/imagem.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Cor da fonte: [color=red]texto[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smileys list'; $lang['help'] = 'Ajuda'; $lang['helpItemDescJoin'] = 'Entrar numa sala:'; $lang['helpItemCodeJoin'] = '/join [Nome da sala]'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Som de logout:'; $lang['settingsSoundChatBot'] = 'Som para mensagens do chatbot:'; $lang['settingsSoundError'] = 'Som para mensagens de erro:'; +$lang['settingsSoundPrivate'] = 'Som para mensagens de privadas:'; $lang['settingsBlink'] = 'Título da janela do "piscamento" em mensagens novas:'; $lang['settingsBlinkInterval'] = 'Intervalo do "piscamento" em milissegundos:'; $lang['settingsBlinkIntervalNumber'] = 'Número de intervalos do "piscamento":'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Procurar'; $lang['logsPrivateChannels'] = 'Salas privadas'; $lang['logsPrivateMessages'] = 'Mensagens privadas'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ro.php b/chat/lib/lang/ro.php index 8e6d641..db62fb5 100644 --- a/chat/lib/lang/ro.php +++ b/chat/lib/lang/ro.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Culoare fontului'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Text îngroÅŸat: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Text înclinat: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Text subliniat: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Introdu URL: [url]http://example.org[/url] or [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Culoarea fontului: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Ajutor'; $lang['helpItemDescJoin'] = 'Alăturăte canalului:'; $lang['helpItemCodeJoin'] = '/join Channelname'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; $lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; $lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'Blink window title on new messages:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Caută'; $lang['logsPrivateChannels'] = 'Canale private'; $lang['logsPrivateMessages'] = 'Mesaje private'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/ru.php b/chat/lib/lang/ru.php index ac86531..5fb6d91 100644 --- a/chat/lib/lang/ru.php +++ b/chat/lib/lang/ru.php @@ -35,6 +35,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Цвет шрифта'; +$lang['bbCodeLabelEmoticon'] = 'Смайли'; $lang['bbCodeTitleBold'] = 'Жирный текÑÑ‚: [b]текÑÑ‚[/b]'; $lang['bbCodeTitleItalic'] = 'КурÑив: [i]текÑÑ‚[/i]'; $lang['bbCodeTitleUnderline'] = 'Подчеркнутый текÑÑ‚: [u]текÑÑ‚[/u]'; @@ -43,6 +44,7 @@ $lang['bbCodeTitleURL'] = 'Ð’Ñтавить ÑÑылку: [url]http://example.org[/url] или [url=http://example.org]текÑÑ‚[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Цвет шрифта: [color=red]текÑÑ‚[/color]'; +$lang['bbCodeTitleEmoticon'] = 'ÑпиÑок Смайли'; $lang['help'] = 'Помощь'; $lang['helpItemDescJoin'] = 'ПриÑоеденитьÑÑ Ðº каналу:'; $lang['helpItemCodeJoin'] = '/join имÑ_канала'; @@ -106,6 +108,7 @@ $lang['settingsSoundLeave'] = 'Звук Ð´Ð»Ñ Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Ð¾Ð± уходе учаÑтника из чата:'; $lang['settingsSoundChatBot'] = 'Звук Ð´Ð»Ñ Ñообщений бота:'; $lang['settingsSoundError'] = 'Звук Ð´Ð»Ñ Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ð¹ об ошибках:'; +$lang['settingsSoundPrivate'] = 'Звук Ð´Ð»Ñ Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… Ñообщений:'; $lang['settingsBlink'] = '"Моргать" заголовком окна при новом Ñообщении:'; $lang['settingsBlinkInterval'] = 'Интервал "морганиÑ" (в миллиÑекундах):'; $lang['settingsBlinkIntervalNumber'] = 'КоличеÑтво "морганий":'; @@ -122,4 +125,4 @@ $lang['logsSearch'] = 'ПоиÑк'; $lang['logsPrivateChannels'] = 'Приватные каналы'; $lang['logsPrivateMessages'] = 'Приватные ÑообщениÑ'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/sk.php b/chat/lib/lang/sk.php index fae99a7..752190d 100644 --- a/chat/lib/lang/sk.php +++ b/chat/lib/lang/sk.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Farba písma'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'TuÄné: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Kurzívou: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'PodÄiarknuté: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'VložiÅ¥ URL: [url]http://www.example.org/[/url] alebo [url=http://www.example.org/]text[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Farba písma: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Nápoveda'; $lang['helpItemDescJoin'] = 'Prihlásenie do kanálu:'; $lang['helpItemCodeJoin'] = '/join Názov_kanálu'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Sound for logout and channel leave messages:'; $lang['settingsSoundChatBot'] = 'Sound for chatbot messages:'; $lang['settingsSoundError'] = 'Sound for error messages:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'Blink window title on new messages:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Vyhľadávanie'; $lang['logsPrivateChannels'] = 'Súkromný kanál'; $lang['logsPrivateMessages'] = 'Súkromná správa'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/sl.php b/chat/lib/lang/sl.php index 6e49415..4a5a7b6 100644 --- a/chat/lib/lang/sl.php +++ b/chat/lib/lang/sl.php @@ -1,124 +1,127 @@ - \ No newline at end of file + diff --git a/chat/lib/lang/sr.php b/chat/lib/lang/sr.php index a14ba55..1a99a3e 100644 --- a/chat/lib/lang/sr.php +++ b/chat/lib/lang/sr.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Boja fonta'; +$lang['bbCodeLabelEmoticon'] = 'Emocije'; $lang['bbCodeTitleBold'] = 'Podebljan tekst: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Iskrivljen tekst: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'PodvuÄen tekst: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Unesi URL: [url]http://www.example.org/[/url] ili [url=http://www.example.org/]text[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Boja fonta: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emocije list'; $lang['help'] = 'Pomoć'; $lang['helpItemDescJoin'] = 'PrikljuÄi se sobi:'; $lang['helpItemCodeJoin'] = '/join Naziv sobe'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Zvuk za odjavljivanje i izlazak iz sobe:'; $lang['settingsSoundChatBot'] = 'Zvuk za chatbot poruke:'; $lang['settingsSoundError'] = 'Zvuk za poruke o greÅ¡ci:'; +$lang['settingsSoundPrivate'] = 'Zvuk za privatne poruke:'; $lang['settingsBlink'] = 'Treptanje naziva prozora za nove poruke:'; $lang['settingsBlinkInterval'] = 'Interval treptanja u milisekundama:'; $lang['settingsBlinkIntervalNumber'] = 'Broj intervala treptanja:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Pretraga'; $lang['logsPrivateChannels'] = 'Privatne sobe'; $lang['logsPrivateMessages'] = 'Privatne poruke'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/sv.php b/chat/lib/lang/sv.php index 87f03a0..4bf8403 100644 --- a/chat/lib/lang/sv.php +++ b/chat/lib/lang/sv.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Textfärg'; +$lang['bbCodeLabelEmoticon'] = 'Smileys'; $lang['bbCodeTitleBold'] = 'Fet text: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'Kursiv text: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Understruken text: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Lägg till URL: [url]http://www.example.org/[/url] or [url=http://www.example.org/]text[/url]'; $lang['bbCodeTitleImg'] = 'Infoga bild: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Textfärg: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smileys list'; $lang['help'] = 'Hjälp'; $lang['helpItemDescJoin'] = 'Anslut till kanal:'; $lang['helpItemCodeJoin'] = '/join Kanalens namn'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Ljud för Logga ut/lämna Kanal meddelanden:'; $lang['settingsSoundChatBot'] = 'Ljud för Chatbot meddelanden:'; $lang['settingsSoundError'] = 'Ljud för felmeddelanden:'; +$lang['settingsSoundPrivate'] = 'Ljud för privata meddelanden:'; $lang['settingsBlink'] = 'Blinka fönstrets titel vid nya meddelanden:'; $lang['settingsBlinkInterval'] = 'Blinkintervall i millisekunder:'; $lang['settingsBlinkIntervalNumber'] = 'Antal blinkintervaller:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Sök'; $lang['logsPrivateChannels'] = 'Privata Kanaler'; $lang['logsPrivateMessages'] = 'Privata Meddelanden'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/th.php b/chat/lib/lang/th.php index 7ed3b1e..1b0149d 100644 --- a/chat/lib/lang/th.php +++ b/chat/lib/lang/th.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'ลิงค์'; $lang['bbCodeLabelImg'] = 'ภาพ'; $lang['bbCodeLabelColor'] = 'สีอัà¸à¸©à¸£'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = 'อัà¸à¸©à¸£à¸•à¸±à¸§à¸«à¸™à¹‰à¸²: [b]ข้อความ[/b]'; $lang['bbCodeTitleItalic'] = 'อัà¸à¸©à¸£à¸•à¸±à¸§à¹€à¸­à¸µà¸¢à¸‡: [i]ข้อความ[/i]'; $lang['bbCodeTitleUnderline'] = 'อัà¸à¸©à¸£à¸‚ีดเส้นใต้: [u]ข้อความ[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'à¹à¸—รà¸à¸¥à¸´à¸‡à¸„์: [url]http://example.org[/url] or [url=http://example.org]ข้อความ[/url]'; $lang['bbCodeTitleImg'] = 'à¹à¸—รà¸à¸ à¸²à¸ž: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'ตัวอัà¸à¸©à¸£à¸ªà¸µ: [color=red]ข้อความ[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = 'ช่วยเหลือ'; $lang['helpItemDescJoin'] = 'ร่วมห้องà¹à¸Šà¸—:'; $lang['helpItemCodeJoin'] = '/join ชื่อห้องà¹à¸Šà¸—'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'เสียงสำหรับออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸šà¹à¸¥à¸°à¸­à¸­à¸à¸ˆà¸²à¸à¸«à¹‰à¸­à¸‡:'; $lang['settingsSoundChatBot'] = 'เสียงสำหรับข้อความจาำà¸à¸£à¸°à¸šà¸š:'; $lang['settingsSoundError'] = 'เสียงสำหรับข้อความผิดพลาด:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = 'มีสัà¸à¸à¸²à¸“ à¸à¸£à¸°à¸žà¸£à¸´à¸šà¸šà¸™ Title Bar เมื่อมีข้อความใหม่:'; $lang['settingsBlinkInterval'] = 'Blink interval in milliseconds:'; $lang['settingsBlinkIntervalNumber'] = 'Number of blink intervals:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'ค้นหา'; $lang['logsPrivateChannels'] = 'ห้องส่วนตัว'; $lang['logsPrivateMessages'] = 'ข้อความส่วนตัว'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/tr.php b/chat/lib/lang/tr.php index 00f7dfa..07709bb 100644 --- a/chat/lib/lang/tr.php +++ b/chat/lib/lang/tr.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Resim'; $lang['bbCodeLabelColor'] = 'Renkli Yazı'; +$lang['bbCodeLabelEmoticon'] = 'Emoticons'; $lang['bbCodeTitleBold'] = 'Kalın text: [b]text[/b]'; $lang['bbCodeTitleItalic'] = 'EÄŸik text: [i]text[/i]'; $lang['bbCodeTitleUnderline'] = 'Altçizgili text: [u]text[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'URL gir: [url]http://example.org[/url] veya [url=http://example.org]text[/url]'; $lang['bbCodeTitleImg'] = 'Resim gir: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Font Rengi: [color=red]text[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Emoticons list'; $lang['help'] = 'Yardım'; $lang['helpItemDescJoin'] = 'Bir kanala girin:'; $lang['helpItemCodeJoin'] = '/join kanalismi'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Çıkış ve kanaldan çıkış sesi:'; $lang['settingsSoundChatBot'] = 'Chatbot mesajları sesi:'; $lang['settingsSoundError'] = 'Hata mesajları sesi:'; +$lang['settingsSoundPrivate'] = 'Özel mesajlar sesi:'; $lang['settingsBlink'] = 'Yeni mesaj geldiÄŸinde pencere baÅŸlığını kırp:'; $lang['settingsBlinkInterval'] = 'Milisaniye olarak kırpma aralığı:'; $lang['settingsBlinkIntervalNumber'] = 'Kırpma sayısı aralığı:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Ara'; $lang['logsPrivateChannels'] = 'Özel Kanallar'; $lang['logsPrivateMessages'] = 'Özel Mesajlar'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/uk.php b/chat/lib/lang/uk.php index a7d80c1..d8bb72e 100644 --- a/chat/lib/lang/uk.php +++ b/chat/lib/lang/uk.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = 'Колір шрифту'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = 'Жирний текÑÑ‚: [b]текÑÑ‚[/b]'; $lang['bbCodeTitleItalic'] = 'ТекÑÑ‚ курÑивом: [i]текÑÑ‚[/i]'; $lang['bbCodeTitleUnderline'] = 'ПідкреÑлений текÑÑ‚: [u]текÑÑ‚[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'Показати URL: [url]http://example.org[/url] or [url=http://example.org]текÑÑ‚[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = 'Колір шрифту: [color=red]текÑÑ‚[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = 'Допомога'; $lang['helpItemDescJoin'] = 'Зайти в кімнату:'; $lang['helpItemCodeJoin'] = '/join Ðазва_Кімнати'; @@ -105,6 +107,7 @@ $lang['settingsSoundLeave'] = 'Звук Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ–Ñ— виходу з Чату чи кімнати:'; $lang['settingsSoundChatBot'] = 'Звук Ð´Ð»Ñ ÑиÑтемних повідомлень:'; $lang['settingsSoundError'] = 'Звук Ð´Ð»Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº:'; +$lang['settingsSoundPrivate'] = 'Звук Ð´Ð»Ñ Ð¾ÑобиÑтих повідомлень:'; $lang['settingsBlink'] = 'Сигналізувати при поÑві нових повідомлень (Ð±Ð»Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑƒ вікна):'; $lang['settingsBlinkInterval'] = 'ТриваліÑÑ‚ÑŒ Ð±Ð»Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÑƒ вікна:'; $lang['settingsBlinkIntervalNumber'] = 'КількіÑÑ‚ÑŒ блимань:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'Пошук'; $lang['logsPrivateChannels'] = 'Приватні кімнати'; $lang['logsPrivateMessages'] = 'Приватні повідомленнÑ'; -?> \ No newline at end of file +?> diff --git a/chat/lib/lang/zh-tw.php b/chat/lib/lang/zh-tw.php index d39fe6b..1224004 100644 --- a/chat/lib/lang/zh-tw.php +++ b/chat/lib/lang/zh-tw.php @@ -33,6 +33,7 @@ $lang['bbCodeLabelURL'] = '連çµ'; $lang['bbCodeLabelImg'] = '圖片'; $lang['bbCodeLabelColor'] = 'å­—é«”é¡è‰²'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = '粗體字: [b]文字[/b]'; $lang['bbCodeTitleItalic'] = '斜體字: [i]文字[/i]'; $lang['bbCodeTitleUnderline'] = '底線: [u]文字[/u]'; @@ -41,6 +42,7 @@ $lang['bbCodeTitleURL'] = 'æ’å…¥URL: [url]http://example.org[/url] 或 [url=http://example.org]文字[/url]'; $lang['bbCodeTitleImg'] = 'æ’入圖片: [img]http://example.org/image.png[/img]'; $lang['bbCodeTitleColor'] = 'å­—é«”é¡è‰²ï¼š [color=red]文字[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = '使用說明'; $lang['helpItemDescJoin'] = '進入一個房間:'; $lang['helpItemCodeJoin'] = '/join 房間å'; @@ -104,6 +106,7 @@ $lang['settingsSoundLeave'] = '登出和離開房間的音效:'; $lang['settingsSoundChatBot'] = '系統訊æ¯çš„音效:'; $lang['settingsSoundError'] = '錯誤訊æ¯çš„音效:'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsBlink'] = '當有新訊æ¯æ™‚閃動標題:'; $lang['settingsBlinkInterval'] = '閃動的間隔時間(毫秒):'; $lang['settingsBlinkIntervalNumber'] = '閃動次數:'; diff --git a/chat/lib/lang/zh.php b/chat/lib/lang/zh.php index 1d18f0b..18677e6 100644 --- a/chat/lib/lang/zh.php +++ b/chat/lib/lang/zh.php @@ -34,6 +34,7 @@ $lang['bbCodeLabelURL'] = 'URL'; $lang['bbCodeLabelImg'] = 'Image'; $lang['bbCodeLabelColor'] = '文字颜色'; +$lang['bbCodeLabelEmoticon'] = 'Smilies'; $lang['bbCodeTitleBold'] = '粗体:[b]文字[/b]'; $lang['bbCodeTitleItalic'] = '斜体:[i]文字[/i]'; $lang['bbCodeTitleUnderline'] = '下划线:[u]文字[/u]'; @@ -42,6 +43,7 @@ $lang['bbCodeTitleURL'] = 'æ’å…¥ URL:[url]http://example.org[/url] 或者 [url=http://example.org]文字[/url]'; $lang['bbCodeTitleImg'] = 'Insert image: [img]http://example.org/image.jpg[/img]'; $lang['bbCodeTitleColor'] = '文字颜色:[color=red]文字[/color]'; +$lang['bbCodeTitleEmoticon'] = 'Smilies list'; $lang['help'] = '帮助'; $lang['helpItemDescJoin'] = '加入频é“'; $lang['helpItemCodeJoin'] = '/join 频é“å'; @@ -104,6 +106,7 @@ $lang['settingsSoundEnter'] = '声音æ示登录或进入频é“ä¿¡æ¯ï¼š'; $lang['settingsSoundLeave'] = '声音æ示退出或离开频é“ä¿¡æ¯ï¼š'; $lang['settingsSoundChatBot'] = '声音æ示机器人信æ¯ï¼š'; +$lang['settingsSoundPrivate'] = 'Sound for private messages:'; $lang['settingsSoundError'] = '声音æ示错误信æ¯ï¼š'; $lang['settingsBlink'] = '有新消æ¯æ—¶é—ªçƒçª—å£æ ‡é¢˜ï¼š'; $lang['settingsBlinkInterval'] = '空闲间隔毫秒数:'; @@ -121,4 +124,4 @@ $lang['logsSearch'] = 'æœç´¢'; $lang['logsPrivateChannels'] = 'ç§äººé¢‘é“'; $lang['logsPrivateMessages'] = 'ç§äººæ¶ˆæ¯'; -?> \ No newline at end of file +?> diff --git a/chat/lib/template/loggedIn.html b/chat/lib/template/loggedIn.html index 16a75eb..b7118ce 100644 --- a/chat/lib/template/loggedIn.html +++ b/chat/lib/template/loggedIn.html @@ -3,21 +3,11 @@ + [LANG]title[/LANG] - [STYLE_SHEETS/] - + @@ -25,29 +15,126 @@ - +
-
-

[LANG]title[/LANG]

-
+

[LANG]title[/LANG]

- - - - - - - -
-
- -
-
- -
-
- 0/[MESSAGE_TEXT_MAX_LENGTH/] - -
-
-
- - - - - - - - + +
+ + + + + + +
+
- -
- - - - - -
-
-

[LANG]onlineUsers[/LANG]

-
-
- + +
+ +
+
+ 0/[MESSAGE_TEXT_MAX_LENGTH/] + +
+
+
+ + + + + + + + + +
+ +
+ + + + + +
+ @@ -383,5 +455,4 @@

[LANG]settings[/LANG]

- - \ No newline at end of file + diff --git a/chat/lib/template/loggedOut.html b/chat/lib/template/loggedOut.html index 2f7a8ea..2d08193 100644 --- a/chat/lib/template/loggedOut.html +++ b/chat/lib/template/loggedOut.html @@ -3,54 +3,20 @@ + [LANG]title[/LANG] - [STYLE_SHEETS/] - - - +
-
-

[LANG]title[/LANG]

-
-
-
- - - -

-
-

-
-

-
-

-
-
-
* [LANG]registeredUsers[/LANG]
-
-
+

[LANG]title[/LANG]

[ERROR_MESSAGES/]
+
+ + + +

+
+

+
+

+
+

+
+
+
* [LANG]registeredUsers[/LANG]
+
- - \ No newline at end of file + diff --git a/chat/lib/template/logs.html b/chat/lib/template/logs.html index d0b9162..4aa98d0 100644 --- a/chat/lib/template/logs.html +++ b/chat/lib/template/logs.html @@ -5,46 +5,27 @@ [LANG]logsTitle[/LANG] - [STYLE_SHEETS/] - - +
-
-

[LANG]logsTitle[/LANG]

-
+

[LANG]logsTitle[/LANG]

@@ -246,14 +226,22 @@

[LANG]settings[/LANG]

+ + + + + + - + + - + + @@ -272,5 +260,4 @@

[LANG]settings[/LANG]

- \ No newline at end of file diff --git a/chat/readme.html b/chat/readme.html index 8b98602..bf578f4 100644 --- a/chat/readme.html +++ b/chat/readme.html @@ -1,384 +1,416 @@ - - - - - AJAX Chat Readme - - - - - -
- -

AJAX Chat for MyBB - - v 0.8.7 MyBB ( blueimp.net/ajax/ ) - -

- - - -

This is the version of Blueimp's AJAX Chat desinged to be run with MyBB.
-If you want to integrate AJAX Chat with one of the other forums we support, go back and choose the right version.

- -

- AJAX stands for "Asynchronous JavaScript and XML".
- The AJAX Chat client (your browser) uses JavaScript to query the web server for updates.
- Instead of delivering a complete HTML page only updated data is sent in XML format.
- By using JavaScript the chat page can be updated without having to reload the whole page.
- PHP is used to communicate with the database and authenticate users. -

- -

Requirements

-
- - - - - - - - - -
Server-SideClient-Side
- PHP >= 5
- MySQL >= 4
- Ruby >= 1.8 (optional) -
- Enabled JavaScript
- Enabled Cookies
- Flash Plugin >= 9 (optional) -
-
- -

Installation

-
-

Download your preferred version of AJAX Chat and unzip the file on your computer.

-

Before You Begin

-
-

- In order to edit PHP files you will need a good text editor. You should not use Windows notepad, wordpad, or Microsoft Word to edit PHP files. These programs will add something called a byte-order-mark (BOM) to the files and this may prevent chat from functioning properly. - We recommend using Notepad ++ ( http://notepad-plus-plus.org ) for editing all files. It also has the benefit of color-coding your files so you can edit them more easily.
- If you get an error message like "Cannot modify header information - headers already sent" it is likely because you have used one of the above programs to edit files. -

-
- -

Upload to Server

-
-

- Upload the chat folder to your server into your mybb forum directory:
- e.g. http://example.org/mybb/chat/

-
- -

Create the Database Tables

-
-

There are two options available to you to create the database. The first, and usually the easiest option, is to run the installation script included with AJAX Chat. Alternatively, you may use a database tool like PHPMyAdmin to manually create the tables.

-
    -
  1. To use the installation script, visit the following URL in your browser:
    - http://example.org/mybb/chat/install.php
    - Where - "http://example.org/mybb/chat/" is the real URL to your chat directory.
  2. -
  3. To install it manually using PHPMyAdmin or a similar tool, copy the contents of the chat.sql file and run it as a query.
  4. -
-

Either of these methods will create the tables your database needs to store chat messages and other information.

-
- -

Delete the Installation Script

-
-

Delete the file install.php from the chat directory on your server. You may also delete the file chat.sql.

-
- -

Congradulation! You Are Winner!

-
-

Yay! You're done! To test your chat, navigate to your chat URL in a browser: http://example.org/path/to/chat/index.php
-
You are now free to customize chat to further suit your needs.

-
-
- -

Configuring and Customizing

-
-

Configuration Files

-
-

AJAX Chat is fully customizable and contains two configuration files:

-
    -
  1. lib/config.php: This file contains the core configuration options for chat. Essential options for configuring the database, security, available languages, etc, are found here.
  2. -
  3. js/config.js: This file contains client side settings that change your users' default options in chat. Many of these settings can be changed by users in their options but some (like the refresh rate) cannot.
  4. -
-

Both of these files are well commented with information on what the settings mean.

-
- -

Customizing the Layout

-
-

The layout of AJAX Chat is fully customizable by using CSS (Cascaded Style Sheets).
- AJAX Chat comes with a predefined set of styles. To add your own style, do the following:

-
    -
  1. Add a new CSS file (e.g. mystyle.css) by copying one of the existing styles from the CSS directory.
  2. -
  3. Edit your file (css/mystyle.css) and adjust the CSS settings to your liking.
  4. -
  5. Add the name of your style without file extension to the available styles in lib/config.php:
    - // Available styles:
    - $config['styleAvailable'] = array('mystyle','beige','black','grey');
    - // Default style:
    - $config['styleDefault'] = 'mystyle';
  6. -
-

To further customize the layout you can adjust the template files in lib/template/.

-

Make sure you are creating valid XHTML, else you will produce errors in modern browsers.
- This is due to the page content-type served as "application/xhtml+xml".
- Using this content-type improves performance when manipulating the Document Object Model (DOM).

-

If for some reason you cannot create valid XHTML you can force a HTML content-type.
- Just edit lib/config.php and set the following option:

-

$config['contentType'] = 'text/html';

-
- -

Adjusting the Language Settings

-
-

AJAX Chat comes with two language file directories:

-
    -
  1. js/lang/: This directory contains the language files used for the chat messages localization. These are JavaScript files with the extension ".js".
  2. -
  3. lib/lang/: This directory contains the language files used for the template output. These are PHP files with the extension ".php".
  4. -
-

Many languages are already included with the download and you can customize them by editing these files.
- For each language, you need a file in both of these directories, with the language code as file name (such as en.js and en.php)..
- The language code is used following the ISO 639 standards.

-

The files for the english (language code "en") localization are js/lang/en.js and lib/lang/en.php.

-

If you create your own localization, you must put the files in the correct folders and then make two changes to config.php:

-
    -
  1. Add the language code (this must match the filename you chose for the language. Remember to use commas correctly to separate multiple language codes):
    - $config['langAvailable'] = array('en');
  2. -
  3. Add the language name (this is what users see in the dropdown menu to choose the language):
    - $config['langNames'] = array('en'=>'English');
  4. -
-

To avoid errors, you should follow these rules:

-
    -
  1. Make sure you encode your localization files in UTF-8 (without Byte-order mark).
  2. -
  3. Don't use HTML entities in your localization files.
  4. -
  5. Don't remove any "%s" inside the JavaScript language files - these are filled with dynamic data.
  6. -
-
- -

Adding Features

-
-

AJAX Chat is designed with numerous hooks and overrides available to improve core functionality without requiring you to edit the core files. - With an intermediate understading of PHP and javascript you can modify your chat to suit your needs.

-

Have a look through a few examples available on the wiki: - https://github.com/Frug/AJAX-Chat/wiki/General-modifications -

-
- -
- -

Logs

-
-

Accessing the Logs

-
-

By default, AJAX Chat stores all chat messages in the database.
- To access the logs you have to add the GET parameter view=logs to your chat url (add ?view=logs to the end of the url):

-

e.g. http://example.org/path/to/chat/?view=logs

-

If you are not already logged in, you have to login as administrator to access the logs.

-

The log view enables you to monitor the latest chat messages on all channels.
- It is also possible to view the logs of private rooms and private messages.
- You have the option to filter the logs by date, time and search strings.

-

The search filter accepts MySQL style regular expressions as described here: http://dev.mysql.com/doc/refman/5.1/en/regexp.html
- You can search for IPs, using the following syntax: ip=127.0.0.1

-
-
- -

Shoutbox

-
-

AJAX Chat is also usable as shoutbox - this is a short guide on how to set it up:

- -

Shoutbox Stylesheet

-
-

Add the following line to the stylesheet (CSS) of all pages displaying the shoutbox:

-

@import url("http://example.org/path/to/chat/css/shoutbox.css");

-

Replace http://example.org/path/to/chat/ with the URL to the chat.
- Modify css/shoutbox.css to your liking.

-
- -

Shoutbox Function

-
-

Add the following function to your PHP code:

- -
-<?php
-function getShoutBoxContent() {
-// URL to the chat directory:
-if(!defined('AJAX_CHAT_URL')) {
-	define('AJAX_CHAT_URL', './chat/');
-}
-
-// Path to the chat directory:
-if(!defined('AJAX_CHAT_PATH')) {
-	define('AJAX_CHAT_PATH', realpath(dirname($_SERVER['SCRIPT_FILENAME']).'/chat').'/');
-}
-
-// Validate the path to the chat:
-if(@is_file(AJAX_CHAT_PATH.'lib/classes.php')) {
-	
-	// Include Class libraries:
-	require_once(AJAX_CHAT_PATH.'lib/classes.php');
-	
-	// Initialize the shoutbox:
-	$ajaxChat = new CustomAJAXChatShoutBox();
-	
-	// Parse and return the shoutbox template content:
-	return $ajaxChat->getShoutBoxContent();
-}
-
-return null;
-}
-?>
-
- -

Make sure AJAX_CHAT_URL and AJAX_CHAT_PATH point to the chat directory.

-
- -

Shoutbox Output

-
-

Display the shoutbox content using the shoutbox function:

-

<div style="width:200px;"><?php echo getShoutBoxContent(); ?></div>

-
-
- -

Socket Server

-
-

Using the AJAX technology alone the chat clients have to permanently pull updates from the server.
- This is due to AJAX being a web technology and HTTP being a stateless protocol.
- Events pushed from server-side need a permanent or long-lasting socket connection between clients and server.
- This requires either a custom HTTP server (called "comet") or another custom socket server.

-

AJAX Chat uses a JavaScript-to-Flash bridge to establish a permanent socket connection from client side.
- The JavaScript-to-Flash bridge requires a Flash plugin >= 9 installed on the user browser.
- Clients without this requirement will fall back to pull the server for updates.

-

This part of the setup is OPTIONAL and meant for experienced users only.

-

Installation

-
-

The socket server coming with AJAX Chat is implemented in Ruby.
- You need to be able to run a Ruby script as a service to run the socket server.
- To be able to start the service, the script files in the socket/ directory have to be executable:

-

$ chmod +x server
- $ chmod +x server.rb

-

"server" is a simple bash script to start and stop a service.
- "server.rb" is the ruby socket server script.
- "server.conf" is a configuration file - each setting is explained with a comment.

-

To start the service, execute the "server" script with the parameter "start":

-

$ ./server start

-

This will create two additional files:

-

"server.pid" contains the process id of the service.
- "server.log" is filled with the socket server log.

-

To monitor the socket server logs, you can use the "tail" command included in most GNU/Linux distributions:

-

$ tail -f server.log

-

By default only errors and start/stop of the server are logged.
- To get more detailed logs configure the log level by editing the configuration file.

-

To stop the service, execute the "server" script with the parameter "stop":

-

$ ./server stop

-

If the socket server is running, you have to enable the following option in lib/config.php:

-

$config['socketServerEnabled'] = true;
-
- This tells the server-side chat script to broadcast chat messages via the socket server.
- Chat clients will establish a permanent connection to the socket server to listen for chat messages.

-

By default only local clients (127.0.0.1,::1) may broadcast messages.
- Clients allowed to broadcast messages may also handle the channel authentication.
- If your socket server is running on another host you should set the broadcast_clients option to the chat server IP.

-

Using the socket server increases response time while improving server performance at the same time.

-
- -

Flash Permissions

-
-

- Since Flash 9.0.115.0 and all Flash 10 versions, permissions for creating sockets using Flash have changed.
- Now an explicit permission (using xml-syntax) is required for creating socket connections.
- In the current state, socket server won't work with the newest Flash versions.
- You will get a "Flash security error" in the browser. -

-

- A solution is to use a policy-files server which will listen to connections in port 843 in the server.
- Each time a client tries to connect to the chat, the Flash client will request the policy authorization to the server.
- The policy-files server is downloadable from http://ammonlauritzen.com/FlashPolicyService-09b.zip
- It works with FF3 and IE7 (not yet tested in other browsers). -

-

A more detailed explanation can be found here:

-

* http://ammonlauritzen.com/blog/2007/12/13/new-flash-security-policies/
- * http://ammonlauritzen.com/blog/2008/04/22/flash-policy-service-daemon/
-

-

Official Adobe documentation:

-

* http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html
- * http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security_04.html

-
-

 

-
- -

Support

-
-

- Please do not email the devs with support questions.
- For further documentation and some examples, check out our github wiki.
- For general support questions use our google group.
- For specific bug reports and a list of pending issues view our github project.
-

-
- - -
-

- Your donations contribute to the growth and development of this project and are always appreciated.
-

- - - - -
- I'm on gittip at https://www.gittip.com/Frug -

-
- -

License

-
-

Bluimp's AJAX Chat is released under a Modified MIT License.

-

You should also find this license included with your download of this project.

-
- -

back to top

- -
- - + + + + + AJAX Chat Readme + + + + + +
+
+

+ AJAX Chat for MyBB + + v 0.8.8 mybb ( blueimp.net/ajax/ ) + +

+
+
+ +
+ + + +
+

Version Information

+
+ This is the version of Blueimp's AJAX Chat desinged to be run with MyBB.
+ If you want to integrate AJAX Chat with one of the other forums we support, go back and choose the right version. + +

+ AJAX stands for "Asynchronous JavaScript and XML".
+ The AJAX Chat client (your browser) uses JavaScript to query the web server for updates.
+ Instead of delivering a complete HTML page only updated data is sent in XML format.
+ By using JavaScript the chat page can be updated without having to reload the whole page.
+ PHP is used to communicate with the database and authenticate users. +

+
+
+ +

1. Requirements

+
+ + + + + + + + + +
Server-SideClient-Side
+ PHP >= 5
+ MySQL >= 4
+ Ruby >= 1.8 (optional) +
+ Enabled JavaScript
+ Enabled Cookies
+ Flash Plugin >= 9 (optional) +
+
+ +

2. Installation

+
+

Download your preferred version of AJAX Chat and unzip the file on your computer.

+ +
+

Use a Proper Text Editor!

+ In order to edit PHP files you will need a good text editor. You should not use Windows notepad, wordpad, or Microsoft Word to edit PHP files. These programs will add something called a byte-order-mark (BOM) to the files and this may prevent chat from functioning properly. + We recommend using Notepad ++ ( http://notepad-plus-plus.org ) for editing all files. It also has the benefit of color-coding your files so you can edit them more easily.
+ If you get an error message like "Cannot modify header information - headers already sent" it is likely because you have used one of the above programs to edit files. +
+ +

Upload to Server

+
+

+ Upload the chat folder to your server into your mybb forum directory:
+ e.g. http://example.org/mybb/chat/

+

+ $config['dbConnection']['host'] = 'your_database_hostname';
+ + In most cases, chat will function with only these fields filled out and you can proceed to the next step.
+ If your host does not use mysqli you will need to change the connection type field:
+

+ The Standalone version of chat uses a php file to store users and rooms while the database is used for chat messages, invites and bans.
+ The integration versions typically make use of a database for users and rooms. If you desire a way to manage users without having to edit a php file, consider using an integration version. +

+

+ Edit users in lib/data/users.php.
+

+
+ +

Create the Database Tables

+
+

There are two options available to you to create the database. The first, and usually the easiest option, is to run the installation script included with AJAX Chat. Alternatively, you may use a database tool like PHPMyAdmin to manually create the tables.

+
    +
  1. + http://example.org/mybb/chat/install.php
    + Where + "http://example.org/mybb/chat/" is the real URL to your chat directory.
  2. + Be sure to delete the install.php file after you have completed this step! + +
  3. To install it manually using PHPMyAdmin or a similar tool, copy the contents of the chat.sql file and run it as a query.
  4. +
+

Either of these methods will create the tables your database needs to store chat messages and other information.

+
+ +

Delete the Installation Script

+
+

Delete the file install.php from the chat directory on your server. You may also delete the file chat.sql.

+
+ +

Congradulation! You Are Winner!

+
+

Yay! You're done! To test your chat, navigate to your chat URL in a browser: http://example.org/path/to/chat/index.php
+
You are now free to customize chat to further suit your needs.

+
+
+ +

3. Configuring and Customizing

+
+

Configuration Files

+
+

AJAX Chat is fully customizable and contains two configuration files:

+
    +
  1. lib/config.php: This file contains the core configuration options for chat. Essential options for configuring the database, security, available languages, etc, are found here.
  2. +
  3. js/config.js: This file contains client side settings that change your users' default options in chat. Many of these settings can be changed by users in their options but some (like the refresh rate) cannot.
  4. +
+

Both of these files are well commented with information on what the settings mean.

+
+ +

Customizing the Layout

+
+

The layout of AJAX Chat is fully customizable by using CSS (Cascaded Style Sheets).
+ AJAX Chat comes with a predefined set of styles. To add your own style, do the following:

+
    +
  1. Add a new CSS file (e.g. mystyle.css) by copying one of the existing styles from the CSS directory.
  2. +
  3. Edit your file (css/mystyle.css) and adjust the CSS settings to your liking.
  4. +
  5. Add the name of your style without file extension to the available styles in lib/config.php:
    + // Available styles:
    + $config['styleAvailable'] = array('mystyle','beige','black','grey');
    + // Default style:
    + $config['styleDefault'] = 'mystyle';
  6. +
+

To further customize the layout you can adjust the template files in lib/template/.

+

Make sure you are creating valid XHTML, else you will produce errors in modern browsers.
+ This is due to the page content-type served as "application/xhtml+xml".
+ Using this content-type improves performance when manipulating the Document Object Model (DOM).

+

If for some reason you cannot create valid XHTML you can force a HTML content-type.
+ Just edit lib/config.php and set the following option:

+

$config['contentType'] = 'text/html';

+
+ +

Adjusting the Language Settings

+
+

AJAX Chat comes with two language file directories:

+
    +
  1. js/lang/: This directory contains the language files used for the chat messages localization. These are JavaScript files with the extension ".js".
  2. +
  3. lib/lang/: This directory contains the language files used for the template output. These are PHP files with the extension ".php".
  4. +
+

Many languages are already included with the download and you can customize them by editing these files.
+ For each language, you need a file in both of these directories, with the language code as file name (such as en.js and en.php)..
+ The language code is used following the ISO 639 standards.

+

The files for the english (language code "en") localization are js/lang/en.js and lib/lang/en.php.

+

If you create your own localization, you must put the files in the correct folders and then make two changes to config.php:

+
    +
  1. Add the language code (this must match the filename you chose for the language. Remember to use commas correctly to separate multiple language codes):
    + $config['langAvailable'] = array('en');
  2. +
  3. Add the language name (this is what users see in the dropdown menu to choose the language):
    + $config['langNames'] = array('en'=>'English');
  4. +
+

To avoid errors, you should follow these rules:

+
    +
  1. Make sure you encode your localization files in UTF-8 (without Byte-order mark).
  2. +
  3. Don't use HTML entities in your localization files.
  4. +
  5. Don't remove any "%s" inside the JavaScript language files - these are filled with dynamic data.
  6. +
+
+ +

Adding Features

+
+

AJAX Chat is designed with numerous hooks and overrides available to improve core functionality without requiring you to edit the core files. + With an intermediate understading of PHP and javascript you can modify your chat to suit your needs.

+

Have a look through a few examples available on the wiki: + https://github.com/Frug/AJAX-Chat/wiki/General-modifications +

+
+ +
+ +

4. Logs

+
+

Accessing the Logs

+
+

By default, AJAX Chat stores all chat messages in the database.
+ To access the logs you have to add the GET parameter view=logs to your chat url (add ?view=logs to the end of the url):

+

e.g. http://example.org/path/to/chat/?view=logs

+

If you are not already logged in, you have to login as administrator to access the logs.

+

The log view enables you to monitor the latest chat messages on all channels.
+ It is also possible to view the logs of private rooms and private messages.
+ You have the option to filter the logs by date, time and search strings.

+

The search filter accepts MySQL style regular expressions as described here: http://dev.mysql.com/doc/refman/5.1/en/regexp.html
+ You can search for IPs, using the following syntax: ip=127.0.0.1

+
+
+ +

5. Shoutbox

+
+

AJAX Chat is also usable as shoutbox - this is a short guide on how to set it up:

+ +

Shoutbox Stylesheet

+
+

Add the following line to the stylesheet (CSS) of all pages displaying the shoutbox:

+

@import url("http://example.org/path/to/chat/css/shoutbox.css");

+

Replace http://example.org/path/to/chat/ with the URL to the chat.
+ Modify css/shoutbox.css to your liking.

+
+ +

Shoutbox Function

+
+

Add the following function to your PHP code:

+ +
+<?php
+function getShoutBoxContent() {
+// URL to the chat directory:
+if(!defined('AJAX_CHAT_URL')) {
+	define('AJAX_CHAT_URL', './chat/');
+}
+
+// Path to the chat directory:
+if(!defined('AJAX_CHAT_PATH')) {
+	define('AJAX_CHAT_PATH', realpath(dirname($_SERVER['SCRIPT_FILENAME']).'/chat').'/');
+}
+
+// Validate the path to the chat:
+if(@is_file(AJAX_CHAT_PATH.'lib/classes.php')) {
+	
+	// Include Class libraries:
+	require_once(AJAX_CHAT_PATH.'lib/classes.php');
+	
+	// Initialize the shoutbox:
+	$ajaxChat = new CustomAJAXChatShoutBox();
+	
+	// Parse and return the shoutbox template content:
+	return $ajaxChat->getShoutBoxContent();
+}
+
+return null;
+}
+?>
+
+ +

Make sure AJAX_CHAT_URL and AJAX_CHAT_PATH point to the chat directory.

+
+ +

Shoutbox Output

+
+

Display the shoutbox content using the shoutbox function:

+

<div style="width:200px;"><?php echo getShoutBoxContent(); ?></div>

+
+
+ +

6. Socket Server

+
+

+ This part of the setup is OPTIONAL and meant for experienced users only.
+ The Socket Server is no longer actively supported and may not function correctly out of the box. + Later versions of AJAX Chat may have this socket server implementation replaced with something else.
+ Please do not report bugs regarding the socket server - you're on your own with this one! +

+ +

Using the AJAX technology alone the chat clients have to permanently pull updates from the server.
+ This is due to AJAX being a web technology and HTTP being a stateless protocol.
+ Events pushed from server-side need a permanent or long-lasting socket connection between clients and server.
+ This requires either a custom HTTP server (called "comet") or another custom socket server.

+

AJAX Chat uses a JavaScript-to-Flash bridge to establish a permanent socket connection from client side.
+ The JavaScript-to-Flash bridge requires a Flash plugin >= 9 installed on the user browser.
+ Clients without this requirement will fall back to pull the server for updates.

+

Installation

+
+

The socket server coming with AJAX Chat is implemented in Ruby.
+ You need to be able to run a Ruby script as a service to run the socket server.
+ To be able to start the service, the script files in the socket/ directory have to be executable:

+

$ chmod +x server
+ $ chmod +x server.rb

+

"server" is a simple bash script to start and stop a service.
+ "server.rb" is the ruby socket server script.
+ "server.conf" is a configuration file - each setting is explained with a comment.

+

To start the service, execute the "server" script with the parameter "start":

+

$ ./server start

+

This will create two additional files:

+

"server.pid" contains the process id of the service.
+ "server.log" is filled with the socket server log.

+

To monitor the socket server logs, you can use the "tail" command included in most GNU/Linux distributions:

+

$ tail -f server.log

+

By default only errors and start/stop of the server are logged.
+ To get more detailed logs configure the log level by editing the configuration file.

+

To stop the service, execute the "server" script with the parameter "stop":

+

$ ./server stop

+

If the socket server is running, you have to enable the following option in lib/config.php:

+

$config['socketServerEnabled'] = true;
+
+ This tells the server-side chat script to broadcast chat messages via the socket server.
+ Chat clients will establish a permanent connection to the socket server to listen for chat messages.

+

By default only local clients (127.0.0.1,::1) may broadcast messages.
+ Clients allowed to broadcast messages may also handle the channel authentication.
+ If your socket server is running on another host you should set the broadcast_clients option to the chat server IP.

+

Using the socket server increases response time while improving server performance at the same time.

+
+ +

Flash Permissions

+
+

+ Since Flash 9.0.115.0 and all Flash 10 versions, permissions for creating sockets using Flash have changed.
+ Now an explicit permission (using xml-syntax) is required for creating socket connections.
+ In the current state, socket server won't work with the newest Flash versions.
+ You will get a "Flash security error" in the browser. +

+

+ A solution is to use a policy-files server which will listen to connections in port 843 in the server.
+ Each time a client tries to connect to the chat, the Flash client will request the policy authorization to the server.
+ The policy-files server is downloadable from http://ammonlauritzen.com/FlashPolicyService-09b.zip
+ It works with FF3 and IE7 (not yet tested in other browsers). +

+

A more detailed explanation can be found here:

+

* http://ammonlauritzen.com/blog/2007/12/13/new-flash-security-policies/
+ * http://ammonlauritzen.com/blog/2008/04/22/flash-policy-service-daemon/
+

+

Official Adobe documentation:

+

* http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html
+ * http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security_04.html

+
+

 

+
+ +

7. Support

+
+

+ Please do not email the devs with support questions.
+ For further documentation and some examples, check out our github wiki.
+ For general support questions use our google group.
+ For specific bug reports and a list of pending issues view our github project.
+

+
+ + +
+

+ Your donations contribute to the growth and development of this project and are always appreciated.
+

+ + + + +
+ I'm on gittip at https://www.gittip.com/Frug +

+
+ +

9. License

+
+

Bluimp's AJAX Chat is released under a Modified MIT License.

+

You should also find this license included with your download of this project.

+
+ +

back to top

+ +
+ + \ No newline at end of file diff --git a/chat/sounds/sound_7.mp3 b/chat/sounds/sound_7.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..7ee9273e4001c30e5af30c687a6b7d97fa29e299 GIT binary patch literal 24241 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
- \ No newline at end of file + From 8a25a073bb8b4bc6aaee92870c51de17a556a6b9 Mon Sep 17 00:00:00 2001 From: Philip Nicolcev Date: Sun, 22 Feb 2015 14:17:25 -0500 Subject: [PATCH 5/5] changelog update --- chat/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/chat/changelog.txt b/chat/changelog.txt index 6d86137..fe3b028 100644 --- a/chat/changelog.txt +++ b/chat/changelog.txt @@ -866,6 +866,7 @@ Bugfixes: - Nesting an [IMG] inside a [URL] tag will now only open the URL instead of also opening the image - thanks to James Almer. - Users can now be kicked for 0 minutes, which is effectively a kick and not a ban - thanks to micheal-swiggs. - User list sorting is now case insensitive (lists should be properly alphabetical) - thanks to marquisite. +- MyBB forums were not showing up correctly in the room list. Misc: - Removed unneeded call to mt_srand() - thanks to Joshua Embrey.