');
+ return 'pw_reset';
+ } else {
+ return 'no_email_on_record';
+ }
+ }
+
+ /**
+ * Changes the user's password.
+ *
+ * @return String 'changed' if successful, error string otherwise
+ * @author Joshua Gross
+ **/
+ function passwordChange($password, $new_password) {
+ if(!$this->checkInfo($this->username, $password)) return 'invalid_pw';
+
+ if(strlen($new_password) >= 6 && strlen($new_password) <= 20) {
+ $query = mysql_query('UPDATE ' . SQL_PREFIX . 'users SET password=\'' . md5($new_password) . '\' WHERE username=\'' . mysql_real_escape_string($this->username) . '\'');
+ return 'pw_changed';
+ } else {
+ return 'password_bad_length';
+ }
+ }
+
+ /**
+ * Adds a user to a chatroom.
+ *
+ * @return String 'joined' if successful, error string otherwise
+ * @author Joshua Gross
+ **/
+ function joinRoom($room) {
+ $room = mysql_real_escape_string(strtolower($room));
+
+ $query = mysql_query('SELECT id FROM ' . SQL_PREFIX . 'chats WHERE user=\'' . mysql_real_escape_string($this->username) . '\' AND room=\'' . $room . '\'');
+
+ if(mysql_num_rows($query) > 0) {
+ return 'already_joined';
+ } else {
+ if(preg_match('/^[^a-z0-9_\d]+$/', $room) == false) {
+ $query = mysql_query('INSERT INTO ' . SQL_PREFIX . 'chats (room, user) VALUES (\'' . $room . '\', \'' . mysql_real_escape_string($this->username) . '\')');
+
+ $output['users'] = $this->getChatlist($room);
+ $notify_buddies = $this->userEvent($this->username, $output, 'chat', array('action'=>'join', 'room'=>$room));
+
+ return $this->json->encode($output);
+ } else {
+ return 'invalid_chars';
+ }
+ }
+ }
+
+ /**
+ * Removes a user from a chatroom.
+ *
+ * @return String 'left' if successful, 'not_left' otherwise
+ * @author Joshua Gross
+ **/
+ function leaveRoom($room) {
+ $room = mysql_real_escape_string(strtolower($room));
+
+ $query = mysql_query('SELECT id FROM ' . SQL_PREFIX . 'chats WHERE user=\'' . mysql_real_escape_string($this->username) . '\' AND room=\'' . $room . '\'') ;
+
+ if(mysql_num_rows($query) > 0) {
+ $row = mysql_fetch_assoc($query);
+ $query = mysql_query('DELETE FROM ' . SQL_PREFIX . 'chats WHERE id=\'' . $row['id'] . '\'');
+
+ $output['users'] = $this->getChatlist($room);
+ $notify_buddies = $this->userEvent($this->username, $output, 'chat', array('action'=>'left', 'room'=>$room));
+
+ return 'left';
+ } else {
+ return 'not_left';
+ }
+ }
+
+ /**
+ * Retrieves a list of room names and returns them to the user as a JSON object.
+ *
+ * @return JSON object
+ * @author Joshua Gross
+ **/
+ function roomList() {
+ $rooms_query = mysql_query('SELECT room FROM ' . SQL_PREFIX . 'chats GROUP BY room ORDER BY room ASC');
+
+ $rooms = array();
+ while($row = mysql_fetch_assoc($rooms_query))
+ $rooms[] = $row['room'];
+
+ return $this->json->encode($rooms);
+ }
+
+ /**
+ * Proccesses the upload of the new Buddy Icon for the user.
+ *
+ * @return JSON object
+ * @author Benjamin Hutchins
+ **/
+ function changeIcon() {
+ global $maxBuddyIconSize;
+
+ if (!isset($maxBuddyIconSize) || $maxBuddyIconSize == 0) {
+ return "unkown";
+ }
+
+ /*
+ @ini_set('file_uploads', 'On');
+ @ini_set('upload_max_filesize', $maxBuddyIconSize.'M');
+ @ini_set('post_max_size', $maxBuddyIconSize.'M');
+ */
+
+ $allowed_types = array("image/x-ms-bmp", "image/x-icon", "image/jpeg", "image/x-png", "image/gif", "image/png", "image/tiff");
+ $allowed_files = array('jpeg', 'jpg', 'jpe', 'bmp', 'png', 'gif', 'ico', "tif", "tiff");
+
+ if (empty($_FILES['icon']['tmp_name'])) {
+ return "nofile";
+ }
+ if ($_FILES['icon']['size'] > $maxBuddyIconSize*1024) {
+ return "size";
+ }
+ if (!in_array($_FILES['icon']['type'], $allowed_types)) {
+ return "bad_type";
+ }
+ $filename = $_FILES['icon']['name'];
+ $extension = strtolower(end(explode(".", $filename)));
+ if (!in_array($extension, $allowed_files)) {
+ return "bad_extension";
+ }
+ if (move_uploaded_file($_FILES['icon']['tmp_name'], "./buddyicons/".$this->username.".".$extension)) {
+ if (mysql_query('UPDATE ' . SQL_PREFIX . 'users SET buddyicon=\'' . mysql_real_escape_string($extension) . '\' WHERE username=\'' . mysql_real_escape_string($this->username) . '\'')) {
+ return "success";
+ } else {
+ return "unkown";
+ }
+ } else {
+ return "unkown";
+ }
+ }
+
+ /**
+ * Updates a user's profile.
+ *
+ * @return success value
+ * @author Benjamin Hutchins
+ **/
+ function changeProfile($profile) {
+ if (mysql_query('UPDATE ' . SQL_PREFIX . 'users SET profile=\'' . mysql_real_escape_string(strip_tags($profile)) . '\' WHERE username=\'' . mysql_real_escape_string($this->username) . '\'')) {
+ return 'success';
+ } else {
+ return 'failed';
+ }
+ }
+
+ /**
+ * Returns a user's profile.
+ *
+ * @return HTML content
+ * @author Benjamin Hutchins
+ **/
+ function getProfile($username) {
+ $query = mysql_query('SELECT profile FROM ' . SQL_PREFIX . 'users WHERE username=\'' . mysql_real_escape_string($username) . '\'');
+
+ $result = mysql_fetch_assoc($query);
+ return $result['profile'];
+ }
+
+ /* Begin private functions */
+
+ /**
+ * Return a user's status.
+ *
+ * @return Integer representing user's status
+ * @author Joshua Gross
+ **/
+ function isOnline($username) {
+ $query = mysql_query('SELECT is_online FROM ' . SQL_PREFIX . 'users WHERE username=\'' . mysql_real_escape_string($username) . '\'');
+
+ $result = mysql_fetch_assoc($query);
+ return $result['is_online'];
+ }
+
+ /**
+ * Check to see if the supplied user information is valid, and if so return specific information.
+ *
+ * @return false if information is invalid, array of data otherwise
+ * @author Joshua Gross
+ **/
+ function checkInfo($username, $password, $return=array()) {
+ if(count($return) > 0)
+ $columns = implode(',', $return);
+ else
+ $columns = 'id';
+
+ $username = mysql_real_escape_string($username);
+ $password = mysql_real_escape_string($password);
+
+ $query = mysql_query('SELECT ' . $columns . ' FROM ' . SQL_PREFIX . 'users WHERE username=\'' . $username . '\' AND password=\'' . $password . '\' LIMIT 1');
+
+ if(mysql_num_rows($query) > 0)
+ return mysql_fetch_assoc($query);
+ else
+ return false;
+ }
+
+ /**
+ * Retrieves a list of users in a specific chatroom.
+ *
+ * @return Array of users
+ * @author Joshua Gross
+ **/
+ function getChatlist($room) {
+ $query = mysql_query('SELECT DISTINCT user FROM ' . SQL_PREFIX . 'chats WHERE room=\'' . mysql_real_escape_string(strtolower($room)) . '\'');
+
+ while ($row = mysql_fetch_assoc($query))
+ $userlist[]=$row['user'];
+ return $userlist;
+ }
+
+ /**
+ * Retrieves a list of all of the user's buddies.
+ *
+ * @return Array of buddies by group
+ * @author Joshua Gross
+ * @update Benjamin Hutchins - returns none-blocked buddies if $inc_blocked = false
+ **/
+ function getBuddylist($username, $inc_blocked=true) {
+ $username = mysql_real_escape_string($username);
+
+ $query = mysql_query('SELECT ' . SQL_PREFIX . 'buddylists.buddy AS buddy, `group` FROM ' . SQL_PREFIX . 'buddylists WHERE user=\'' . $username . '\' AND ' . SQL_PREFIX . 'buddylists.buddy NOT IN(SELECT user FROM ' . SQL_PREFIX . 'blocklists WHERE buddy=\'' . $username . '\')' . ($inc_blocked ? "" : ' AND ' . SQL_PREFIX . 'buddylists.buddy NOT IN(SELECT buddy FROM ' . SQL_PREFIX . 'blocklists WHERE user=\'' . $username . '\')'));
+
+ $buddylist = array();
+ while($row = mysql_fetch_assoc($query))
+ $buddylist[$row['group']][] = $row['buddy'];
+
+ return $buddylist;
+ }
+
+ /**
+ * Retrieves a list of the user's buddies that are online (with any status).
+ *
+ * @return Array of buddies by group with status information
+ * @author Joshua Gross
+ * @update Benjamin Hutchins - only returns buddies that did not block user.
+ **/
+ function getBuddylistOnline($username) {
+ $username = mysql_real_escape_string($username);
+
+ //$query = mysql_query('SELECT ' . SQL_PREFIX . 'buddylists.buddy, `group`, buddyicon, is_online FROM ' . SQL_PREFIX . 'buddylists LEFT JOIN ' . SQL_PREFIX . 'users ON ' . SQL_PREFIX . 'buddylists.buddy = ' . SQL_PREFIX . 'users.username WHERE ' . SQL_PREFIX . 'buddylists.user=\'' . $username . '\' AND ' . SQL_PREFIX . 'buddylists.buddy NOT IN(SELECT user FROM ' . SQL_PREFIX . 'blocklists WHERE buddy=\'' . $username . '\')');
+ $query = mysql_query('SELECT ' . SQL_PREFIX . 'buddylists.buddy, `group`, buddyicon, is_online, ' . SQL_PREFIX . 'buddylists.buddy IN(SELECT user FROM ' . SQL_PREFIX . 'blocklists WHERE buddy=\'' . $username . '\') AS blocked FROM ' . SQL_PREFIX . 'buddylists LEFT JOIN ' . SQL_PREFIX . 'users ON ' . SQL_PREFIX . 'buddylists.buddy = ' . SQL_PREFIX . 'users.username WHERE ' . SQL_PREFIX . 'buddylists.user=\'' . $username . '\'');
+
+ $buddylist = array();
+ while($row = mysql_fetch_assoc($query)) {
+ $buddylist[$row['group']][] = array('username'=>$row['buddy'], 'icon'=>$row['buddyicon'], 'is_online'=>($row['blocked'] ? 0 : $row['is_online']));
+ }
+ return $buddylist;
+ }
+
+ /**
+ * Retrieves the list of blocked buddies from the database.
+ *
+ * @return Array of buddies
+ * @author Joshua Gross
+ **/
+ function getBlocklist($username) {
+ $username = mysql_real_escape_string($username);
+
+ $query = mysql_query('SELECT buddy FROM ' . SQL_PREFIX . 'blocklists WHERE user=\'' . $username . '\'');
+
+ $blocklist = array();
+ while($row = mysql_fetch_assoc($query))
+ $blocklist[] = $row['buddy'];
+
+ return $blocklist;
+ }
+
+ /**
+ * Event handler for status or chat status updates.
+ *
+ * @return void
+ * @author Joshua Gross
+ **/
+ function userEvent($username, $buddylist, $event, $args) {
+ $username = mysql_real_escape_string($username);
+
+ switch($event) {
+ case 'chat':
+ $users = $buddylist['users'];
+ $users_str = @implode("','", $users);
+
+ $query = mysql_query('SELECT username, is_online FROM ' . SQL_PREFIX . 'users WHERE username IN(\'' . $users_str . '\') AND is_online > 0 ORDER BY username ASC');
+
+ while ($row = mysql_fetch_assoc($query))
+ if(strlen($to_insert[$row['username']]) == 0) $to_insert[$row['username']] = mysql_real_escape_string($event . ',' . $args['action'] . ',' . $args['room']);
+ break;
+
+ case 'status':
+ if($args['status'] == 100) {
+ $args['status'] = 0; // we're going to do this backwards
+ // instead of broadcasting a positive message to our buddies
+ // we will send a negative (offline) message to all our non-buddies
+ // who have us on their buddylist
+ $query_string = 'username IN(SELECT user FROM ' . SQL_PREFIX . 'buddylists WHERE buddy=\'' . $username . '\') AND ' .
+ 'username NOT IN(\'';
+ } else {
+ $query_string = '(username IN(SELECT user FROM ' . SQL_PREFIX . 'buddylists WHERE buddy=\'' . $username . '\') AND username NOT IN(SELECT buddy FROM ' . SQL_PREFIX . 'blocklists WHERE user=\'' . $username . '\')) OR ' .
+ 'username IN(\'';
+ }
+
+ if(count($buddylist) == 0) $buddylist[''] = array('');
+
+ foreach($buddylist as $group => $users) {
+ $users_str = implode("','", $users);
+
+ $query = mysql_query('SELECT username, is_online FROM ' . SQL_PREFIX . 'users WHERE (' . $query_string . $users_str . '\')) GROUP BY username');
+
+ while($row = mysql_fetch_assoc($query)) {
+ if(in_array($row['username'], $users) !== false) {
+ if($row['is_online'] == 100) {
+ $friend_query = mysql_query('SELECT id FROM ' . SQL_PREFIX . 'buddylists WHERE user=\'' . $row['username'] . '\' AND buddy=\'' . $username . '\' LIMIT 1');
+ if(mysql_num_rows($friend_query) == 0) $row['is_online'] = 0;
+ }
+ }
+
+ if($row['is_online'] != 0 && strlen($to_insert[$row['username']]) == 0) $to_insert[$row['username']] = mysql_real_escape_string($event . ',' . $args['status']);
+ }
+ }
+ break;
+ }
+
+ if(count($to_insert) > 0) {
+ $time_cur = time();
+ foreach($to_insert as $user => $evt)
+ $insert_str .= "('" . $evt . "', 'event', '" . $username . "', '" . mysql_real_escape_string($user) . "', " . $time_cur . "),";
+
+ $insert_str = substr($insert_str, 0, strlen($insert_str) - 1);
+ $query = @mysql_query('INSERT INTO ' . SQL_PREFIX . 'messages (message, type, sender, recipient, stamp) VALUES ' . $insert_str);
+ }
+ }
+
+ /**
+ * Generates a random string of the specified length (default = 10).
+ *
+ * @return String
+ * @author Joshua Gross
+ **/
+ function generatePassword($length=10) {
+ $randstr='';
+ srand((double)microtime()*1000000);
+
+ $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ while(strlen($randstr)<$length) {
+ $randstr.=substr($chars,(rand()%(strlen($chars))),1);
+ }
+ return $randstr;
+ }
+
+ /**
+ * Garbage collector. Resets users who have been inactive for more than 5 minutes.
+ *
+ * @return void
+ * @author Joshua Gross
+ **/
+ function gc() {
+ // cleanup logged-in users in database? [30% chance]
+ if(rand(1, 100) <= 30) {
+ // yes, cleanup! //
+ $expire_time = time() - 30; // idle for more than 30 seconds?
+
+ $cleanup_event = mysql_query('SELECT username FROM ' . SQL_PREFIX . 'users WHERE last_ping < ' . $expire_time . ' AND is_online > 0');
+ if(mysql_num_rows($cleanup_event) > 0) {
+ while($row = mysql_fetch_assoc($cleanup_event))
+ $notify_buddies = $this->userEvent($row['username'], $this->getBuddylist($row['username']), 'status', array('status'=>0));
+ }
+
+ $cleanup_event2 = mysql_query('SELECT user, room FROM ' . SQL_PREFIX . 'chats WHERE user IN(SELECT username FROM ' . SQL_PREFIX . 'users WHERE last_ping < ' . $expire_time . ' AND is_online > 0)');
+ if(mysql_num_rows($cleanup_event2) > 0) {
+ while($row = mysql_fetch_assoc($cleanup_event2)) {
+ $room = mysql_query('SELECT user FROM ' . SQL_PREFIX . 'chats WHERE room=\'' . $row['room'] . '\'');
+
+ if(mysql_num_rows($room) > 0) {
+ while($row2 = mysql_fetch_assoc($room))
+ $chatusers['users'][] = $row2['user'];
+ }
+
+ $notify_chatusers = $this->userEvent($row['user'], $chatusers, 'chat', array('action'=>'left', 'room'=>$row['room']));
+ }
+ }
+
+ $cleanup_chats = mysql_query('DELETE FROM ' . SQL_PREFIX . 'chats WHERE user IN(SELECT username FROM ' . SQL_PREFIX . 'users WHERE last_ping < ' . $expire_time . ' AND is_online > 0)');
+ $cleanup_msgs = mysql_query('DELETE FROM ' . SQL_PREFIX . 'messages WHERE stamp < ' . (time() - 300));
+ $cleanup = mysql_query('UPDATE ' . SQL_PREFIX . 'users SET is_online=0 WHERE last_ping < ' . $expire_time . ' AND is_online > 0');
+ }
+ }
+}
+
+$ajax_im = new Ajax_IM($_POST['call']);
+
+mysql_close();
+?>
diff --git a/config-sample.php b/config-sample.php
new file mode 100644
index 0000000..309fd9b
--- /dev/null
+++ b/config-sample.php
@@ -0,0 +1,21 @@
+
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+// MySQL Database Configuration
+$sql_user = 'root';
+$sql_pass = '';
+$sql_host = 'localhost';
+$sql_db = 'ajaxim';
+
+// This is the prefix for the ajax im MySQL tables -- this can usually be left alone.
+// (If upgrading from a version < 3.1, set the prefix to '')
+define('SQL_PREFIX', 'ajaxim_');
+
+$maxBuddyIconSize = 100; // in KBs, set to 0 to disable uploads
+?>
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..220e506
--- /dev/null
+++ b/index.html
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
:
+
+
:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
:
+
+
:
+
+
:
+
+
:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/install.php b/install.php
new file mode 100644
index 0000000..ea74343
--- /dev/null
+++ b/install.php
@@ -0,0 +1,237 @@
+
+
+
+
+
+ ajax im - installation
+
+
+
+
+ ajax im
+
+
+
before you begin...
+ Did you remember to:
+
+ setup a database for ajax im?
+ edit config.php to match your MySQL configuration?
+ 0 && trim(substr(sprintf('%o', fileperms('./buddyicons/')), -4)) != 777) { echo 'CHMOD buddyicons/ to 0777, it is at: '. substr(sprintf('%o', fileperms('./buddyicons/')), -4) .'? '; } ?>
+
+
+
+
+
+
+
installing...
+ \n";
+ $problem = true;
+ } else {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ $error = true;
+ }
+ } else {
+ mysql_query('ALTER TABLE `'.SQL_PREFIX.'messages` CHANGE `message` `message` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL');
+ print "Table '".SQL_PREFIX."messages' added successfully! \n";
+ }
+
+ $table_users = 'CREATE TABLE `'.SQL_PREFIX.'users` ( `username` varchar(32), `password` varchar(32), `email` text, `is_online` int(11) default \'0\', `last_ping` text, `last_ip` varchar(15), `banned` tinyint(1) default \'0\', `admin` tinyint(1) default \'0\', `buddyicon` varchar(4) NOT NULL default \'none\', `profile` text, `id` bigint(20) unsigned NOT NULL auto_increment, UNIQUE KEY `id` (`id`), UNIQUE `username` (`username`) ) ;';
+ if(!mysql_query($table_users)) {
+ if(mysql_errno() == 1050) {
+ print "Table '".SQL_PREFIX."users' already exists! If you had a version of ajax im less than 3.2 installed on this database, please delete the table and then run this script again, otherwise ignore this error. \n";
+ } else {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ $error = true;
+ }
+ } else {
+ print "Table '".SQL_PREFIX."users' added successfully! \n";
+ }
+
+ $table_chats = 'CREATE TABLE `'.SQL_PREFIX.'chats` ( `room` text, `user` text, `id` bigint(20) unsigned NOT NULL auto_increment, UNIQUE KEY `id` (`id`) ) ;';
+ if(!mysql_query($table_chats)) {
+ if(mysql_errno() == 1050) {
+ print "Table '".SQL_PREFIX."chats' already exists! If you had a version of ajax im less than 3.0 installed on this database, please delete the table and then run this script again, otherwise ignore this error. \n";
+ $problem = true;
+ } else {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ $error = true;
+ }
+ } else {
+ mysql_query('ALTER TABLE `'.SQL_PREFIX.'chats` CHANGE `room` `room` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL');
+ print "Table '".SQL_PREFIX."chats' added successfully! \n";
+ }
+
+ $table_buddylists = 'CREATE TABLE `'.SQL_PREFIX.'buddylists` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `user` VARCHAR( 100 ) NOT NULL, `buddy` VARCHAR( 100 ) NOT NULL, `group` VARCHAR( 100 ) NOT NULL, INDEX ( `user` , `group` )) ENGINE = MYISAM ;';
+ if(!mysql_query($table_buddylists)) {
+ if(mysql_errno() == 1050) {
+ print "Table '".SQL_PREFIX."buddylists' already exists! If you had a version of ajax im less than 3.2 installed on this database, please delete the table and then run this script again, otherwise ignore this error. \n";
+ $problem = true;
+ } else {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ $error = true;
+ }
+ } else {
+ print "Table '".SQL_PREFIX."buddylists' added successfully! \n";
+ }
+
+ $table_blocklists = 'CREATE TABLE `'.SQL_PREFIX.'blocklists` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `user` VARCHAR( 100 ) NOT NULL, `buddy` VARCHAR( 100 ) NOT NULL, INDEX ( `user` , `buddy` )) ENGINE = MYISAM ;';
+ if(!mysql_query($table_blocklists)) {
+ if(mysql_errno() == 1050) {
+ print "Table '".SQL_PREFIX."blocklists' already exists! If you had a version of ajax im less than 3.2 installed on this database, please delete the table and then run this script again, otherwise ignore this error. \n";
+ $problem = true;
+ } else {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ $error = true;
+ }
+ } else {
+ print "Table '".SQL_PREFIX."blocklists' added successfully! \n";
+ }
+
+ $add_user = 'INSERT INTO `'.SQL_PREFIX.'users` (username, password, email, admin) VALUES (\'' . mysql_real_escape_string($_POST['username']) . '\', \'' . mysql_real_escape_string(md5($_POST['password'])) . '\', \'' . mysql_real_escape_string($_POST['email']) . '\', 1)';
+ if(!mysql_query($add_user)) {
+ print("A MySQL error occured: (" . mysql_errno() . ") " . mysql_error() . " \n");
+ print "Unable to add the first user! This likely means there was some other issue during installation. \n";
+ $error = true;
+ } else {
+ print "First/admin user registered! \n";
+ }
+
+ if ($maxBuddyIconSize > 0) {
+ if (trim(substr(sprintf('%o', fileperms('./buddyicons/')), -4)) != 777) {
+ $error = true;
+ print "File permissions: : CHMOD buddyicons/ to 0777 ";
+ } else {
+ print "You have change permissions of buddyicons/ ";
+ }
+ }
+
+ mysql_close();
+ ?>
+
+
+
+
status
+ here. Please be sure to delete install.php and update.php!';
+ ?>
+
+
+
+
diff --git a/is_online/README b/is_online/README
new file mode 100644
index 0000000..4e4b6dd
--- /dev/null
+++ b/is_online/README
@@ -0,0 +1,16 @@
+///////////////////////////////////
+// ajax im 3.4 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+The is_online.php script allows you to display a users status as an image. It is very simple to use.
+
+To use:
+1. Upload the is_online.php script and accompanying images folder to your server.
+2. To display a user's status, insert this line anywhere:
+
+
+ Replace [pathtoscript] with the path to the script and [username] with the username you want to display the status of.
diff --git a/is_online/images/away.gif b/is_online/images/away.gif
new file mode 100644
index 0000000..746e738
Binary files /dev/null and b/is_online/images/away.gif differ
diff --git a/is_online/images/offline.gif b/is_online/images/offline.gif
new file mode 100644
index 0000000..93f22cb
Binary files /dev/null and b/is_online/images/offline.gif differ
diff --git a/is_online/images/online.gif b/is_online/images/online.gif
new file mode 100644
index 0000000..9218efb
Binary files /dev/null and b/is_online/images/online.gif differ
diff --git a/is_online/is_online.php b/is_online/is_online.php
new file mode 100644
index 0000000..84e9dd4
--- /dev/null
+++ b/is_online/is_online.php
@@ -0,0 +1,41 @@
+
diff --git a/js/admin.js b/js/admin.js
new file mode 100644
index 0000000..7ffb669
--- /dev/null
+++ b/js/admin.js
@@ -0,0 +1,457 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+/**
+ * Object to hold all Admin Windows as variables
+ *
+ * @author Joshua Gross
+ **/
+var AdminWindows = {
+ /**
+ * Display window to allow admin to search for users
+ *
+ * @author Joshua Gross
+ **/
+ userSearch: function() {
+ var userSearchWin;
+ if($('admin-userSearch')) {
+ Windows.getWindow('admin-userSearch').toFront();
+ return;
+ }
+
+ userSearchWin = new Window({id: 'admin-userSearch', className: "dialog", width: 250, height: 110, resizable: true,
+ title: Languages.get('admin-admin') + ' - ' + Languages.get('admin-userSearch'), draggable: true, closable: true, maximizable: false, minimizable: true, detachable: false,
+ minWidth: 250, minHeight: 110, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ userSearchWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ userSearchWin.getContent().innerHTML = '' + Languages.get('admin-chooseByAndSearch') + '
\
+ \
+
' + Languages.get('admin-searchType') + ':
\
+
\
+ ' + Languages.get('username') + ' \
+ ' + Languages.get('email') + ' \
+ \
+
' + Languages.get('search') + ':
\
+
\
+
' +
+ ButtonCtl.create(Languages.get('search'), 'Admin.findUser($(\'admin-searchType\').value, $(\'admin-search\').value);') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'admin-userSearch\');') +
+ '
';
+
+ $('admin-searchButtons').setStyle({position: 'absolute',
+ top: '105px',
+ left: '32px'});
+
+ userSearchWin.setDestroyOnClose();
+ userSearchWin.showCenter();
+ },
+
+ /**
+ * On admin window resize, fix elements within window
+ *
+ * @arguments
+ * win - window to be resized
+ *
+ * @author Joshua Gross
+ **/
+ handleResize: function(win) {
+ switch(win.getId().replace(/admin-/, '')) {
+ case 'userSearch':
+ if($('admin-userSearchResults')) {
+ $('admin-userSearchResults').setStyle({'width': win.getSize()['width'] + 'px'});
+ $('admin-userSearchResults').parentNode.setStyle({'width': win.getSize()['width'] + 'px'});
+ $('admin-userExecFunctions').setStyle({'left': ((win.getSize()['width'] - $('admin-userExecFunctions').getWidth()) / 2) + 'px'});
+ }
+
+ $('admin-searchButtons').setStyle({'left': ((win.getSize()['width'] - $('admin-searchButtons').getWidth()) / 2) + 'px'});
+ break;
+ }
+ }
+}
+
+
+/**
+ * Handle all Admin requests
+ *
+ * @author Joshua Gross
+ **/
+var Admin = {
+ // current selected user from the user-search-results list
+ selectedUser: null,
+
+ /**
+ * Finds and displays users searched for by the admin
+ *
+ * @author Joshua Gross
+ * @update Benjamin Hutchins
+ * - User's email be displayed.
+ **/
+ findUser: function(searchType, search) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(adminPingTo, "POST", "call=search&by="+searchType+"&for="+search, function(xh) {
+ if(xh.responseText == 'access_denied') return Admin.noAccess();
+
+ if($('admin-userSearchResults'))
+ $('admin-userSearchResults').parentNode.parentNode.removeChild($('admin-userSearchResults').parentNode);
+
+ var results = xh.responseText.parseJSON();
+ var resultsTable = '
';
+ resultsTable += '' + Languages.get('username') + ' ' + Languages.get('email') + ' ' + Languages.get('admin-lastKnownIP') + ' ' + Languages.get('admin-lastActive') + ' ' + Languages.get('admin-status') + ' ' + Languages.get('admin-banned') + ' ' + Languages.get('admin-admin') + ' ';
+
+ for(var i=0; i' +
+ '' + results[i].username + ' ' + results[i].email + ' ' + results[i].lastKnownIP + ' ' +
+ '' + lastActive + ' ' + '' + results[i].currentStatus + ' ' + results[i].banned + ' ' +
+ '' + results[i].admin + ' ';
+ }
+ resultsTable += '
';
+
+ var userSearch = Windows.getWindow('admin-userSearch')
+ userSearch.setSize(500, 232);
+ userSearch.options.minWidth = 500;
+ userSearch.options.minHeight = 232;
+ userSearch.showCenter(false);
+ userSearch.getContent().innerHTML += resultsTable;
+
+ if(!$('admin-userExecFunctions')) {
+ userSearch.getContent().innerHTML += '
' +
+ ButtonCtl.create(Languages.get('admin-kick'), 'Admin.kickUser(Admin.selectedUser.getElementsByTagName(\'td\')[0].innerHTML);') +
+ ButtonCtl.create(Languages.get('admin-ban'), 'Admin.banUser(Admin.selectedUser.getElementsByTagName(\'td\')[0].innerHTML);', 'admin-banButton') +
+ ButtonCtl.create(Languages.get('admin-makeAdmin'), 'Admin.toggleAdmin(Admin.selectedUser.getElementsByTagName(\'td\')[0].innerHTML);', 'admin-makeAdminButton') +
+ '
';
+
+ $('admin-userExecFunctions').setStyle({position: 'absolute',
+ top: '195px',
+ left: '83px'});
+ }
+
+ $('admin-searchButtons').innerHTML = ButtonCtl.create(Languages.get('searchAgain'), 'Admin.findUser($(\'admin-searchType\').value, $(\'admin-search\').value);') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'admin-userSearch\');');
+
+
+ $('admin-searchButtons').setStyle({position: 'absolute',
+ top: '225px',
+ left: '130px'});
+
+ var t = new ScrollableTable($('admin-userSearchResults'), 100, 500);
+ t = new SortableTable($('admin-userSearchResults'));
+
+ $('admin-searchType').value = searchType;
+ $('admin-search').value = search;
+ });
+ },
+
+ /**
+ * Sends request to server to ban user
+ *
+ * @arguments
+ * user - user to be banned
+ *
+ * @author Joshua Gross
+ **/
+ banUser: function(user) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(adminPingTo, "POST", "call=ban&user="+user, function(xh) {
+ if(xh.responseText == 'access_denied') return Admin.noAccess();
+
+ Admin.selectedUser.getElementsByTagName('td')[4].innerHTML = xh.responseText;
+ $('admin-banButton').innerHTML = (xh.responseText=='true'?Languages.get('admin-unban'):Languages.get('admin-ban'));
+ });
+ },
+
+ /**
+ * Sends request to server to kick a user offline
+ *
+ * @arguments
+ * user - user to be kicked
+ *
+ * @author Joshua Gross
+ **/
+ kickUser: function(user) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(adminPingTo, "POST", "call=kick&user="+user, function(xh) {
+ if(xh.responseText == 'access_denied') return Admin.noAccess();
+
+ Admin.selectedUser.getElementsByTagName('td')[3].innerHTML = '0';
+ });
+ },
+
+ /**
+ * Toggles a user's admin rights
+ *
+ * @arguments
+ * user - user to be toggled
+ *
+ * @author Joshua Gross
+ **/
+ toggleAdmin: function(user) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(adminPingTo, "POST", "call=admin&user="+user, function(xh) {
+ if(xh.responseText == 'access_denied') return Admin.noAccess();
+
+ Admin.selectedUser.getElementsByTagName('td')[5].innerHTML = xh.responseText;
+ $('admin-makeAdminButton').innerHTML = (xh.responseText=='true'?Languages.get('admin-removeAdmin'):Languages.get('admin-makeAdmin'));
+ });
+ },
+
+ /**
+ * Add hover effect to an element
+ *
+ * @arguments
+ * el - element to have effect added
+ *
+ * @author Joshua Gross
+ **/
+ findUserListHover: function(el) {
+ Element.addClassName(el, 'listHover').removeClassName('listSelected').removeClassName('listNotSelected');
+ },
+
+ /**
+ * Remove hover effect added by Admin.findUserListHover
+ *
+ * @arguments
+ * el - element to have effect removed
+ *
+ * @author Joshua Gross
+ **/
+ findUserListDefault: function(el) {
+ if(el != Admin.selectedUser) Element.addClassName(el, 'listNotSelected').removeClassName('listSelected').removeClassName('listHover');
+ else Element.addClassName(el, 'listSelected').removeClassName('listNotSelected').removeClassName('listHover');
+ },
+
+ /**
+ * Change Admin.selectedUser to the user clicked by the admin
+ *
+ * @arguments
+ * el - list element to turn into selected
+ *
+ * @author Joshua Gross
+ **/
+ findUserListSelect: function(el) {
+ if(Admin.selectedUser) Element.addClassName(Admin.selectedUser, 'listNotSelected').removeClassName('listSelected').removeClassName('listHover');
+ Element.addClassName(el, 'listSelected').removeClassName('listNotSelected').removeClassName('listHover');
+ Admin.selectedUser = el;
+
+ if(el.getElementsByTagName('td')[4].innerHTML == 'true')
+ $('admin-banButton').innerHTML = Languages.get('admin-unban');
+ else
+ $('admin-banButton').innerHTML = Languages.get('admin-ban');
+
+ if(el.getElementsByTagName('td')[5].innerHTML == 'true')
+ $('admin-makeAdminButton').innerHTML = Languages.get('admin-removeAdmin');
+ else
+ $('admin-makeAdminButton').innerHTML = Languages.get('admin-makeAdmin');
+ }
+};
+
+/**
+*
+* Scrollable HTML table
+* http://www.webtoolkit.info/
+*
+**/
+function ScrollableTable (tableEl, tableHeight, tableWidth) {
+
+ this.initIEengine = function () {
+
+ this.containerEl.style.overflowY = 'auto';
+ if (this.tableEl.parentElement.clientHeight - this.tableEl.offsetHeight < 0) {
+ this.tableEl.style.width = this.newWidth - this.scrollWidth +'px';
+ } else {
+ this.containerEl.style.overflowY = 'hidden';
+ this.tableEl.style.width = this.newWidth +'px';
+ }
+
+ if (this.thead) {
+ var trs = this.thead.getElementsByTagName('tr');
+ for (x=0; x
= (this.newHeight - (headHeight + footHeight))) {
+ this.tbody.style.overflow = '-moz-scrollbars-vertical';
+ for (x=0; x]+>/g,'');
+ }
+
+ this.getParent = function (el, pTagName) {
+ if (el == null) return null;
+ else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
+ return el;
+ else
+ return this.getParent(el.parentNode, pTagName);
+ }
+
+ this.sort = function (cell) {
+
+ var column = cell.cellIndex;
+ var itm = this.getInnerText(this.tbody[0].rows[1].cells[column]);
+ var sortfn = this.sortCaseInsensitive;
+
+ if (itm.match(/\d\d[-]+\d\d[-]+\d\d\d\d/)) sortfn = this.sortDate; // date format mm-dd-yyyy
+ if (itm.replace(/^\s+|\s+$/g,"").match(/^[\d\.]+$/)) sortfn = this.sortNumeric;
+
+ this.sortColumnIndex = column;
+
+ var newRows = new Array();
+ for (j = 0; j < this.tbody[0].rows.length; j++) {
+ newRows[j] = this.tbody[0].rows[j];
+ }
+
+ newRows.sort(sortfn);
+
+ if (cell.getAttribute("sortdir") == 'down') {
+ newRows.reverse();
+ cell.setAttribute('sortdir','up');
+ } else {
+ cell.setAttribute('sortdir','down');
+ }
+
+ for (i=0;i 0)) return;
+
+ if (sortSection && sortSection[0].rows && sortSection[0].rows.length > 0) {
+ var sortRow = sortSection[0].rows[0];
+ } else {
+ return;
+ }
+
+ for (var i=0; i0?siteName:document.title);
+var blinkerTimer;
+var pingTimer;
+var newWin, newWinRcvd;
+var windowButtons;
+var smilies = [];
+var soundManager;
+
+
+/**
+ * Before the window is 'unloaded', confirm the user wants to leave
+ *
+ * @author Joshua Gross
+ **/
+window.onbeforeunload = function(event) {
+ event = event || window.event;
+ if(event && loggedIn) {
+ var text = Languages.get('onunload');
+ event.returnValue = text;
+ window.onbeforeunload = function() { };
+ return text;
+ }
+}
+
+
+/**
+ * After all content and images for the web page is loaded,
+ * run some functions
+ *
+ * @author Joshua Gross
+ **/
+window.onload = function() {
+ Windows.addObserver({ onResize: IM.handleResize });
+ Windows.addObserver({ onClose: IM.handleClose });
+ Windows.addObserver({ onMaximize: IM.handleResize });
+ Windows.addObserver({ onMinimize: IM.handleMinimize });
+
+ // initialize the sound manager
+ soundManager = new SoundManager();
+ soundManager.onload = function() {
+ soundManager.createSound({id: 'msg_in', url: './sounds/msg_in.mp3', autoLoad: true});
+ soundManager.createSound({id: 'msg_out', url: './sounds/msg_out.mp3', autoLoad: true});
+ soundManager.play('msg_out');
+ };
+ soundManager.beginDelayedInit();
+
+ // attach event
+ // before window is unloaded, remove sound manager
+ Element.observe(window, 'beforeunload', soundManager.destruct);
+
+ // center modal
+ setTimeout(function() { recenterModal(null); }, 1000);
+
+ // on window resize, recenter modal
+ Event.observe(window, 'resize', recenterModal);
+
+ // on window unload, logout the user
+ Event.observe(window, 'unload', function() { if(loggedIn) System.logout(); });
+
+ // clear all inputs
+ clearInputs();
+
+ // replace status images with theme-based images
+ $('statusList').getElementsBySelector('img').each(function(el) {
+ el.src = el.src.replace(/images/g, 'themes/' + theme);
+ });
+
+ // initialize Context Menus
+ Context.loaded();
+
+ // hook mousedown for status list
+ var dOMD = (document.onmousedown ? document.onmousedown : new Function());
+ document.onmousedown = window.onmousedown = function(e) {
+ showHide(e);
+ dOMD(e);
+ }
+
+ // if the user wants to disable register, hide the button
+ if (!allowNewUsers) {
+ $$('.registerObject').each(function(el) {
+ el.remove();
+ });
+ // then fix the buttons for login
+ $('login_dialog_links').setStyle({width:'190px'});
+ }
+
+ // show login
+ Dialogs.login();
+};
+
+
+/**
+ * After all content for the web page is loaded,
+ * load some more stuff.
+ *
+ * @author Joshua Gross
+ **/
+Event.onReady(function() {
+ var getEmoteHTML = new XHConn();
+ getEmoteHTML.connect('themes/' + theme +'/emoticons/emoticons.html', 'GET', '', function(xh) {
+ document.body.innerHTML += xh.responseText;
+
+ var getEmoteJS = new XHConn();
+ getEmoteJS.connect('themes/' + theme +'/emoticons/emoticons.js', 'GET', '', function(xh) {
+ window.smilies = xh.responseText.parseJSON();
+ });
+ });
+
+ // load language file
+ var s = document.createElement('script');
+ s.src = 'languages/' + languageOptions[0][0] + '/lang.js?' + (new Date()).getTime();
+ s.type = 'text/javascript';
+ document.getElementsByTagName('head').item(0).appendChild(s);
+
+ // if lingo is enabled
+ if (useLingo) {
+ // load the lingo file
+ var l = document.createElement('script');
+ l.src = 'languages/' + languageOptions[0][0] + '/lingo.js?' + (new Date()).getTime();
+ l.type = 'text/javascript';
+ document.getElementsByTagName('head').item(0).appendChild(l);
+ }
+
+ // if there is more than one language installed on the server, show them as options
+ if(languageOptions.length > 1) {
+ for(var i=0; i' + languageOptions[i][1] + ' | ';
+
+ $('languageList').innerHTML = $('languageList').innerHTML.substring(0, $('languageList').innerHTML.length - 3);
+ }
+});
+
+
+/**
+ * Clear the value of input elements
+ *
+ * @author Joshua Gross
+ **/
+function clearInputs() {
+ var formInputs = document.getElementsByTagName('input');
+ for (var i=0; i 10 ? '...' : '') + '"';
+ blinkerTimer = setTimeout("titlebarBlink('"+name+"', '"+message+"', 2, "+chatroom+")", 1000);
+ } else if(alter == 2) {
+ document.title = defaultTitle;
+ blinkerTimer = setTimeout("titlebarBlink('"+name+"', '"+message+"', 0, "+chatroom+")", 1000);
+ }
+}
+
+
+/**
+ * Toggle the variable 'titlebarBlinker' to true/false
+ *
+ * @author Joshua Gross
+ * @update Benjamin Hutchins
+ **/
+function blinkerOn(onoff) {
+ titlebarBlinker = (onoff == true ? true : false);
+}
+
+
+/**
+ * Button effects for browsers without ":" support
+ *
+ * @arguments
+ * el - element to affect
+ *
+ * @author Joshua Gross
+ **/
+function buttonHover(el) {
+ var newsrc = el.src;
+ newsrc = newsrc.replace(/_hover/, '');
+ el.src = newsrc.replace(/\.png/, '_hover.png');
+}
+function buttonDown(el) {
+ el.src = el.src.replace(/_hover\.png/, '_down.png');
+}
+function buttonNormal(el) {
+ el.src = el.src.replace(/\_hover.png/, '.png').replace(/\_down.png/, '.png');
+}
+
+
+/**
+ * Check to see is an email is valid
+ *
+ * @arguments
+ * email - email to check
+ *
+ * @author Joshua Gross
+ * @updated Benjamin Hutchins
+ * @return true if email is valid, false otherwise
+ **/
+function checkEmailAddr(email) {
+ var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
+ return filter.test(email);
+}
+
+
+/**
+ * Generates a random string
+ *
+ * @arguments
+ * length - length of string to be created
+ *
+ * @author Joshua Gross
+ * @return random string
+ **/
+function randomString(length) {
+ var chars = "abcdefghijklmnopqrstuvwxyz1234567890";
+ var pass = "";
+ var charLength = chars.length;
+
+ for(x=0;x 0) {
+ do {
+ if (this[i] === search_term) {
+ return true;
+ }
+ } while (i--);
+ }
+ return false;
+}
+
+
+/**
+ * Checks to see if a string is alphanumeric (only letters and numbers)
+ *
+ * @author Joshua Gross
+ * @return true if string is alphanumeric, false otherwise
+ **/
+String.prototype.isAlphaNumeric = function() {return /^[A-Za-z0-9_\d]+$/.test (this)};
+
+
+/**
+ * Load the theme stylesheet
+ **/
+var loadCSS = document.createElement("link");
+loadCSS.setAttribute("rel", "stylesheet")
+loadCSS.setAttribute("type", "text/css")
+loadCSS.setAttribute("href", 'themes/' + theme + '/style.css')
+if (typeof loadCSS != "undefined")
+ document.getElementsByTagName("head")[0].appendChild(loadCSS);
diff --git a/js/browser.js b/js/browser.js
new file mode 100644
index 0000000..50f49f7
--- /dev/null
+++ b/js/browser.js
@@ -0,0 +1,47 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Class to handle browser requests
+ **/
+var Browser = {
+ /**
+ * Get the width of the client browser
+ *
+ * @author Joshua Gross
+ * @return Document Width
+ **/
+ width: function() {
+ if (self.innerWidth) {
+ return self.innerWidth;
+ } else if (document.documentElement && document.documentElement.clientWidth) {
+ return document.documentElement.clientWidth;
+ } else if (document.body) {
+ return document.body.clientWidth;
+ }
+ return 630;
+ },
+
+ /**
+ * Get the height of the client browser
+ *
+ * @author Joshua Gross
+ * @return Document Height
+ **/
+ height: function() {
+ if (self.innerWidth) {
+ return self.innerHeight;
+ } else if (document.documentElement && document.documentElement.clientWidth) {
+ return document.documentElement.clientHeight;
+ } else if (document.body) {
+ return document.body.clientHeight;
+ }
+ return 470;
+ }
+};
diff --git a/js/buddylist.js b/js/buddylist.js
new file mode 100644
index 0000000..5618f90
--- /dev/null
+++ b/js/buddylist.js
@@ -0,0 +1,428 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Class to handle buddylist events
+ *
+ * @author Joshua Gross
+ **/
+var Buddylist = {
+ buddyListWin: null, // buddy list window
+
+ /**
+ * Process the creation of the buddy list window
+ *
+ * @author Joshua Gross
+ **/
+ create: function() {
+ Event.observe(window, 'resize', Buddylist.fixBuddyList);
+
+ if(!$('bl')) {
+ this.buddyListWin = new Window({id: 'bl', className: "dialog", width: 210, height: (Browser.height() - 60), zIndex: 100, resizable: true, title: Languages.get('buddyList'), draggable: true, closable: false, maximizable: false, detachable: false, minWidth: 205, minHeight: 150, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+ this.buddyListWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+ }
+
+ this.buddyListWin.getContent().innerHTML = '';
+ Event.observe(this.buddyListWin.getContent(), 'contextmenu', function() { return false; });
+
+ $('bl_minimize').setStyle({left: (this.buddyListWin.getSize()['width'] - 21) + 'px'});
+
+ this.sizeBuddyList();
+
+ this.buddyListWin.showCenter(false, (((Browser.height()-40) / 2) - (this.buddyListWin.getSize()['height'] / 2)), (buddyListLoc == 0 ? 10 : (Browser.width() - this.buddyListWin.getSize()['width'] - 10)));
+ this.buddyListWin.toFront();
+
+ this.list = {};
+ this.listObjects = {};
+ this.blocked = {};
+ },
+
+ /**
+ * Destroy the buddy list window
+ *
+ * @author Joshua Gross
+ **/
+ destroy: function() {
+ this.buddyListWin.destroy();
+ },
+
+ /**
+ * Reposition buddylist
+ *
+ * @author Joshua Gross
+ **/
+ fixBuddyList: function() {
+ if(Buddylist.buddyListWin.isVisible()) {
+ Buddylist.buddyListWin.setSize(210, (Browser.height() - 60));
+ Buddylist.buddyListWin.setLocation((((Browser.height()-40) / 2) - (Buddylist.buddyListWin.getSize()['height'] / 2)), (buddyListLoc == 0 ? 10 : (Browser.width() - Buddylist.buddyListWin.getSize()['width'] - 10)));
+ Buddylist.sizeBuddyList();
+ }
+ },
+
+ /**
+ * Resize buddylist
+ *
+ * @author Joshua Gross
+ **/
+ sizeBuddyList: function() {
+ $('blContainer').setStyle({width: (this.buddyListWin.getSize()['width'] - 8) + 'px',
+ height: (this.buddyListWin.getSize()['height'] - 95) + 'px'});
+
+ $('blBottomToolbar').setStyle({width: (this.buddyListWin.getSize()['width'] - 8) + 'px',
+ top: (this.buddyListWin.getSize()['height'] - 7) + 'px'});
+
+ $('bl_minimize').setStyle({left: (this.buddyListWin.getSize()['width'] - 21) + 'px'});
+ },
+
+ /**
+ * Add new buddy to the list
+ *
+ * @arguments
+ * username - user's username
+ * groupname - group the user is in
+ *
+ * @author Joshua Gross
+ **/
+ addNewBuddy: function(username, groupname) {
+ username = username.toLowerCase();
+ if(!inArray(Buddylist.list, username) && (!Buddylist.listObjects[username] || !$(Buddylist.listObjects[username].obj))) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(pingTo, "POST", "call=isuser&username="+username, function(xh) {
+ if(xh.responseText == 'not_exists') {
+ $('newbuddy_error_msg').innerHTML = Languages.get('noSuchUser');
+ } else {
+ if(!$(groupname.replace(/\s/, '_') + '_group')) {
+ Buddylist.addGroup(groupname);
+ Buddylist.list[groupname] = [];
+ }
+
+ Buddylist.addBuddy(username, 'Offline', 'none');
+
+ if(parseInt(xh.responseText) == 0) {
+ Buddylist.moveBuddy(username, 'Offline');
+ $(Buddylist.listObjects[username].img).src = 'themes/' + theme + '/offline.png';
+ } else if(parseInt(xh.responseText) == 2) {
+ Buddylist.moveBuddy(username, groupname);
+ $(Buddylist.listObjects[username].img).src = 'themes/' + theme + '/away.png';
+ } else {
+ Buddylist.moveBuddy(username, groupname);
+ $(Buddylist.listObjects[username].img).src = 'themes/' + theme + '/online.png';
+ }
+
+ Buddylist.list[groupname][username] = {'username': username, 'blocked': false, 'status': parseInt(xh.responseText)};
+
+ var xhConn = new XHConn();
+ xhConn.connect(pingTo, "POST", "call=addbuddy&username="+username+'&group='+groupname, null);
+
+ Windows.close('newBuddy');
+ }
+ });
+ } else {
+ $('newbuddy_error_msg').innerHTML = Languages.get('alreadyOnBuddylist');
+ }
+ },
+
+ /**
+ * Add buddy to the list
+ *
+ * @arguments
+ * username - username of the buddy we're adding
+ * groupname - the group the buddy is in
+ * buddyicon - the buddy's buddyiocn
+ *
+ * @author Joshua Gross
+ * update Benjamin Hutchins
+ **/
+ addBuddy: function(username, groupname, buddyicon) {
+ if(!$(groupname.replace(/\s/, '_') + '_group')) this.addGroup(groupname);
+ var groupList = $(groupname.replace(/\s/, '_') + '_group');
+ var iconsrc = (buddyicon=='none'?defaultIcon:pathToIcons+username+'.'+buddyicon);
+
+ var randId = Math.floor(Math.random()*1000000000);
+ while($(randId + '_blItem'))
+ randId = Math.floor(Math.random()*1000000000);
+
+ groupList.innerHTML += '' + (useIcons&&showInList?(defaultIcon==""&&buddyicon=='none'?'':' '):'') + ' '+username+' ';
+
+ Buddylist.listObjects[username] = {};
+ Buddylist.listObjects[username].obj = randId + '_blItem';
+ Buddylist.listObjects[username].img = randId + '_blImg';
+ Buddylist.listObjects[username].icon = buddyicon;
+ Buddylist.listObjects[username].group = groupname;
+
+ $(Buddylist.listObjects[username].obj).setStyle({listStyleType: 'none'});
+ },
+
+ /**
+ * Move a buddy from one group to another
+ *
+ * @arguments
+ * username - username of the buddy we're moving
+ * groupname - new group name
+ *
+ * @author Joshua Gross
+ **/
+ moveBuddy: function(username, groupname) {
+ if(groupname == null) return;
+ if($(Buddylist.listObjects[username].obj).parentNode == $(groupname.replace(/\s/, '_') + '_group')) return;
+ if(!$(groupname.replace(/\s/, '_') + '_group')) this.addGroup(groupname);
+
+ var group = $(groupname.replace(/\s/, '_') + '_group')
+
+ group.insertBefore($(Buddylist.listObjects[username].obj), null);
+ },
+
+ /**
+ * Add a new group the buddylist window
+ *
+ * @arguments
+ * groupname - group to add
+ *
+ * @author Joshua Gross
+ **/
+ addGroup: function(groupname) {
+ var bList = $('buddylist');
+ bList.innerHTML = (groupname=='Offline' ? bList.innerHTML : '') + ' ' + groupname +
+ (groupname!='Offline' ? ' ' : '') + ' ' + "\n" + '' + (groupname!='Offline' ? bList.innerHTML : '');
+ },
+
+ /**
+ * Remove buddy from the buddylist permanently
+ *
+ * @arguments
+ * username - buddy we're removin
+ *
+ * @author Joshua Gross
+ **/
+ deleteBuddy: function(username) {
+ if(username.indexOf('_group') != -1) {
+ this.deleteGroup(username.substring(0, username.length - 6));
+ return;
+ }
+
+ var usernam = username;
+
+ var ingroup = null;
+ for (var group in this.list) {
+ if(typeof(this.list[group][username]) !== 'undefined' && this.list[group][username].username == username) {
+ ingroup = group;
+ break;
+ }
+ }
+
+ var buddyToRmv = $(Buddylist.listObjects[username].obj);
+
+ if(typeof(buddyToRmv) !== 'undefined') {
+ buddyToRmv.parentNode.removeChild(buddyToRmv);
+ if(this.list[ingroup]) {
+ this.list[ingroup][username] = null;
+
+ var xhConn = new XHConn();
+ xhConn.connect(pingTo, "POST", "call=removebuddy&username="+username, null);
+
+ }
+ Dialog.closeInfo();
+ }
+ },
+
+ /**
+ * Process the blocking of a buddy
+ *
+ * @arguments
+ * username - the buddy to be blocked
+ *
+ * @author Joshua Gross
+ * @update Benjamin Hutchins
+ **/
+ blockBuddy: function(username) {
+ var isBlocked = this.blocked.inArray(username);
+ if(isBlocked) {
+ for(var i=0; i= 2 ? 'themes/' + theme + '/away.png' : 'themes/' + theme + '/offline.png')));
+ if(!blockedBuddyStatus && isBlocked) {
+ Buddylist.moveBuddy(username, Languages.get('offline'));
+ }
+ break;
+ }
+ }
+ },
+
+ /**
+ * Remove a group from the buddylist permanently
+ *
+ * @arguments
+ * groupname - group to be removes
+ *
+ * @author Joshua Gross
+ **/
+ deleteGroup: function(groupname) {
+ var groupNoSpaces = groupname.replace(/\s/, '_');
+ var groupToRmv = $(groupNoSpaces+"_group");
+ var groupTop = $(groupNoSpaces+"_groupTop");
+
+ if(typeof(groupToRmv) !== 'undefined') {
+ groupToRmv.parentNode.removeChild(groupToRmv);
+ groupTop.parentNode.removeChild(groupTop);
+
+ for(var i=0;i 0) {
+ try {
+ var el = $(Buddylist.listObjects[curSelected].obj);
+ Element.addClassName(el, 'listNotSelected');
+ Element.removeClassName(el, 'listSelected');
+ Element.removeClassName(el, 'listHover');
+ } catch(e) { }
+ }
+
+ curSelected = username;
+
+ var oel = $(Buddylist.listObjects[curSelected].obj);
+ Element.addClassName(oel, 'listSelected');
+ Element.removeClassName(oel, 'listNotSelected');
+ Element.removeClassName(oel, 'listHover');
+ }
+ return false;
+ },
+
+ /**
+ * Process double clicks, open the IM window
+ *
+ * @author Joshua Gross
+ **/
+ onBuddyDblClick: function() {
+ if(curSelected.length > 0) {
+ if(typeof(IM.windows[curSelected]) == 'undefined') {
+ IM.create(curSelected, curSelected);
+ } else {
+ if(IM.windows[curSelected].detached) {
+ if(IM.windows[curSelected].popup.closed) {
+ IM.windows[curSelected] = IM.windows[curSelected].old;
+ IM.windows[curSelected].show();
+ } else {
+ IM.windows[curSelected].popup.focus();
+ }
+ } else if(!IM.windows[curSelected].isVisible()) {
+ IM.windows[curSelected].show();
+ IM.windows[curSelected].toFront();
+ setTimeout("scrollToBottom('" + IM.windows[curSelected].getId() + "_rcvd')", 125);
+ setTimeout("$('" + IM.windows[curSelected].getId() + "_sendBox').focus();", 250);
+ } else {
+ IM.windows[curSelected].toFront();
+ setTimeout("$('" + IM.windows[curSelected].getId() + "_sendBox').focus();", 250);
+ }
+ }
+ }
+ }
+};
diff --git a/js/buttonctl.js b/js/buttonctl.js
new file mode 100644
index 0000000..84e7bfd
--- /dev/null
+++ b/js/buttonctl.js
@@ -0,0 +1,76 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Button control class
+ */
+var ButtonCtl = {
+ /**
+ * Create a button/link wrapper
+ *
+ * @arguments
+ * text - innerHTML for link
+ * action - onClick action
+ * id - element ID to apply (if none is supplied, none is set)
+ *
+ * @author Joshua Gross
+ **/
+ create: function(text, action, id) {
+ return '' + text + ' ';
+ },
+
+ /**
+ * Create a submit input button wrapper
+ *
+ * @arguments
+ * text - value for input
+ * id - element ID to apply (if none is supplied, none is set)
+ *
+ * @authro Benjamin Hutchins
+ **/
+ createSubmit: function(text, id) {
+ return ' ';
+ },
+
+ /**
+ * Effect to apply to 'el' (element) on mouseover
+ *
+ * @arguments
+ * el - element to affect
+ *
+ * @author Joshua Gross
+ **/
+ hover: function(el) {
+ el.className = 'stdButton btnHover';
+ },
+
+ /**
+ * Effect to apply to 'el' (element) on mousedown
+ *
+ * @arguments
+ * el - element to affect
+ *
+ * @author Joshua Gross
+ **/
+ down: function(el) {
+ el.className = 'stdButton btnDown';
+ },
+
+ /**
+ * Restore 'el' (element) to normal on mouseout
+ *
+ * @arguments
+ * el - element to affect
+ *
+ * @author Joshua Gross
+ **/
+ normal: function(el) {
+ el.className = 'stdButton';
+ }
+};
diff --git a/js/chat.js b/js/chat.js
new file mode 100644
index 0000000..7e3e270
--- /dev/null
+++ b/js/chat.js
@@ -0,0 +1,362 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Chatroom Class
+ **/
+var Chatroom = {
+ windows: {}, // JavaScript object to store all chatroom windows
+
+ /**
+ * Create a new chatroom
+ *
+ * @arguments
+ * name - chatroom name
+ * imTitle - window title, default is chatroom name
+ *
+ * @author Joshua Gross
+ **/
+ create: function(name, imTitle) {
+ var imLeft = Math.round(Math.random()*(Browser.width()-360))+'px';
+ var imTop = Math.round(Math.random()*(Browser.height()-400))+'px';
+
+ var winId = randomString(32) + '_chat';
+
+ this.windows[name] = new ChatWindow({id: winId, className: "dialog", width: 475, height: 340, top: imTop, left: imLeft, resizable: true, title: imTitle, draggable: true, detachable: false, minWidth: 475, minHeight: 150, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ this.windows[name].setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ this.windows[name].getContent().innerHTML = '
' + "\n" +
+ '' + "\n" +
+ '' +
+ ' Tahoma ' +
+ ' 12 ' +
+ '
' +
+ ' ' +
+ "\n" + '
';
+
+ this.windows[name].setRoom(name);
+
+ $(winId + '_userlist').setStyle({left: (this.windows[name].getSize().width - 155) + 'px', height: (this.windows[name].getSize().height - 12) + 'px'});
+ $(winId + '_rcvd').setStyle({marginTop: '5px', height: (this.windows[name].getSize().height - 103) + 'px', width: (this.windows[name].getSize().width - 170) + 'px'});
+ $(winId + '_toolbar').setStyle({top: (this.windows[name].getSize().height - 73) + 'px', width: (this.windows[name].getSize().width - 170) + 'px'});
+ $(winId + '_setFont').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontSize').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontColor').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontColorColor').setStyle({backgroundColor: '#000'});
+ $(winId + '_insertEmoticon').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+
+ var sendBox = $(winId + '_sendBox');
+ sendBox.setStyle({top: (this.windows[name].getSize().height - 45) + 'px',
+ left: '2px',
+ width: (this.windows[name].getSize().width - 175) + 'px',
+ fontWeight: '400',
+ fontStyle: 'normal',
+ textDecoration: 'none'});
+
+ this.windows[name].show();
+ this.windows[name].toFront();
+ Windows.focusedWindow = this.windows[name];
+ setTimeout("$('"+winId+"_sendBox').focus();", 250);
+ },
+
+ /**
+ * Process chatroom window resize
+ *
+ * @arguments
+ * name - chatroom name
+ *
+ * @author Joshua Gross
+ **/
+ handleResize: function(name) {
+ var winId = this.windows[name].getId();
+
+ $(winId + '_userlist').setStyle({left: (this.windows[name].getSize().width - 155) + 'px', height: (this.windows[name].getSize().height - 12) + 'px'});
+ $(winId + '_rcvd').setStyle({height: (this.windows[name].getSize().height - 103) + 'px', width: (this.windows[name].getSize().width - 170) + 'px'});
+ $(winId + '_toolbar').setStyle({top: (this.windows[name].getSize().height - 73) + 'px', width: (this.windows[name].getSize().width - 170) + 'px'});
+ $(winId + '_setFont').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontSize').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontColor').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_setFontColorColor').setStyle({backgroundColor: '#000'});
+ $(winId + '_insertEmoticon').setStyle({top: (this.windows[name].getSize().height - 65) + 'px'});
+ $(winId + '_sendBox').setStyle({top: (this.windows[name].getSize().height - 45) + 'px', left: '2px', width: (this.windows[name].getSize().width - 175) + 'px'});
+ },
+
+ /**
+ * Send request to server to enter a chatroom
+ *
+ * @argument
+ * room - room name user is entering
+ *
+ * @author Joshua Gross
+ **/
+ join: function(room) {
+ room = room.toLowerCase();
+
+ var xhConn = new XHConn();
+ xhConn.connect(pingTo, "POST", "call=joinroom&room="+room,
+ function(xh) {
+ if(xh.responseText.indexOf('"') == -1) {
+ switch(xh.responseText) {
+ case 'already_joined':
+ $('newroom_error_msg').innerHTML = Languages.get('alreadyInRoom').replace('%1', room);
+ break;
+ case 'room_is_user':
+ $('newroom_error_msg').innerHTML = Languages.get('invalidRoom');
+ break;
+ case 'invalid_chars':
+ $('newroom_error_msg').innerHTML = Languages.get('invalidRoomChars');
+ break;
+ }
+ } else {
+ if(!$(room + '_im')) {
+ Chatroom.create(room, room);
+ } else {
+ if(!Chatroom.windows[room].isVisible()) {
+ Chatroom.windows[room].show();
+ setTimeout("scrollToBottom('" + room + "_rcvd')", 125);
+ }
+ }
+ var users = xh.responseText.parseJSON().users;
+ for(var i=0; i '+username+'';
+ $(username+'_'+this.room+'_chatUser').setStyle({listStyleType: 'none'});
+ },
+
+ /**
+ * Remove a user from the chatroom user list
+ *
+ * @arguments
+ * username - user to remove
+ *
+ * @author Joshua Gross
+ **/
+ deleteUser: function(username) {
+ var toDelete = $(username + '_' + this.room + '_chatUser');
+ if(typeof(toDelete) !== 'undefined')
+ toDelete.parentNode.removeChild(toDelete);
+ },
+
+ /**
+ * Process mouseover and mousout calls for the user list
+ *
+ * @arguments
+ * sel - element
+ * username - user's username
+ * selected - is mouse over or did it go out
+ *
+ * @author Joshua Gross
+ **/
+ selectUser: function(sel, username, selected) {
+ if(selected === false) {
+ if(this.curSelected != username) {
+ try {
+ Element.addClassName(sel, 'listNotSelected');
+ Element.removeClassName(sel, 'listSelected');
+ Element.removeClassName(sel, 'listHover');
+ } catch(e) { }
+ } else {
+ Element.addClassName(sel, 'listSelected');
+ Element.removeClassName(sel, 'listNotSelected');
+ Element.removeClassName(sel, 'listHover');
+ }
+ } else {
+ Element.addClassName(sel, 'listHover');
+ Element.removeClassName(sel, 'listSelected');
+ Element.removeClassName(sel, 'listNotSelected');
+ }
+ },
+
+ /**
+ * Process event when a user is clicked
+ *
+ * @arguments
+ * username - the username of the user clicked
+ *
+ * @author Josh Gross
+ **/
+ clickUser: function(username) {
+ if(this.curSelected.length > 0) {
+ try {
+ var el = $(this.curSelected + '_' + this.room + '_chatUser');
+ Element.addClassName(el, 'listNotSelected');
+ Element.removeClassName(el, 'listSelected');
+ Element.removeClassName(el, 'listHover');
+ } catch(e) { }
+ }
+
+ this.curSelected = username;
+
+ var oel = $(this.curSelected + '_' + this.room + '_chatUser');
+ Element.addClassName(oel, 'listSelected');
+ Element.removeClassName(oel, 'listNotSelected');
+ Element.removeClassName(oel, 'listHover');
+ },
+
+ /**
+ * On DoubleClick of a user from the chatroom user
+ * list, start a private IM with him/her.
+ *
+ * @author Joshua Gross
+ **/
+ onUserDblClick: function() {
+ if(this.curSelected.length > 0) {
+ if(typeof(IM.windows[this.curSelected]) == 'undefined') {
+ IM.create(this.curSelected, this.curSelected);
+ } else {
+ if(!IM.windows[this.curSelected].isVisible()) {
+ IM.windows[this.curSelected].show();
+ IM.windows[this.curSelected].toFront();
+ setTimeout("scrollToBottom('" + IM.windows[this.curSelected].getId() + "_rcvd')", 125);
+ setTimeout("$('" + IM.windows[this.curSelected].getId() + "_sendBox').focus();", 250);
+ } else {
+ IM.windows[this.curSelected].toFront();
+ setTimeout("$('" + IM.windows[this.curSelected].getId() + "_sendBox').focus();", 250);
+ }
+ }
+ }
+ }
+});
+
+
+/**
+ * Class to handle the window of the chat rooms
+ **/
+var ChatroomList = {
+ curSelected: '', // current selected chat room
+
+ /**
+ * Get list of chat rooms that exist
+ *
+ * @author Joshua Gross
+ **/
+ get: function(applyTo) {
+ var xhConn = new XHConn();
+
+ xhConn.connect(pingTo, "POST", "call=roomlist", function(xh) {
+ var rooms = xh.responseText.parseJSON();
+
+ applyTo.innerHTML = ' ';
+
+ if(rooms.length > 0 || predefRooms.length > 0) {
+ for(var i=0; i' + rooms[i] + '';
+ }
+ }
+
+ for(var i=0; i' + predefRooms[i] + '';
+ }
+ }
+ } else {
+ applyTo.innerHTML += '' + Languages.get('noRoomsExist') + ' ';
+ }
+ applyTo.innerHTML += ' ';
+ });
+ },
+
+ /**
+ * Proccess mouseover and mouseout of list items
+ *
+ * @arguments
+ * sel - list element
+ * roomname - chatroom name
+ * selected - did mouse go over or out
+ *
+ * @author Joshua Gross
+ **/
+ selectRoom: function(sel, roomname, selected) {
+ if(selected === false) {
+ if(this.curSelected != roomname) {
+ try {
+ Element.addClassName(sel, 'listNotSelected').removeClassName('listSelected').removeClassName('listHover');
+ } catch(e) { }
+ } else {
+ Element.addClassName(sel, 'listSelected').removeClassName('listNotSelected').removeClassName('listHover');
+ }
+ } else {
+ Element.addClassName(sel, 'listHover').removeClassName('listSelected').removeClassName('listNotSelected');
+ }
+ },
+
+ /**
+ * Process the clicking of a room
+ *
+ * @arguments
+ * roomname - room that was clicked
+ *
+ * @author Joshua Gross
+ **/
+ clickRoom: function(roomname) {
+ if(this.curSelected.length > 0) {
+ try {
+ Element.addClassName($('chatroom_list_' + hex_md5(this.curSelected)), 'listNotSelected').removeClassName('listSelected').removeClassName('listHover');
+ } catch(e) { }
+ }
+
+ this.curSelected = roomname;
+ $('roomname').value = roomname;
+
+ Element.addClassName($('chatroom_list_' + hex_md5(roomname)), 'listSelected').removeClassName('listNotSelected').removeClassName('listHover');
+ }
+};
diff --git a/js/config.js b/js/config.js
new file mode 100644
index 0000000..e48f8b5
--- /dev/null
+++ b/js/config.js
@@ -0,0 +1,110 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+// Configuration //
+
+// Title //
+var siteName = 'ajax im'; // Name of your site (appears as the page title).
+ // If '', then the title will be used from the index file.
+
+// Registration //
+var allowNewUsers = true; // Enable/Disable open registration
+
+// Languages //
+// Format: [
+// ['folderName', 'properName'],
+// ['language2Folder', 'Language 2 Proper Name'],
+// ...
+// ]
+// Note: The first language will be used as the default language.
+var languageOptions = [
+ ['english', 'English']
+ ];
+
+// Theme Settings //
+var theme = 'dark'; // ajax im theme
+var alertWidth = 400; // alert window width
+
+// Notification //
+var useBlinker = true; // Show new message in titlebar when window isn't active.
+var blinkSpeed = 1000; // How fast to change between the titles when "blinking" (in milliseconds).
+var pulsateTitles = true; // Pulsate (blink) IM window titles on new IM when they are not the active window.
+var audioNotify = true; // By default, play sounds upon getting an IM?
+
+// Server //
+var pingFrequency = 2500; // How often to ping the server (in milliseconds). Best range between 2500 and 3500 ms.
+var pingTo = 'ajax_im.php'; // The file that is the "server".
+var adminPingTo = 'admin.php'; // The "server" script for admin functions.
+var blockedBuddyStatus = false; // Show blocked buddies' status.
+
+// Windows //
+var imWidth = 310; // Default IM window width
+var imHeight = 335; // Default IM window height
+var imDetachable = true; // Enable/Disable ability to detach IM windows from the application
+var buddyListLoc = 1; // Default buddylist location: 0=left, 1=right (of window)
+
+// Timeouts //
+var idleTime = 15; // How long until a user goes idle from now sending any messages (in minutes).
+ // If 0, feature not used.
+
+// Lingo Text-Replacement //
+var useLingo = true; // Automated text replacement for messaging. Will replace typos and shorthand,
+ // as defined in the current language's lingo.js file, with the proper replacement
+ // text.
+var lingoPunction = [ // Punction the can be placed at the end of a word/setence.
+ [" ", " "], // Format: [RegularExpression, Real]
+ ["\\.\\.", ".."],
+ ["\\.\\.\\.", "..."],
+ ["\\.\\.\\.\\.", "...."],
+ ["\\.\\.\\.\\.\\.", "....."],
+ ["\\.", "."],
+ [",", ","],
+ [";", ";"],
+ ["\\!", "!"],
+ ["\\?", "?"]
+ ];
+
+// Buddy Icons //
+var useIcons = true; // Enable/Disable use of buddy icons
+var pathToIcons = './buddyicons/';// Path to buddy icons, include trailing slash.
+var showInList = false; // Enable/Disable showing of buddy icons in the buddy list
+var vanishingIcons = true; // Enable/Disable the hiding of the buddy icons in a chat
+var vanishingSpeed = 10000; // Show the buddy icon for X amount until it is hidden (in milliseconds).
+var defaultIcon = ''; // Location of image to use when no buddy icon is availible
+ // If blank, no default icon is used
+
+
+// Messaging History //
+var imHistory = true; // Retain conversations with buddies throughout the session?
+ // How it works: If an IM window is closed an imHistory is true,
+ // next time that IM window is opened (during the same session!),
+ // the old chat text will be there
+
+// Chatrooms //
+var predefRooms = []; // Define preset rooms that will always exist when a user views the "Join Room" list.
+ // Format: ['room1', 'room2', ...]
+
+// Timestamp Format //
+// This is the timestamp format used to note when an IM was received.
+/* M = month, Jan - Dec
+ * m = month, 01 - 12, with prepended 0 (01, 02, ...)
+ * u = month, 1 - 12, without prepended 0 (1, 2, ...)
+ * d = day, 01 - 31, with prepended 0 (01, 02, ...)
+ * x = day, 1 - 31, without prepended 0 (1, 2, ...)
+ * Y = year, 4 digits (eg: 2008)
+ * y = year, 2 digits (eg: 08)
+ * H = hours, 24-hour format with prepended 0 (01, 02, ...)
+ * h = hours, 12-hour format without prepended 0 (1, 2, ...)
+ * Q = hours, 24-hour format without prepended 0 (1, 2, ...)
+ * q = hours, 12-hour format with prepended 0 (01, 02, ...)
+ * i = minutes
+ * s = seconds
+ * a = am/pm
+ * A = AM/PM
+ */
+var timestamp = '[h:i:s a]';
diff --git a/js/context.js b/js/context.js
new file mode 100644
index 0000000..a5e8fd5
--- /dev/null
+++ b/js/context.js
@@ -0,0 +1,146 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Handle all right-click menus for buddy list
+ *
+ * @author Benjamin Hutchins
+ **/
+var Context = {
+ currentUser: null, // current user that the menu is being shown for
+ lastClicked: null, // last user that was right-clicked
+
+ /**
+ * On window load, apply new observes
+ *
+ * @author Benjamin Hutchins
+ **/
+ loaded: function() {
+ if (typeof document.oncontextmenu != 'undefined') {
+ document.oncontextmenu = Context.oncontextmenu;
+ } else {
+ window.oncontextmenu = Context.oncontextmenu;
+ }
+
+ document.onmousedown = window.onmousedown = Context.onmousedown;
+ },
+
+ /**
+ * onClick of 'Get Info', open the users' profile.
+ *
+ * @author Benjamin Hutchins
+ **/
+ profile: function() {
+ $('divContext').style.display = 'none';
+ if(typeof(Profile.windows[Context.currentUser]) == 'undefined') {
+ Profile.create(Context.currentUser, Context.currentUser);
+ } else {
+ if(!Profile.windows[Context.currentUser].isVisible()) {
+ Profile.windows[Context.currentUser].show();
+ Profile.windows[Context.currentUser].toFront();
+ } else {
+ Profile.windows[Context.currentUser].toFront();
+ }
+ }
+ },
+
+ /**
+ * onClick of 'IM', open the conversation window with the user.
+ *
+ * @author Benjamin Hutchins
+ **/
+ createIM: function() {
+ $('divContext').style.display = 'none';
+ if(typeof(IM.windows[Context.currentUser]) == 'undefined') {
+ IM.create(Context.currentUser, Context.currentUser);
+ } else {
+ if(IM.windows[Context.currentUser].detached) {
+ if(IM.windows[Context.currentUser].popup.closed) {
+ IM.windows[Context.currentUser] = IM.windows[Context.currentUser].old;
+ IM.windows[Context.currentUser].show();
+ } else {
+ IM.windows[Context.currentUser].popup.focus();
+ }
+ } else if(!IM.windows[Context.currentUser].isVisible()) {
+ IM.windows[Context.currentUser].show();
+ IM.windows[Context.currentUser].toFront();
+ setTimeout("scrollToBottom('" + IM.windows[Context.currentUser].getId() + "_rcvd')", 125);
+ setTimeout("$('" + IM.windows[Context.currentUser].getId() + "_sendBox').focus();", 250);
+ } else {
+ IM.windows[Context.currentUser].toFront();
+ setTimeout("$('" + IM.windows[Context.currentUser].getId() + "_sendBox').focus();", 250);
+ }
+ }
+ },
+
+ /**
+ * onClick of 'Block' or 'Unblock', toggle the user's blocked status.
+ *
+ * @author Benjamin Hutchins
+ **/
+ blockBuddy: function() {
+ $('divContext').style.display = 'none';
+ Dialogs.blockBuddy(Context.currentUser);
+ },
+
+ /**
+ * onClick of 'Remove', remove the user from the friend's list.
+ *
+ * @author Benjamin Hutchins
+ **/
+ removeBuddy: function() {
+ $('divContext').style.display = 'none';
+ Dialogs.removeBuddy(Context.currentUser);
+ },
+
+ /**
+ * Global onContextMenu handler
+ *
+ * @author Benjamin Hutchins
+ **/
+ oncontextmenu: function (event) {
+ if (loggedIn && Context.lastClicked != null) {
+ event = event || window.event;
+
+ Context.currentUser = Context.lastClicked;
+ var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
+ var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
+
+ $('divContext').style.display = 'none';
+ var group = Buddylist.listObjects[Context.currentUser].group;
+ $('contextBlock').innerHTML = (typeof Buddylist.list[group] != 'undefined' && Buddylist.list[group][Context.currentUser].blocked == true ? Languages.get('contextUnblock') : Languages.get('contextBlock'));
+ Element.setStyle($('divContext'), {
+ left: (event.clientX + scrollLeft - 5) + 'px',
+ top: (event.clientY + scrollTop - 5) + 'px',
+ zIndex: Windows.maxZIndex + 20,
+ display: 'block'
+ });
+
+ Context.lastClicked = null;
+ return false;
+ } else if ($('divContext')) {
+ $('divContext').style.display = 'none';
+ }
+ },
+
+ /**
+ * Global onMouseDown handler, hide right-click menu,
+ * as long as it wasn't a right click.
+ *
+ * @author Benjamin Hutchins
+ **/
+ onmousedown: function (event) {
+ if (loggedIn) {
+ event = event || window.event;
+ if (event.button != 2 && event.button != 3) {
+ setTimeout("$('divContext').style.display='none';", 100);
+ }
+ }
+ }
+};
diff --git a/js/dialogs.js b/js/dialogs.js
new file mode 100644
index 0000000..118a6d3
--- /dev/null
+++ b/js/dialogs.js
@@ -0,0 +1,405 @@
+///////////////////////////////////
+// ajax im 3.41 //
+// AJAX Instant Messenger //
+// Copyright (c) 2006-2008 //
+// http://www.ajaxim.com/ //
+// Do not remove this notice //
+///////////////////////////////////
+
+
+/**
+ * Dialog and windows class
+ *
+ * @author Joshua Gross
+ **/
+var Dialogs = {
+ /**
+ * Display login modal
+ *
+ * @author Joshua Gross
+ **/
+ login: function() {
+ clearInputs();
+ $('login_error_msg').innerHTML = '';
+ this.mainDialogShow('login');
+ this.currentMainDialog = 'login';
+ setTimeout("try { $('username').focus(); } catch(e) { }", 1125);
+ },
+
+ /**
+ * Display register modal
+ *
+ * @author Joshua Gross
+ **/
+ register: function() {
+ clearInputs();
+ $('register_error_msg').innerHTML = '';
+ Dialogs.mainDialogShow('register');
+ this.currentMainDialog = 'register';
+ setTimeout("try { $('newusername').focus(); } catch(e) { }", 505);
+ },
+
+ /**
+ * Display forgot password modal
+ *
+ * @author Joshua Gross
+ **/
+ forgotPass: function() {
+ clearInputs();
+ $('forgotpass_error_msg').innerHTML = '';
+ Dialogs.mainDialogShow('forgotPass');
+ this.currentMainDialog = 'forgotPass';
+ setTimeout("try { $('resetto').focus(); } catch(e) { }", 505);
+ },
+
+ /**
+ * Display main dialog
+ *
+ * @author Joshua Gross
+ **/
+ mainDialogShow: function(dialog) {
+ if(this.currentMainDialog) Element.setStyle(this.currentMainDialog + 'Dialog', {'display': 'none'});
+ Element.setStyle(dialog + 'Dialog', {'display': 'block'});
+ },
+
+ /**
+ * New IM window, or IM Anyone. Displays a window to enter a
+ * username in attempt to message a new friend.
+ *
+ * @author Joshua Gross
+ **/
+ newIM: function() {
+ var newIMWin;
+ if($('newIM')) {
+ Windows.getWindow('newIM').toFront();
+ return;
+ }
+
+ newIMWin = new Window({id: 'newIM', className: "dialog", width: 240, height: 120, resizable: false, title: Languages.get('newIM'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 120, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ newIMWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ newIMWin.getContent().innerHTML = '' + Languages.get('newIMPlease') + '
\
+ \
+ \
+
' + Languages.get('username') + ':
\
+
\
+ ' +
+ ButtonCtl.create(Languages.get('openIM'), 'IM.newIMWindow();') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'newIM\');') +
+ '
';
+
+ $('newim_buttons').setStyle({position: 'absolute', top: '110px', left: '25px'});
+ newIMWin.setDestroyOnClose();
+ newIMWin.showCenter();
+ setTimeout("$('sendto').focus();", 125);
+ },
+
+ /**
+ * Display a window that will allow the user
+ * to enter a name for a chat room to be created.
+ *
+ * @author Joshua Gross
+ **/
+ newRoom: function() {
+ var newRoomWin;
+ if($('newRoom')) {
+ Windows.getWindow('newRoom').toFront();
+ return;
+ }
+
+ newRoomWin = new Window({id: 'newRoom', className: "dialog", width: 240, height: 300, resizable: false, title: Languages.get('newRoom'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 120, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ newRoomWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ newRoomWin.getContent().innerHTML = '' + Languages.get('newRoomPlease') + '
\
+ \
+ \
+
' + Languages.get('roomname') + ':
\
+
\
+
\
+ ' +
+ ButtonCtl.create(Languages.get('joinRoom'), 'Chatroom.join($(\'roomname\').value);') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'newRoom\');') +
+ '
';
+
+ $('newroom_buttons').setStyle({position: 'absolute', top: '290px', left: '25px'});
+
+ ChatroomList.get($('newroom_room_list'));
+
+ newRoomWin.setDestroyOnClose();
+ newRoomWin.showCenter();
+ setTimeout("$('roomname').focus();", 125);
+ },
+
+ /**
+ * Display a window to allow the user to enter another
+ * buddy's username and a group name to have the user added
+ * to the user's buddylist.
+ *
+ * @author Joshua Gross
+ **/
+ newBuddy: function() {
+ var newBuddyWin;
+ if($('newBuddy')) {
+ Windows.getWindow('newBuddy').toFront();
+ return;
+ }
+
+ newBuddyWin = new Window({id: 'newBuddy', className: "dialog", width: 240, height: 160, resizable: false, title: Languages.get('newBuddy'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 120, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ newBuddyWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ newBuddyWin.getContent().innerHTML = '' + Languages.get('newBuddyPlease') + '
\
+ \
+ \
+ ' +
+ ButtonCtl.create(Languages.get('add'), 'Buddylist.addNewBuddy($(\'newBuddyUsername\').value, $(\'newBuddyGroup\').value);') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'newBuddy\');') +
+ '
';
+
+ $('newbuddy_buttons').setStyle({position: 'absolute', top: '150px', left: '25px'});
+
+ newBuddyWin.setDestroyOnClose();
+ newBuddyWin.showCenter();
+ setTimeout("$('newBuddyUsername').focus();", 125);
+ },
+
+ /**
+ * Display a window to confirm the removal of a buddy.
+ *
+ * @author Joshua Gross
+ * @update Benjamin Hutchins
+ **/
+ removeBuddy: function(username) {
+ var delBuddyWin;
+
+ if (typeof username == 'undefined')
+ var username = curSelected;
+
+ if(username == '' || username.length == 0)
+ return;
+
+ if($('delBuddy')) {
+ Windows.getWindow('delBuddy').toFront();
+ return;
+ }
+
+ delBuddyWin = new Window({id: 'delBuddy', className: "dialog", width: 240, height: 70, resizable: false, title: Languages.get('removeBuddy'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight:70, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ delBuddyWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ delBuddyWin.getContent().innerHTML = '' + Languages.get('removeBuddyAreYouSure').replace('%1', username) + '
\
+ ' +
+ ButtonCtl.create(Languages.get('ok'), 'Buddylist.deleteBuddy(\'' + username + '\');Windows.close(\'delBuddy\');') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'delBuddy\');') +
+ '
';
+
+ $('delbuddy_buttons').setStyle({position: 'absolute', top: '60px', left: '25px'});
+
+ delBuddyWin.setDestroyOnClose();
+ delBuddyWin.showCenter();
+ },
+
+ /**
+ * Display a window to confirm the blocking/unblocking
+ * of a buddy.
+ *
+ * @author Joshua Gross
+ **/
+ blockBuddy: function(buddy) {
+ var blockBuddyWin;
+
+ if($('blockBuddy')) {
+ Windows.getWindow('blockBuddy').toFront();
+ return;
+ }
+
+ blockBuddyWin = new Window({id: 'blockBuddy', className: "dialog", width: 240, height: 70, resizable: false, title: Languages.get('blockBuddy'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight:70, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ blockBuddyWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ blockBuddyWin.getContent().innerHTML = '' + (Buddylist.blocked.inArray(buddy) ? Languages.get('unblockBuddyAreYouSure').replace('%1', buddy) : Languages.get('blockBuddyAreYouSure').replace('%1', buddy)) + '
\
+ ' +
+ ButtonCtl.create(Languages.get('ok'), 'Buddylist.blockBuddy(\'' + buddy + '\');Windows.close(\'blockBuddy\');') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'blockBuddy\');') +
+ '
';
+
+ $('blockbuddy_buttons').setStyle({position: 'absolute', top: '60px', left: '25px'});
+
+ blockBuddyWin.setDestroyOnClose();
+ blockBuddyWin.showCenter();
+ },
+
+ /**
+ * Display a window to confirm the removal of an
+ * entire buddy group.
+ *
+ * @author Joshua Gross
+ **/
+ removeGroup: function(group) {
+ var delGroupWin;
+ if($('delGroup')) {
+ Windows.getWindow('delGroup').toFront();
+ return;
+ }
+
+ delGroupWin = new Window({id: 'delGroup', className: "dialog", width: 240, height: 70, resizable: false, title: Languages.get('removeGroup'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight:70, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ delGroupWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ delGroupWin.getContent().innerHTML = '' + Languages.get('removeGroupAreYouSure').replace('%1', group) + '
\
+ ' +
+ ButtonCtl.create(Languages.get('ok'), 'Buddylist.deleteGroup(\'' + group + '\');Windows.close(\'delGroup\');') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'delGroup\');') +
+ '
';
+
+ $('delgroup_buttons').setStyle({position: 'absolute', top: '60px', left: '25px'});
+
+ delGroupWin.setDestroyOnClose();
+ delGroupWin.showCenter();
+ },
+
+ /**
+ * Display a window to show the available settings
+ * that the user can change.
+ *
+ * @author Benjamin Hutchins
+ **/
+ changeSettings: function() {
+ var changeSettings;
+ if($('changeSettings')) {
+ Windows.getWindow('changeSettings').toFront();
+ return;
+ }
+
+ changeSettings = new Window({id: 'changeSettings', className: "dialog", width: 300, height: 160, resizable: false, title: Languages.get('changeSettings'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 150, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ changeSettings.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ changeSettings.getContent().innerHTML = '' + Languages.get('changeSettingsInstructions') + '
\
+ ' +
+ ButtonCtl.create(Languages.get('changeSettingsPassword'), 'Dialogs.changePass();if($(\'changeSettings\')){Windows.close(\'changeSettings\');}') +
+ ButtonCtl.create(Languages.get('changeSettingsProfile'), 'Dialogs.changeProfile();if($(\'changeSettings\')){Windows.close(\'changeSettings\');}') +
+ (useIcons ? ButtonCtl.create(Languages.get('changeSettingsBuddyicon'), 'Dialogs.changeIcon();if($(\'changeSettings\')){Windows.close(\'changeSettings\');}') : '') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'changeSettings\');') +
+ '
';
+
+ $('changesettings_buttons').setStyle({position: 'absolute', top: '60px', left: '85px'});
+
+ changeSettings.setDestroyOnClose();
+ changeSettings.showCenter();
+ },
+
+ /**
+ * Display a window to allow the user to change
+ * their buddy profile.
+ *
+ * @author Benjamin Hutchins
+ **/
+ changeProfile: function() {
+ var changeProfileWin;
+ if($('changeProfile')) {
+ Windows.getWindow('changeProfile').toFront();
+ return;
+ }
+
+ changeProfileWin = new Window({id: 'changeProfile', className: "dialog", width: 300, height: 250, resizable: false, title: Languages.get('changeProfile'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 240, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+ changeProfileWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+ changeProfileWin.getContent().innerHTML = '' + Languages.get('changeProfileInstructions') + '
\
+ \
+ \
+ ' +
+ ButtonCtl.create(Languages.get('change'), 'System.changeProfile();') +
+ ButtonCtl.create(Languages.get('cancel'), 'Windows.close(\'changeProfile\');') +
+ '
';
+
+ $('changeprofile_buttons').setStyle({position: 'absolute', top: '245px', left: '55px'});
+
+ var xhConn = new XHConn();
+ xhConn.connect(pingTo, "POST", "call=getprofile&user="+user,
+ function(xh) {
+ $('changeprofile_textarea').value = xh.responseText;
+ }
+ );
+
+ changeProfileWin.setDestroyOnClose();
+ changeProfileWin.showCenter();
+ },
+
+ /**
+ * Display a window to allow the user to upload
+ * a new buddy icon.
+ *
+ * @author Benjamin Hutchins
+ **/
+ changeIcon: function () {
+ if(!useIcons) return;
+
+ var changeIconWin;
+ if($('changeIcon')) {
+ Windows.getWindow('changeIcon').toFront();
+ return;
+ }
+
+ changeIconWin = new Window({id: 'changeIcon', className: "dialog", width: 300, height: 160, resizable: false, title: Languages.get('changeBuddyicon'), draggable: true, closable: true, maximizable: false, minimizable: false, detachable: false, minWidth: 240, minHeight: 120, showEffectOptions: {duration: 0}, hideEffectOptions: {duration: 0}});
+
+ changeIconWin.setConstraint(true, {left: 0, right: 0, top: 0, bottom: 0});
+
+ changeIconWin.getContent().innerHTML = '' + Languages.get('changeBuddyiconInstructions') + '
\
+ \
+