"user", $kind_agent => "agent", $kind_for_agent => "hidden",
						$kind_info => "inf", $kind_conn => "conn", $kind_events => "event", $kind_avatar => "avatar");
function get_user_id()
{
	return (time() + microtime()) . rand(0, 99999999);
}
function next_token()
{
	return rand(99999, 99999999);
}
function next_revision()
{
	$db = Database::getInstance();
	$db->query("update {chatrevision} set id=LAST_INSERT_ID(id+1)");
	$val = $db->insertedId();
	return $val;
}
/**
 * @todo Think about post_message_ and post_message diffrence
 */
function post_message_($threadid, $kind, $message, $from = null, $utime = null, $opid = null)
{
	$db = Database::getInstance();
	$query = "insert into {chatmessage} " .
		"(threadid,ikind,tmessage,tname,agentId,dtmcreated) " .
		"values (:threadid,:kind,:message,:name,:agentid,:created)";
	 $values = array(
		':threadid' => $threadid,
		':kind' => $kind,
		':message' => $message,
		':name' => ($from ? $from : "null"),
		':agentid' => ($opid ? $opid : 0),
		':created' => ($utime ? $utime : time())
	);
	$db->query($query, $values);
	return $db->insertedId();
}
function post_message($threadid, $kind, $message, $from = null, $agentid = null)
{
	return post_message_($threadid, $kind, $message, $from, null, $agentid);
}
function prepare_html_message($text, $allow_formating)
{
	$escaped_text = htmlspecialchars($text);
	$text_w_links = preg_replace('/(https?|ftp):\/\/\S*/', '$0', $escaped_text);
	$multiline = str_replace("\n", "
", $text_w_links);
	if (! $allow_formating) {
		return $multiline;
	}
	$formated = preg_replace('/<(span|strong)>(.*)<\/\1>/U', '<$1>$2$1>', $multiline);
	$formated = preg_replace('/<span class="(.*)">(.*)<\/span>/U', '$2', $formated);
	return $formated;
}
function message_to_html($msg)
{
	global $kind_to_string, $kind_user, $kind_agent, $kind_avatar;
	if ($msg['ikind'] == $kind_avatar) return "";
	$message = "" . date("H:i:s", $msg['created']) . " ";
	$kind = $kind_to_string{$msg['ikind']};
	if ($msg['tname'])
		$message .= "" . htmlspecialchars($msg['tname']) . ": ";
	$allow_formating = ($msg['ikind'] != $kind_user && $msg['ikind'] != $kind_agent);
	$message .= "" . prepare_html_message($msg['tmessage'], $allow_formating) . "
";
	return $message;
}
function message_to_text($msg)
{
	global $kind_user, $kind_agent, $kind_info, $kind_avatar;
	if ($msg['ikind'] == $kind_avatar) return "";
	$message_time = date("H:i:s ", $msg['created']);
	if ($msg['ikind'] == $kind_user || $msg['ikind'] == $kind_agent) {
		if ($msg['tname'])
			return $message_time . $msg['tname'] . ": " . $msg['tmessage'] . "\n";
		else
			return $message_time . $msg['tmessage'] . "\n";
	} else if ($msg['ikind'] == $kind_info) {
		return $message_time . $msg['tmessage'] . "\n";
	} else {
		return $message_time . "[" . $msg['tmessage'] . "]\n";
	}
}
function get_messages($threadid, $meth, $isuser, &$lastid)
{
	global $kind_for_agent, $kind_avatar, $webim_encoding;
	$db = Database::getInstance();
	$msgs = $db->query(
		"select messageid,ikind,dtmcreated as created,tname,tmessage from {chatmessage} " .
		"where threadid = :threadid and messageid > :lastid " .
		($isuser ? "and ikind <> {$kind_for_agent} " : "") .
		"order by messageid",
		array(
			':threadid' => $threadid,
			':lastid' => $lastid,
		),
		array('return_rows' => Database::RETURN_ALL_ROWS)
		
	);
	$messages = array();
	foreach ($msgs as $msg) {
		$message = "";
		if ($meth == 'xml') {
			switch ($msg['ikind']) {
				case $kind_avatar:
					$message = "" . myiconv($webim_encoding, "utf-8", escape_with_cdata($msg['tmessage'])) . "";
					break;
				default:
					$message = "" . myiconv($webim_encoding, "utf-8", escape_with_cdata(message_to_html($msg))) . "\n";
			}
		} else {
			if ($msg['ikind'] != $kind_avatar) {
				$message = (($meth == 'text') ? message_to_text($msg) : topage(message_to_html($msg)));
			}
		}
		$messages[] = $message;
		if ($msg['messageid'] > $lastid) {
			$lastid = $msg['messageid'];
		}
	}
	return $messages;
}
function print_thread_messages($thread, $token, $lastid, $isuser, $format, $agentid = null)
{
	global $webim_encoding, $webimroot, $connection_timeout;
	$threadid = $thread['threadid'];
	$istyping = abs(time() - $thread[$isuser ? "lpagent" : "lpuser"]) < $connection_timeout
				&& $thread[$isuser ? "agentTyping" : "userTyping"] == "1" ? "1" : "0";
	if ($format == "xml") {
		$output = get_messages($threadid, "xml", $isuser, $lastid);
		start_xml_output();
		print("");
		foreach ($output as $msg) {
			print $msg;
		}
		print("");
	} else if ($format == "html") {
		$output = get_messages($threadid, "html", $isuser, $lastid);
		start_html_output();
		$url = "$webimroot/thread.php?act=refresh&thread=$threadid&token=$token&html=on&user=" . ($isuser ? "true" : "false");
		print(
				"" .
				"\n
\n" .
				"\n" .
				"\n" .
				"\n" .
				"chat\n" .
				"\n" .
				"" .
				"| ");
		foreach ($output as $msg) {
			print $msg;
		}
		print(
				" | 
" .
				"");
	}
}
function get_user_name($username, $addr, $id)
{
	return str_replace(
		"{addr}", $addr,
		str_replace(
			"{id}", $id,
			str_replace("{name}", $username, Settings::get('usernamepattern'))
		)
	);
}
function is_ajax_browser($browserid, $ver, $useragent)
{
	if ($browserid == "opera")
		return $ver >= 8.02;
	if ($browserid == "safari")
		return $ver >= 125;
	if ($browserid == "msie")
		return $ver >= 5.5 && !strstr($useragent, "powerpc");
	if ($browserid == "netscape")
		return $ver >= 7.1;
	if ($browserid == "mozilla")
		return $ver >= 1.4;
	if ($browserid == "firefox")
		return $ver >= 1.0;
	if ($browserid == "chrome")
		return true;
	return false;
}
function is_old_browser($browserid, $ver)
{
	if ($browserid == "opera")
		return $ver < 7.0;
	if ($browserid == "msie")
		return $ver < 5.0;
	return false;
}
$knownAgents = array("opera", "msie", "chrome", "safari", "firefox", "netscape", "mozilla");
function get_remote_level($useragent)
{
	global $knownAgents;
	$useragent = strtolower($useragent);
	foreach ($knownAgents as $agent) {
		if (strstr($useragent, $agent)) {
			if (preg_match("/" . $agent . "[\\s\/]?(\\d+(\\.\\d+)?)/", $useragent, $matches)) {
				$ver = $matches[1];
				if (is_ajax_browser($agent, $ver, $useragent))
					return "ajaxed";
				else if (is_old_browser($agent, $ver))
					return "old";
				return "simple";
			}
		}
	}
	return "simple";
}
function is_agent_opera95()
{
	$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
	if (strstr($useragent, "opera")) {
		if (preg_match("/opera[\\s\/]?(\\d+(\\.\\d+)?)/", $useragent, $matches)) {
			$ver = $matches[1];
			if ($ver >= "9.5")
				return true;
		}
	}
	return false;
}
function is_mac_opera()
{
	$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
	return strstr($useragent, "opera") && strstr($useragent, "mac");
}
function needsFramesrc()
{
	$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
	return strstr($useragent, "safari/");
}
function setup_logo($group = NULL)
{
	global $page;
	$toplevelgroup = (!$group)?array():get_top_level_group($group);
	$page['ct.company.name'] = topage(empty($toplevelgroup['vctitle'])?Settings::get('title'):$toplevelgroup['vctitle']);
	$page['ct.company.chatLogoURL'] = topage(empty($toplevelgroup['vclogo'])?Settings::get('logo'):$toplevelgroup['vclogo']);
	$page['webimHost'] = topage(empty($toplevelgroup['vchosturl'])?Settings::get('hosturl'):$toplevelgroup['vchosturl']);
}
function setup_leavemessage($name, $email, $message, $groupid, $groupname, $info, $referrer, $canshowcaptcha)
{
	global $page;
	$page['formname'] = topage($name);
	$page['formemail'] = topage($email);
	$page['formmessage'] = $message ? topage($message) : "";
	$page['showcaptcha'] = Settings::get("enablecaptcha") == "1" && $canshowcaptcha ? "1" : "";
	$page['formgroupid'] = $groupid;
	$page['formgroupname'] = $groupname;
	$page['forminfo'] = topage($info);
	$page['referrer'] = urlencode(topage($referrer));
	if (Settings::get('enablegroups') == '1') {
		$groups = setup_groups_select($groupid, false);
		if ($groups) {
			$page['groups'] = $groups['select'];
			$page['group.descriptions'] = json_encode($groups['descriptions']);
			$page['default.department.description'] = $groups['defaultdescription'];
		}
	}
}
function setup_survey($name, $email, $groupid, $info, $referrer)
{
	global $page;
	$page['formname'] = topage($name);
	$page['formemail'] = topage($email);
	$page['formgroupid'] = $groupid;
	$page['forminfo'] = topage($info);
	$page['referrer'] = urlencode(topage($referrer));
	if (Settings::get('enablegroups') == '1' && Settings::get('surveyaskgroup') == '1') {
		$groups = setup_groups_select($groupid, true);
		if ($groups) {
			$page['groups'] = $groups['select'];
			$page['group.descriptions'] = json_encode($groups['descriptions']);
			$page['default.department.description'] = $groups['defaultdescription'];
		}
	}
	$page['showemail'] = Settings::get("surveyaskmail") == "1" ? "1" : "";
	$page['showmessage'] = Settings::get("surveyaskmessage") == "1" ? "1" : "";
	$page['showname'] = Settings::get('usercanchangename') == "1" ? "1" : "";
}
function setup_groups_select($groupid, $markoffline)
{
	$showgroups = ($groupid == '')?true:group_has_children($groupid);
	if (!$showgroups) {
		return false;
	}
	$allgroups = get_groups(false);
	if (empty($allgroups)) {
		return false;
	}
	$val = "";
	$selectedgroupid = $groupid;
	$groupdescriptions = array();
	foreach ($allgroups as $k) {
		$groupname = $k['vclocalname'];
		if ($k['inumofagents'] == 0 || ($groupid && $k['parent'] != $groupid && $k['groupid'] != $groupid )) {
			continue;
		}
		if ($k['ilastseen'] !== NULL && $k['ilastseen'] < Settings::get('online_timeout')) {
			if (!$selectedgroupid) {
				$selectedgroupid = $k['groupid']; // select first online group
			}
		} else {
			$groupname .= $markoffline?" (offline)":"";
		}
		$isselected = $k['groupid'] == $selectedgroupid;
		if ($isselected) {
			$defaultdescription = $k['vclocaldescription'];
		}
		$val .= "";
		$groupdescriptions[] = $k['vclocaldescription'];
	}
	return array(
		'select' => $val,
		'descriptions' => $groupdescriptions,
		'defaultdescription' => $defaultdescription
	);
}
function setup_chatview_for_user($thread, $level)
{
	global $page, $webimroot;
	$page = array();
	if (! empty($thread['groupid'])) {
		$group = group_by_id($thread['groupid']);
		$group = get_top_level_group($group);
	} else {
		$group = array();
	}
	$page['agent'] = false;
	$page['user'] = true;
	$page['canpost'] = true;
	$nameisset = getstring("chat.default.username") != $thread['userName'];
	$page['displ1'] = $nameisset ? "none" : "inline";
	$page['displ2'] = $nameisset ? "inline" : "none";
	$page['level'] = $level;
	$page['ct.chatThreadId'] = $thread['threadid'];
	$page['ct.token'] = $thread['ltoken'];
	$page['ct.user.name'] = htmlspecialchars(topage($thread['userName']));
	$page['canChangeName'] = Settings::get('usercanchangename') == "1";
	$page['chat.title'] = topage(empty($group['vcchattitle'])?Settings::get('chattitle'):$group['vcchattitle']);
	$page['chat.close.confirmation'] = getlocal('chat.close.confirmation');
	setup_logo($group);
	if (Settings::get('sendmessagekey') == 'enter') {
		$page['send_shortcut'] = "Enter";
		$page['ignorectrl'] = 1;
	} else {
		$page['send_shortcut'] = is_mac_opera() ? "⌘-Enter" : "Ctrl-Enter";
		$page['ignorectrl'] = 0;
	}
	$params = "thread=" . $thread['threadid'] . "&token=" . $thread['ltoken'];
	$page['mailLink'] = "$webimroot/client.php?" . $params . "&level=$level&act=mailthread";
	if (Settings::get('enablessl') == "1" && !is_secure_request()) {
		$page['sslLink'] = get_app_location(true, true) . "/client.php?" . $params . "&level=$level";
	}
	$page['isOpera95'] = is_agent_opera95();
	$page['neediframesrc'] = needsFramesrc();
	$page['frequency'] = Settings::get('updatefrequency_chat');
}
function setup_chatview_for_operator($thread, $operator)
{
	global $page, $webimroot, $company_logo_link, $webim_encoding, $company_name;
	$page = array();
	if (! is_null($thread['groupid'])) {
		$group = group_by_id($thread['groupid']);
		$group = get_top_level_group($group);
	} else {
		$group = array();
	}
	$page['agent'] = true;
	$page['user'] = false;
	$page['canpost'] = $thread['agentId'] == $operator['operatorid'];
	$page['ct.chatThreadId'] = $thread['threadid'];
	$page['ct.token'] = $thread['ltoken'];
	$page['ct.user.name'] = htmlspecialchars(topage(get_user_name($thread['userName'], $thread['remote'], $thread['userid'])));
	$page['chat.title'] = topage(empty($group['vcchattitle'])?Settings::get('chattitle'):$group['vcchattitle']);
	$page['chat.close.confirmation'] = getlocal('chat.close.confirmation');
	setup_logo($group);
	if (Settings::get('sendmessagekey') == 'enter') {
		$page['send_shortcut'] = "Enter";
		$page['ignorectrl'] = 1;
	} else {
		$page['send_shortcut'] = is_mac_opera() ? "⌘-Enter" : "Ctrl-Enter";
		$page['ignorectrl'] = 0;
	}
	if (Settings::get('enablessl') == "1" && !is_secure_request()) {
		$page['sslLink'] = get_app_location(true, true) . "/operator/agent.php?thread=" . $thread['threadid'] . "&token=" . $thread['ltoken'];
	}
	$page['isOpera95'] = is_agent_opera95();
	$page['neediframesrc'] = needsFramesrc();
	$page['historyParams'] = array("userid" => "" . $thread['userid']);
	$page['historyParamsLink'] = add_params($webimroot . "/operator/userhistory.php", $page['historyParams']);
	if (Settings::get('enabletracking')) {
	    $visitor = track_get_visitor_by_threadid($thread['threadid']);
	    $page['trackedParams'] = array("visitor" => "" . $visitor['visitorid']);
	    $page['trackedParamsLink'] = add_params($webimroot . "/operator/tracked.php", $page['trackedParams']);
	}
	$predefinedres = "";
	$canned_messages = load_canned_messages($thread['locale'], 0);
	if ($thread['groupid']) {
		$canned_messages = array_merge(
			load_canned_messages($thread['locale'], $thread['groupid']),
			$canned_messages
		);
	};
	foreach ($canned_messages as $answer) {
		$predefinedres .= "";
		$fullAnswers[] = myiconv($webim_encoding, getoutputenc(), $answer['vcvalue']);
	}
	$page['predefinedAnswers'] = $predefinedres;
	$page['fullPredefinedAnswers'] = json_encode($fullAnswers);
	$params = "thread=" . $thread['threadid'] . "&token=" . $thread['ltoken'];
	$page['redirectLink'] = "$webimroot/operator/agent.php?" . $params . "&act=redirect";
	$page['namePostfix'] = "";
	$page['frequency'] = Settings::get('updatefrequency_chat');
}
/**
 * Pings the chat thread. Updates 'lastpinguser' (or 'lastpingagent') to current timestamp. 
 * Sends system messages when operator or user was seen more than $connection_timeout seconds ago
 *
 * @global int $kind_for_agent
 * @global int $state_queue
 * @global int $state_loading
 * @global int $state_chatting
 * @global int $state_waiting
 * @global int $kind_conn
 * @global int $connection_timeout
 * @param array $thread Thread's array
 * @param boolean $isuser true for user and false for operator
 * @param boolean $istyping true if user (or agent) is typing
 */
function ping_thread($thread, $isuser, $istyping)
{
	global $kind_for_agent, $state_queue, $state_loading, $state_chatting, $state_waiting, $kind_conn, $connection_timeout;
	$db = Database::getInstance();
	$params = array(($isuser ? "lastpinguser" : "lastpingagent") => time(),
					($isuser ? "userTyping" : "agentTyping") => ($istyping ? "1" : "0"));
	$lastping = $thread[$isuser ? "lpagent" : "lpuser"];
	if ($thread['istate'] == $state_loading && $isuser) {
		$params['istate'] = $state_queue;
		commit_thread($thread['threadid'], $params);
		return;
	}
	if ($lastping > 0 && abs(time() - $lastping) > $connection_timeout) {
		$params[$isuser ? "lastpingagent" : "lastpinguser"] = "0";
		if (!$isuser) {
			$message_to_post = getstring_("chat.status.user.dead", $thread['locale']);
			post_message_($thread['threadid'], $kind_for_agent, $message_to_post, null, $lastping + $connection_timeout);
		} else if ($thread['istate'] == $state_chatting) {
			$message_to_post = getstring_("chat.status.operator.dead", $thread['locale']);
			post_message_($thread['threadid'], $kind_conn, $message_to_post, null, $lastping + $connection_timeout);
			$params['istate'] = $state_waiting;
			$params['nextagent'] = 0;
			commit_thread($thread['threadid'], $params);
			return;
		}
	}
	$clause = "";
	$values = array();
	foreach ($params as $k => $v) {
		if (strlen($clause) > 0) {
			$clause .= ", ";
		}
		$clause .= $k . "=?";
		$values[] = $v;
	}
	$values[] = $thread['threadid'];
	$db->query(
		"update {chatthread} set {$clause} where threadid = ?",
		$values
	);
}
function commit_thread($threadid, $params)
{
	$db = Database::getInstance();
	$query = "update {chatthread} t " .
		"set lrevision = ?, dtmmodified = ?";
	$values = array();
	$values[] = next_revision();
	$values[] = time();
	foreach ($params as $name => $value) {
		$query .= ", {$name} = ?" ;
		$values[] = $value;
	}
	$query .= " where threadid = ?";
	$values[] = $threadid;
	$db->query($query, $values);
}
function rename_user($thread, $newname)
{
	global $kind_events;
	commit_thread($thread['threadid'], array('userName' => $newname));
	if ($thread['userName'] != $newname) {
		post_message_($thread['threadid'], $kind_events,
					  getstring2_("chat.status.user.changedname", array($thread['userName'], $newname), $thread['locale']));
	}
}
function close_thread($thread, $isuser)
{
	global $state_closed, $kind_events;
	$db = Database::getInstance();
	list($message_count) = $db->query(
		"SELECT COUNT(*) FROM {chatmessage} WHERE {chatmessage}.threadid = ? AND ikind = 1",
		array($thread['threadid']),
		array(
			'return_rows' => Database::RETURN_ONE_ROW,
			'fetch_type' => Database::FETCH_NUM
		)
	);
	if ($thread['istate'] != $state_closed) {
		commit_thread(
			$thread['threadid'],
			array(
				'istate' => $state_closed,
				'messageCount' => $message_count
			)
		);
	}
	$message = $isuser ? getstring2_("chat.status.user.left", array($thread['userName']), $thread['locale'])
			: getstring2_("chat.status.operator.left", array($thread['agentName']), $thread['locale']);
	post_message_($thread['threadid'], $kind_events, $message);
}
function close_old_threads()
{
	global $state_closed, $state_left, $state_chatting;
	if (Settings::get('thread_lifetime') == 0) {
		return;
	}
	$db = Database::getInstance();
	$query = "update {chatthread} set lrevision = :next_revision, " .
		"dtmmodified = :now, istate = :state_closed " .
		"where istate <> :state_closed and istate <> :state_left " .
		"and ((lastpingagent <> 0 and lastpinguser <> 0 and " .
		"(ABS(:now - lastpinguser) > ".
		":thread_lifetime and " .
		"ABS(:now - lastpingagent) > ".
		":thread_lifetime)) or " .
		"lastpingagent = 0 and lastpinguser <> 0 and " .
		"ABS(:now - lastpinguser) > ".
		":thread_lifetime)";
	$db->query(
		$query,
		array(
			':next_revision' => next_revision(),
			':now' => time(),
			':state_closed' => $state_closed,
			':state_left' => $state_left,
			':thread_lifetime' => Settings::get('thread_lifetime')
		)
	);
}
function thread_by_id($id)
{
	$db = Database::getInstance();
	return $db->query(
		"select threadid,userName,agentName,agentId,lrevision,istate,ltoken,userTyping, " .
		"agentTyping,dtmmodified as modified, " .
		"dtmcreated as created, " .
		"dtmchatstarted as chatstarted,remote,referer,locale," .
		"lastpinguser as lpuser,lastpingagent as lpagent," .
		"nextagent,shownmessageid,userid, " .
		"userAgent,groupid from {chatthread} where threadid = :threadid",
		array(
			':threadid' => $id
		),
		array('return_rows' => Database::RETURN_ONE_ROW)
	);
}
function ban_for_addr($addr)
{
	$db = Database::getInstance();
	return $db->query(
		"select banid,comment from {chatban} " .
		"where dtmtill > :now AND address = :addr",
		array(
			':addr' => $addr,
			':now' => time()
		),
		array('return_rows' => Database::RETURN_ONE_ROW)
	);
}
function create_thread($groupid, $username, $remoteHost, $referer, $lang, $userid, $userbrowser, $initialState)
{
	$db = Database::getInstance();
	$query = "insert into {chatthread} (" .
			"userName, " .
			"userid, " .
			"ltoken, " .
			"remote, " .
			"referer, " .
			"lrevision, " .
			"locale, " .
			"userAgent, " .
			"dtmcreated, " .
			"dtmmodified, " .
			"istate" .
			($groupid ? ", groupid" : "") .
		") values (" .
			":username, " .
			":userid, " .
			":ltoken, " .
			":remote," .
			":referer, " .
			":lrevision, " .
			":locale, " .
			":useragent, " .
			":now, " .
			":now, " .
			":istate" .
			($groupid ? ", :groupid" : "") .
		")";
	$values = array(
		':username' => $username,
		':userid' => $userid,
		':ltoken' => next_token(),
		':remote' => $remoteHost,
		':referer' => $referer,
		':lrevision' => next_revision(),
		':locale' => $lang,
		':useragent' => $userbrowser,
		':now' => time(),
		':istate' => $initialState
	);
	if ($groupid) {
		$values[':groupid'] = $groupid;
	}
	$db->query($query, $values);
	$id = $db->insertedId();
	$newthread = thread_by_id($id);
	return $newthread;
}
function do_take_thread($threadid, $operatorId, $operatorName, $chatstart = false)
{
	global $state_chatting;
	$params = array("istate" => $state_chatting,
			"nextagent" => 0,
			"agentId" => $operatorId,
			"agentName" => $operatorName);
	if ($chatstart){
		$params['dtmchatstarted'] = time();
	}
	commit_thread($threadid, $params);
}
function reopen_thread($threadid)
{
	global $state_queue, $state_loading, $state_waiting, $state_chatting, $state_closed, $state_left, $kind_events;
	$thread = thread_by_id($threadid);
	if (!$thread)
		return FALSE;
	if (Settings::get('thread_lifetime') != 0 && abs($thread['lpuser'] - time()) > Settings::get('thread_lifetime') && abs($thread['lpagent'] - time()) > Settings::get('thread_lifetime')) {
		return FALSE;
	}
	if ($thread['istate'] == $state_closed || $thread['istate'] == $state_left)
		return FALSE;
	if ($thread['istate'] != $state_chatting && $thread['istate'] != $state_queue && $thread['istate'] != $state_loading) {
		commit_thread(
			$threadid,
			array("istate" => $state_waiting, "nextagent" => 0)
		);
	}
	post_message_($thread['threadid'], $kind_events, getstring_("chat.status.user.reopenedthread", $thread['locale']));
	return $thread;
}
function take_thread($thread, $operator)
{
	global $state_queue, $state_loading, $state_waiting, $state_chatting, $kind_events, $kind_avatar, $home_locale;
	$state = $thread['istate'];
	$threadid = $thread['threadid'];
	$message_to_post = "";
	$chatstart = $thread['chatstarted'] == 0;
	$operatorName = ($thread['locale'] == $home_locale) ? $operator['vclocalename'] : $operator['vccommonname'];
	if ($state == $state_queue || $state == $state_waiting || $state == $state_loading) {
		do_take_thread($threadid, $operator['operatorid'], $operatorName, $chatstart);
		if ($state == $state_waiting) {
			if ($operatorName != $thread['agentName']) {
				$message_to_post = getstring2_("chat.status.operator.changed", array($operatorName, $thread['agentName']), $thread['locale']);
			} else {
				$message_to_post = getstring2_("chat.status.operator.returned", array($operatorName), $thread['locale']);
			}
		} else {
			$message_to_post = getstring2_("chat.status.operator.joined", array($operatorName), $thread['locale']);
		}
	} else if ($state == $state_chatting) {
		if ($operator['operatorid'] != $thread['agentId']) {
			do_take_thread($threadid, $operator['operatorid'], $operatorName, $chatstart);
			$message_to_post = getstring2_("chat.status.operator.changed", array($operatorName, $thread['agentName']), $thread['locale']);
		}
	} else {
		return false;
	}
	if ($message_to_post) {
		post_message($threadid, $kind_events, $message_to_post);
		post_message($threadid, $kind_avatar, $operator['vcavatar'] ? $operator['vcavatar'] : "");
	}
	return true;
}
function check_for_reassign($thread, $operator)
{
	global $state_waiting, $home_locale, $kind_events, $kind_avatar;
	$operatorName = ($thread['locale'] == $home_locale) ? $operator['vclocalename'] : $operator['vccommonname'];
	if ($thread['istate'] == $state_waiting &&
		($thread['nextagent'] == $operator['operatorid']
		 || $thread['agentId'] == $operator['operatorid'])) {
		do_take_thread($thread['threadid'], $operator['operatorid'], $operatorName);
		if ($operatorName != $thread['agentName']) {
			$message_to_post = getstring2_("chat.status.operator.changed", array($operatorName, $thread['agentName']), $thread['locale']);
		} else {
			$message_to_post = getstring2_("chat.status.operator.returned", array($operatorName), $thread['locale']);
		}
		post_message($thread['threadid'], $kind_events, $message_to_post);
		post_message($thread['threadid'], $kind_avatar, $operator['vcavatar'] ? $operator['vcavatar'] : "");
	}
}
function check_connections_from_remote($remote)
{
	global $state_closed, $state_left;
	if (Settings::get('max_connections_from_one_host') == 0) {
		return true;
	}
	$db = Database::getInstance();
	$result = $db->query(
		"select count(*) as opened from {chatthread} " .
		"where remote = ? AND istate <> ? AND istate <> ?",
		array($remote, $state_closed, $state_left),
		array('return_rows' => Database::RETURN_ONE_ROW)
	);
	if ($result && isset($result['opened'])) {
		return $result['opened'] < Settings::get('max_connections_from_one_host');
	}
	return true;
}
function visitor_from_request()
{
	global $namecookie, $webim_encoding, $usercookie;
	$defaultName = getstring("chat.default.username");
	$userName = $defaultName;
	if (isset($_COOKIE[$namecookie])) {
		$data = base64_decode(strtr($_COOKIE[$namecookie], '-_,', '+/='));
		if (strlen($data) > 0) {
			$userName = myiconv("utf-8", $webim_encoding, $data);
		}
	}
	if ($userName == $defaultName) {
		$userName = getgetparam('name', $userName);
	}
	if (isset($_COOKIE[$usercookie])) {
		$userId = $_COOKIE[$usercookie];
	} else {
		$userId = get_user_id();
		setcookie($usercookie, $userId, time() + 60 * 60 * 24 * 365);
	}
	return array('id' => $userId, 'name' => $userName);
}
function get_remote_host()
{
	$extAddr = $_SERVER['REMOTE_ADDR'];
	if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) &&
		$_SERVER['HTTP_X_FORWARDED_FOR'] != $_SERVER['REMOTE_ADDR']) {
		$extAddr = $_SERVER['REMOTE_ADDR'] . ' (' . $_SERVER['HTTP_X_FORWARDED_FOR'] . ')';
	}
	return isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : $extAddr;
}
?>