@@ -0,0 +1,72 @@
<?php
/*********************************************************************
attachment.php
Attachments interface for clients.
Clients should never see the dir paths.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: attachment.php,v 1.1.2.2 2010/04/15 14:33:55 carlos.delfino Exp $
**********************************************************************/
require('secure.inc.php');
//TODO: alert admin on any error on this file.
if(!$thisclient || !$thisclient->isClient() || !$_GET['id'] || !$_GET['ref']) die($trl->translate("TEXT_ACCESS_DENIED"));

$sql='SELECT attach_id,ref_id,ticket.ticket_id,ticketID,ticket.created,dept_id,file_name,file_key,email FROM '.TICKET_ATTACHMENT_TABLE.
' LEFT JOIN '.TICKET_TABLE.' ticket USING(ticket_id) '.
' WHERE attach_id='.db_input($_GET['id']);
//valid ID??
if(!($resp=db_query($sql)) || !db_num_rows($resp)) die('Invalid/unknown file');
list($id,$refid,$tid,$extid,$date,$deptID,$filename,$key,$email)=db_fetch_row($resp);

//Still paranoid...:)...check the secret session based hash and email
$hash=MD5($tid*$refid.session_id());
if(!$_GET['ref'] || strcmp($hash,$_GET['ref']) || strcasecmp($thisclient->getEmail(),$email)) die('Access denied: Kwaheri');


//see if the file actually exits.
$month=date('my',strtotime("$date"));
$file=rtrim($cfg->getUploadDir(),'/')."/$month/$key".'_'.$filename;
if(!file_exists($file))
$file=rtrim($cfg->getUploadDir(),'/')."/$key".'_'.$filename;

if(!file_exists($file)) die('Invalid Attachment');

$extension =substr($filename,-3);
switch(strtolower($extension))
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Type: $ctype");
$user_agent = strtolower ($_SERVER["HTTP_USER_AGENT"]);
if ((is_integer(strpos($user_agent,"msie"))) && (is_integer(strpos($user_agent,"win"))))
{
header( "Content-Disposition: filename=".basename($filename).";" );
} else {
header( "Content-Disposition: attachment; filename=".basename($filename).";" );
}
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($file));
readfile($file);
exit();
?>
@@ -0,0 +1,22 @@
<?php
/*********************************************************************
captcha.php
Simply returns captcha image.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: captcha.php,v 1.1.2.2 2010/04/15 14:34:05 carlos.delfino Exp $
**********************************************************************/
require_once('main.inc.php');
require(INCLUDE_DIR.'class.captcha.php');

$captcha = new Captcha(5,12,ROOT_DIR.'images/captcha/');
echo $captcha->getImage();
?>
@@ -0,0 +1,60 @@
<?php
/*********************************************************************
client.inc.php
File included on every client page
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: $
**********************************************************************/
if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('kwaheri rafiki!');

if(!file_exists('main.inc.php')) die('Fatal Error.');

require_once('main.inc.php');

if(!defined('INCLUDE_DIR')) die('Fatal error');

/*Some more include defines specific to client only */
define('CLIENTINC_DIR',INCLUDE_DIR.'client/');
define('OSTCLIENTINC',TRUE);

//Check the status of the HelpDesk.
if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline()) {
include('./offline.php');
exit;
}

//Forced upgrade? Version mismatch.
if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) {
die('System is offline for an upgrade.');
exit;
}

/* include what is needed on client stuff */
require_once(INCLUDE_DIR.'class.client.php');
require_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.dept.php');

//clear some vars
$errors=array();
$msg='';
$thisclient=null;
//Make sure the user is valid..before doing anything else.
if($_SESSION['_client']['userID'] && $_SESSION['_client']['key'])
$thisclient = new ClientSession($_SESSION['_client']['userID'],$_SESSION['_client']['key']);

//print_r($_SESSION);
//is the user logged in?
if($thisclient && $thisclient->getId() && $thisclient->isValid()){
$thisclient->refreshSession();
}

?>
BIN +49 Bytes images/bg.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +3.65 KB images/button.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +127 Bytes images/cal.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +921 Bytes images/captcha/ripple.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +8.31 KB images/fibres.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +221 Bytes images/home.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +248 Bytes images/icons/refresh.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +274 Bytes images/icons/thread.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +210 Bytes images/icons/ticket.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +7.25 KB images/lipsum.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +5.44 KB images/logo.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +11 KB images/logo2.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +338 Bytes images/logout.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +126 Bytes images/my_tickets.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +120 Bytes images/new_ticket.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +2.79 KB images/poweredby.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +16.9 KB images/rainbow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +929 Bytes images/refresh_btn.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +123 Bytes images/ticket_status.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +19.6 KB images/verticalbar.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +578 Bytes images/view_open_btn.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,2 @@
ost-config.primeiro.teste.php
ost-config.php
@@ -0,0 +1 @@
Deny from all
@@ -0,0 +1,40 @@
<?php
/*********************************************************************
ajax.kbase.php
AJAX interface for knowledge base related...allowed methods.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: ajax.kbase.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

if(!defined('OSTAJAXINC') || !defined('INCLUDE_DIR')) die('!');

class KbaseAjaxAPI{

function cannedResp($params) {

$sql='SELECT answer FROM '.KB_PREMADE_TABLE.' WHERE isenabled=1 AND premade_id='.db_input($params['id']);
if(($res=db_query($sql)) && db_num_rows($res))
list($response)=db_fetch_row($res);

if($response && $params['tid'] && strpos($response,'%')!==false) {
include_once(INCLUDE_DIR.'class.ticket.php');

$ticket = new Ticket($params['tid']);
if($ticket && $ticket->getId()){
$response=$ticket->replaceTemplateVars($response);
}
}

return $response;
}
}
?>
@@ -0,0 +1,141 @@
<?php
/*********************************************************************
ajax.tickets.php
AJAX interface for tickets
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: ajax.tickets.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

if(!defined('OSTAJAXINC') || !defined('INCLUDE_DIR')) die('403');

include_once(INCLUDE_DIR.'class.ticket.php');

class TicketsAjaxAPI{

function searchbyemail($params) {

$input = db_input(strtolower($params['input']),false);
$len = strlen($input);
$limit = isset($params['limit']) ? (int) $params['limit']:25;
$items=array();
$sql='SELECT DISTINCT email,name FROM '.TICKET_TABLE.' WHERE email LIKE \''.$input.'%\' ORDER BY created LIMIT '.$limit;
$resp=db_query($sql);
if($resp && db_num_rows($resp)){
while(list($email,$name)=db_fetch_row($resp)) {
$name=(strpos($name,'@')===false)?$name:'';
$items[] ='{"id": "'.$email.'", "value": "'.$email.'", "info": "'.$name.'"}';
}
}
$result= '{"results": ['.implode(", ", $items).']}';
return $result;
}

function search($params) {

$input = db_input(strtolower($params['input']),false);
$len = strlen($input);
$limit = isset($params['limit']) ? (int) $params['limit']:25;
$items=array();
$ticketid=false;
if(is_numeric($input)) {
$WHERE=' WHERE ticketID LIKE \''.$input.'%\'';
$ticketid=true;
}else{
$WHERE=' WHERE email LIKE \''.$input.'%\'';
}
$sql='SELECT DISTINCT ticketID,email FROM '.TICKET_TABLE.' '.$WHERE.' ORDER BY created LIMIT '.$limit;
$resp=db_query($sql);
if($resp && db_num_rows($resp)){
while(list($id,$email)=db_fetch_row($resp)) {
$info=($ticketid)?$email:$id;
$id=($ticketid)?$id:$email;
$items[] ='{"id": "'.$id.'", "value": "'.$id.'", "info": "'.$info.'"}';
}
}
$result= '{"results": ['.implode(", ", $items).']}';
return $result;
}

function acquireLock($params) {
global $cfg,$thisuser;

if(!$params['tid'] or !is_numeric($params['tid']))
return 0;

$ticket = new Ticket($params['tid']);

if(!$ticket || (!$thisuser->canAccessDept($ticket->getDeptId()) && ($ticket->isAssigned() && $thisuser->getId()!=$ticket->getStaffId())))
return '{"id":0, "retry":false}';

//is the ticket already locked?
if($ticket->isLocked() && ($lock=$ticket->getLock()) && !$lock->isExpired()) {
/*Note: Ticket->acquireLock does the same logic...but we need it here since we need to know who owns the lock up front*/

//Ticket is locked by someone else.??
if($lock->getStaffId()!=$thisuser->getId())
return '{"id":0, "retry":false}';

//Ticket already locked by staff...try renewing it.
$lock->renew(); //New clock baby!

return '{"id":'.$lock->getId().', "time":'.$lock->getTime().'}';
}

//Ticket is not locked or the lock is expired...try locking it...
if(($lock=$ticket->acquireLock())) //Set the lock.
return '{"id":'.$lock->getId().', "time":'.$lock->getTime().'}';

//unable to obtain the lock..for some really weired reason!
return '{"id":0, "retry":true}'; //Client should watch for possible loop on retries. Max attempts?
}

function renewLock($params) {
global $thisuser;

if(!$params['id'] or !is_numeric($params['id']))
return '{"id":0, "retry":true}';

$lock= new TicketLock($params['id']);

if(!$lock->load() || !$lock->getStaffId() || $lock->isExpired()) //Said lock doesn't exist or is is expired
return TicketsAjaxAPI::acquireLock($params); //acquire the lock

if($lock->getStaffId()!=$thisuser->getId()) //user doesn't own the lock anymore??? sorry...try to next time.
return '{"id":0, "retry":false}'; //Give up...

//Renew the lock.
$lock->renew(); //Failure here is not an issue since the lock is not expired yet..

return '{"id":'.$lock->getId().', "time":'.$lock->getTime().'}';
}

function releaseLock($params) {
global $thisuser;

if($params['id'] && is_numeric($params['id'])){ //Lock Id provided!

$lock= new TicketLock($params['id']);
//Already gone?
if(!$lock->load() || !$lock->getStaffId() || $lock->isExpired()) //Said lock doesn't exist or is is expired
return 1;

//make sure the user actually owns the lock before releasing it.
return ($lock->getStaffId()==$thisuser->getId() && $lock->release())?1:0;

}elseif($params['tid']){ //release all the locks the user owns on the ticket.
return TicketLock::removeStaffLocks($thisuser->getId(),$params['tid'])?1:0;
}

return 0;
}
}
?>
@@ -0,0 +1,89 @@
<?php
/*********************************************************************
class.api.php
Api related functions...
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.api.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/
class Api {


function add($ip,&$errors) {
global $cfg;

$passphrase=$cfg->getAPIPassphrase();

if(!$passphrase)
$errors['err']='API passphrase missing.';

if(!$ip || !Validator::is_ip($ip))
$errors['ip']='Valid IP required';
elseif(Api::getKey($ip))
$errors['ip']='API key for the IP already exists';

$id=0;
if(!$errors) {
$sql='INSERT INTO '.API_KEY_TABLE.' SET created=NOW(), updated=NOW(), isactive=1'.
',ipaddr='.db_input($ip).
',apikey='.db_input(strtoupper(md5($ip.md5($passphrase)))); //Security of the apikey is not as critical at the moment

if(db_query($sql))
$id=db_insert_id();

}

return $id;
}

function setPassphrase($phrase,&$errors) {
global $cfg;

if(!$phrase)
$errors['phrase']='Required';
elseif(str_word_count($_POST['phrase'])<3)
$errors['phrase']='Must be at least 3 words long.';
elseif(!strcmp($cfg->getAPIPassphrase(),$phrase))
$errors['phrase']='Already set';
else{
$sql='UPDATE '.CONFIG_TABLE.' SET updated=NOW(), api_passphrase='.db_input($phrase).
' WHERE id='.db_input($cfg->getId());
if(db_query($sql) && db_affected_rows()){
$cfg->reload();
return true;
}

}

return false;
}


function getKey($ip) {

$key=null;
$resp=db_query('SELECT apikey FROM '.API_KEY_TABLE.' WHERE ipaddr='.db_input($ip));
if($resp && db_num_rows($resp))
list($key)=db_fetch_row($resp);

return $key;
}


function validate($key,$ip) {

$resp=db_query('SELECT id FROM '.API_KEY_TABLE.' WHERE ipaddr='.db_input($ip).' AND apikey='.db_input($key));
return ($resp && db_num_rows($resp))?true:false;

}

}
?>
@@ -0,0 +1,33 @@
<?php
/*********************************************************************
class.banlist.php
Banned emails handle.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.banlist.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

class Banlist {

function add($email,$submitter='') {
$sql='INSERT IGNORE INTO '.BANLIST_TABLE.' SET added=NOW(),email='.db_input($email).',submitter='.db_input($submitter);
return (db_query($sql) && ($id=db_insert_id()))?$id:0;
}

function remove($email) {
$sql='DELETE FROM '.BANLIST_TABLE.' WHERE email='.db_input($email);
return (db_query($sql) && db_affected_rows())?true:false;
}

function isbanned($email) {
return db_num_rows(db_query('SELECT id FROM '.BANLIST_TABLE.' WHERE email='.db_input($email)))?true:false;
}
}
@@ -0,0 +1,55 @@
<?php
/*********************************************************************
class.captcha.php
Very basic captcha class.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: $
**********************************************************************/
class Captcha {
var $hash;
var $bgimages=array('cottoncandy.png','grass.png','ripple.png','silk.png','whirlpool.png',
'bubbles.png','crackle.png','lines.png','sand.png','snakeskin.png');
var $font = 10;
function Captcha($len=6,$font=7,$bg=''){

$this->hash = strtoupper(substr(md5(rand(0, 9999)),rand(0, 24),$len));
$this->font = $font;

if($bg && !is_dir($bg)){ //bg file provided?
$this->bgimg=$bg;
}else{ //assume dir provided or defaults to local.
$this->bgimg=rtrim($bg,'/').'/'.$this->bgimages[array_rand($this->bgimages, 1)];
}
}

function getImage(){

if(!extension_loaded('gd') || !function_exists('gd_info')) //GD ext required.
return;

$_SESSION['captcha'] =''; //Clear

list($w,$h) = getimagesize($this->bgimg);
$x = round(($w/2)-((strlen($this->hash)*imagefontwidth($this->font))/2), 1);
$y = round(($h/2)-(imagefontheight($this->font)/2));

$img= imagecreatefrompng($this->bgimg);
imagestring($img,$this->font, $x, $y,$this->hash,imagecolorallocate($img,0, 0, 0));

Header ("(captcha-content-type:) image/png");
imagepng($img);
imagedestroy($img);
$_SESSION['captcha'] = md5($this->hash);
}
}

?>
@@ -0,0 +1,88 @@
<?php
/*********************************************************************
class.client.php
Handles everything about client
The class will undergo major changes one client's accounts are used.
At the moment we will play off the email + ticket ID authentication.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.client.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

class Client {


var $id;
var $fullname;
var $username;
var $passwd;
var $email;


var $udata;
var $ticket_id;
var $ticketID;

function Client($email,$id){
$this->id =0;
return ($this->lookup($id,$email));
}

function isClient(){
return TRUE;
}

function lookup($id,$email=''){
$sql='SELECT ticket_id,ticketID,name,email FROM '.TICKET_TABLE.' WHERE ticketID='.db_input($id);
if($email){ //don't validate...using whatever is entered.
$sql.=' AND email='.db_input($email);
}
$res=db_query($sql);
if(!$res || !db_num_rows($res))
return NULL;

/* Faking most of the stuff for now till we start using accounts.*/
$row=db_fetch_array($res);
$this->udata=$row;
$this->id = $row['ticketID']; //placeholder
$this->ticket_id = $row['ticket_id'];
$this->ticketID = $row['ticketID'];
$this->fullname = ucfirst($row['name']);
$this->username = $row['email'];
$this->email = $row['email'];

return($this->id);
}


function getId(){
return $this->id;
}

function getEmail(){
return($this->email);
}

function getUserName(){
return($this->username);
}

function getName(){
return($this->fullname);
}

function getTicketID() {
return $this->ticketID;
}
}

?>

Large diffs are not rendered by default.

@@ -0,0 +1,44 @@
<?php
/*********************************************************************
class.cron.php
Nothing special...just a central location for all cron calls.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
TODO: The plan is to make cron jobs db based.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.cron.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/
//TODO: Make it DB based!
class Cron {

function MailFetcher() {
require_once(INCLUDE_DIR.'class.mailfetch.php');
MailFetcher::fetchMail(); //Fetch mail..frequency is limited by email account setting.
}

function TicketMonitor() {
require_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.lock.php');
Ticket::checkOverdue(); //Make stale tickets overdue
TicketLock::cleanup(); //Remove expired locks
}

function PurgeLogs() {
Sys::purgeLogs();
}

function run(){ //called by outside cron NOT autocron
Cron::MailFetcher();
Cron::TicketMonitor();
cron::PurgeLogs();
}
}
?>
@@ -0,0 +1,265 @@
<?php
/*********************************************************************
class.dept.php
Department class
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.dept.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/
class Dept {
var $id;
var $name;
var $signature;

var $tplId;

var $emailId;
var $email;

var $autorespEmail;

var $managerId;
var $manager;

var $row;

function Dept($id=0){
$this->id=0;
if($id && ($info=$this->getInfoById($id))){
$this->row=$info;
$this->id=$info['dept_id'];
$this->tplId=$info['tpl_id'];
$this->emailId=$info['email_id'];
$this->managerId=$info['manager_id'];
$this->deptname=$info['dept_name'];
$this->signature=$info['dept_signature'];
$this->getEmail(); //Auto load email struct.
}
}

function getId(){
return $this->id;
}

function getName(){
return $this->deptname;
}


function getEmailId(){
return $this->emailId;
}

function getEmail(){

if(!$this->email && $this->emailId)
$this->email= new Email($this->emailId);

return $this->email;
}

function getTemplateId() {
return $this->tplId;
}

function getAutoRespEmail() {

if(!$this->autorespEmail && $this->row['autoresp_email_id'])
$this->autorespEmail= new Email($this->row['autoresp_email_id']);
else // Defualt to dept email if autoresp is not specified.
$this->autorespEmail= $this->getEmail();

return $this->autorespEmail;
}

function getEmailAddress() {
return $this->email?$this->email->getAddress():null;
}

function getSignature() {

return $this->signature;
}

function canAppendSignature() {
return ($this->signature && $this->row['can_append_signature'])?true:false;
}

function getManagerId(){
return $this->managerId;
}

function getManager(){

if(!$this->manager && $this->managerId)
$this->manager= new Staff($this->managerId);

return $this->manager;
}

function isPublic() {
return $this->row['ispublic']?true:false;
}

function autoRespONNewTicket() {
return $this->row['ticket_auto_response']?true:false;
}

function autoRespONNewMessage() {
return $this->row['message_auto_response']?true:false;
}

function noreplyAutoResp(){
return $this->row['noreply_autoresp']?true:false;
}

function getInfo() {
return $this->row;
}

function update($vars,&$errors) {
if($this->save($this->getId(),$vars,$errors)){
return true;
}
return false;
}



function getInfoById($id) {
$sql='SELECT * FROM '.DEPT_TABLE.' WHERE dept_id='.db_input($id);
if(($res=db_query($sql)) && db_num_rows($res))
return db_fetch_array($res);

return null;
}


function getIdByName($name) {
$id=0;
$sql ='SELECT dept_id FROM '.DEPT_TABLE.' WHERE dept_name='.db_input($name);
if(($res=db_query($sql)) && db_num_rows($res))
list($id)=db_fetch_row($res);

return $id;
}

function getIdByEmail($email) {
$id=0;
$sql ='SELECT dept_id FROM '.DEPT_TABLE.' WHERE dept_email='.db_input($email);
if(($res=db_query($sql)) && db_num_rows($res))
list($id)=db_fetch_row($res);

return $id;
}

function getNameById($id) {
$sql ='SELECT dept_name FROM '.DEPT_TABLE.' WHERE dept_id='.db_input($id);
if(($res=db_query($sql)) && db_num_rows($res))
list($name)=db_fetch_row($res);
return $name;
}

function getDefaultDeptName() {
global $cfg;
return Dept::getNameById($cfg->getDefaultDeptId());
}


function create($vars,&$errors) {
return Dept::save(0,$vars,$errors);
}


function delete($id) {
global $cfg;
if($id==$cfg->getDefaultDeptId())
return 0;

$sql='DELETE FROM '.DEPT_TABLE.' WHERE dept_id='.db_input($id);
if(db_query($sql) && ($num=db_affected_rows())){
// DO SOME HOUSE CLEANING
//TODO: Do insert select internal note...
//Move tickets to default Dept.
db_query('UPDATE '.TICKET_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
//Move Dept members
//This should never happen..since delete should be issued only to empty Depts...but check it anyways
db_query('UPDATE '.STAFF_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
//make help topic using the dept default to default-dept.
db_query('UPDATE '.TOPIC_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
return $num;
}
return 0;

}

function save($id,$vars,&$errors) {
global $cfg;

if($id && $id!=$_POST['dept_id'])
$errors['err']='Missing or invalid Dept ID';

if(!$_POST['email_id'] || !is_numeric($_POST['email_id']))
$errors['email_id']='Dept email required';

if(!is_numeric($_POST['tpl_id']))
$errors['tpl_id']='Template required';

if(!$_POST['dept_name']) {
$errors['dept_name']='Dept name required';
}elseif(strlen($_POST['dept_name'])<4) {
$errors['dept_name']='Dept name must be at least 4 chars.';
}else{
$sql='SELECT dept_id FROM '.DEPT_TABLE.' WHERE dept_name='.db_input($_POST['dept_name']);
if($id)
$sql.=' AND dept_id!='.db_input($id);

if(db_num_rows(db_query($sql)))
$errors['dept_name']='Department already exist';
}

if($_POST['ispublic'] && !$_POST['dept_signature'])
$errors['dept_signature']='Signature required';

if(!$_POST['ispublic'] && ($_POST['dept_id']==$cfg->getDefaultDeptId()))
$errors['ispublic']='Default department can not be private';

if(!$errors){

$sql=' SET updated=NOW() '.
',ispublic='.db_input($_POST['ispublic']).
',email_id='.db_input($_POST['email_id']).
',tpl_id='.db_input($_POST['tpl_id']).
',autoresp_email_id='.db_input($_POST['autoresp_email_id']).
',manager_id='.db_input($_POST['manager_id']?$_POST['manager_id']:0).
',dept_name='.db_input(Format::striptags($_POST['dept_name'])).
',dept_signature='.db_input(Format::striptags($_POST['dept_signature'])).
',ticket_auto_response='.db_input($_POST['ticket_auto_response']).
',message_auto_response='.db_input($_POST['message_auto_response']).
',can_append_signature='.db_input(isset($_POST['can_append_signature'])?1:0);

if($id) {
$sql='UPDATE '.DEPT_TABLE.' '.$sql.' WHERE dept_id='.db_input($id);
if(!db_query($sql) || !db_affected_rows())
$errors['err']='Unable to update '.Format::input($_POST['dept_name']).' Dept. Error occured';
}else{
$sql='INSERT INTO '.DEPT_TABLE.' '.$sql.',created=NOW()';
if(db_query($sql) && ($deptID=db_insert_id()))
return $deptID;

$errors['err']='Unable to create department. Internal error';
}
}

return $errors?false:true;
}
}
?>

Large diffs are not rendered by default.

@@ -0,0 +1,166 @@
<?php
/*********************************************************************
class.format.php
Collection of helper function used for formatting
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.format.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/


class Format {


function file_size($bytes) {

if($bytes<1024)
return $bytes.' bytes';
if($bytes <102400)
return round(($bytes/1024),1).' kb';

return round(($bytes/1024000),1).' mb';
}

function file_name($filename) {

$search = array('/ß/','/ä/','/Ä/','/ö/','/Ö/','/ü/','/Ü/','([^[:alnum:]._])');
$replace = array('ss','ae','Ae','oe','Oe','ue','Ue','_');
return preg_replace($search,$replace,$filename);
}

function phone($phone) {

$stripped= preg_replace("/[^0-9]/", "", $phone);
if(strlen($stripped) == 7)
return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2",$stripped);
elseif(strlen($stripped) == 10)
return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "($1) $2-$3",$stripped);
else
return $phone;
}

function truncate($string,$len,$hard=false) {

if(!$len || $len>strlen($string))
return $string;

$string = substr($string,0,$len);

return $hard?$string:(substr($string,0,strrpos($string,' ')).' ...');
}

function strip_slashes($var){
return is_array($var)?array_map(array('Format','strip_slashes'),$var):stripslashes($var);
}

function htmlchars($var) {
return is_array($var)?array_map(array('Format','htmlchars'),$var):htmlspecialchars($var,ENT_QUOTES);
}


//Same as htmlchars above but with ability to add extra checks...etc.
function input($var) {

/*: Moved to main.inc.php
if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
$var=Format::strip_slashes($var);
*/
return Format::htmlchars($var);
}

//Format text for display..
function display($text) {
global $cfg;

$text=Format::htmlchars($text); //take care of html special chars
if($cfg && $cfg->clickableURLS() && $text)
$text=Format::clickableurls($text);

//Wrap long words...
$text =preg_replace_callback('/\w{75,}/',create_function('$matches','return wordwrap($matches[0],70,"\n",true);'),$text);

return nl2br($text);
}

function striptags($string) {
return strip_tags(html_entity_decode($string)); //strip all tags ...no mercy!
}

//make urls clickable. Mainly for display
function clickableurls($text) {

//Not perfect but it works - please help improve it.
$text=preg_replace('/(((f|ht){1}tp(s?):\/\/)[-a-zA-Z0-9@:%_\+.~#?&;\/\/=]+)/','<a href="\\1" target="_blank">\\1</a>', $text);
$text=preg_replace("/(^|[ \\n\\r\\t])(www\.([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)(\/[^\/ \\n\\r]*)*)/",
'\\1<a href="http://\\2" target="_blank">\\2</a>', $text);
$text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/",'\\1<a href="mailto:\\2" target="_blank">\\2</a>', $text);

return $text;
}

function stripEmptyLines ( $string) {
//return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $string);
//return preg_replace('/\s\s+/',"\n",$string); //Too strict??
return preg_replace("/\n{3,}/", "\n\n", $string);
}


function linebreaks($string) {
return urldecode(ereg_replace("%0D", " ", urlencode($string)));
}

/* elapsed time */
function elapsedTime($sec){

if(!$sec || !is_numeric($sec)) return "";

$days = floor($sec / 86400);
$hrs = floor(bcmod($sec,86400)/3600);
$mins = round(bcmod(bcmod($sec,86400),3600)/60);
if($days > 0) $tstring = $days . 'd,';
if($hrs > 0) $tstring = $tstring . $hrs . 'h,';
$tstring =$tstring . $mins . 'm';

return $tstring;
}

/* Dates helpers...most of this crap will change once we move to PHP 5*/
function db_date($time) {
global $cfg;
return Format::userdate($cfg->getDateFormat(),Misc::db2gmtime($time));
}

function db_datetime($time) {
global $cfg;
return Format::userdate($cfg->getDateTimeFormat(),Misc::db2gmtime($time));
}

function db_daydatetime($time) {
global $cfg;
return Format::userdate($cfg->getDayDateTimeFormat(),Misc::db2gmtime($time));
}

function userdate($format,$gmtime) {
return Format::date($format,$gmtime,$_SESSION['TZ_OFFSET'],$_SESSION['daylight']);
}

function date($format,$gmtimestamp,$offset=0,$daylight=false){
if(!$gmtimestamp || !is_numeric($gmtimestamp)) return "";

$offset+=$daylight?date('I',$gmtimestamp):0; //Daylight savings crap.
return date($format,($gmtimestamp+($offset*3600)));
}




}
?>
@@ -0,0 +1,78 @@
<?php
/*********************************************************************
class.group.php
Groups
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: $
**********************************************************************/

class Group {

function update($id,$vars,&$errors) {
if($id && Group::save($id,$vars,$errors)){
return true;
}
return false;
}

function create($vars,&$errors) {
return Group::save(0,$vars,$errors);
}

function save($id,$vars,&$errors) {

if($id && !$vars['group_id'])
$errors['err']='Missing or invalid group ID';

if(!$vars['group_name']) {
$errors['group_name']='Group name required';
}elseif(strlen($vars['group_name'])<5) {
$errors['group_name']='Group name must be at least 5 chars.';
}else {
$sql='SELECT group_id FROM '.GROUP_TABLE.' WHERE group_name='.db_input($vars['group_name']);
if($id)
$sql.=' AND group_id!='.db_input($id);

if(db_num_rows(db_query($sql)))
$errors['group_name']='Group name already exists';
}

if(!$errors){

$sql=' SET updated=NOW(), group_name='.db_input(Format::striptags($vars['group_name'])).
', group_enabled='.db_input($vars['group_enabled']).
', dept_access='.db_input($vars['depts']?implode(',',$vars['depts']):'').
', can_create_tickets='.db_input($vars['can_create_tickets']).
', can_delete_tickets='.db_input($vars['can_delete_tickets']).
', can_edit_tickets='.db_input($vars['can_edit_tickets']).
', can_transfer_tickets='.db_input($vars['can_transfer_tickets']).
', can_close_tickets='.db_input($vars['can_close_tickets']).
', can_ban_emails='.db_input($vars['can_ban_emails']).
', can_manage_kb='.db_input($vars['can_manage_kb']);
//echo $sql;
if($id) {
$res=db_query('UPDATE '.GROUP_TABLE.' '.$sql.' WHERE group_id='.db_input($id));
if(!$res || !db_affected_rows())
$errors['err']='Internal error occured';
}else{
$res=db_query('INSERT INTO '.GROUP_TABLE.' '.$sql.',created=NOW()');
if($res && ($gID=db_insert_id()))
return $gID;

$errors['err']='Unable to create the group. Internal error';
}
}

return $errors?false:true;
}
}
?>
@@ -0,0 +1,52 @@
<?php
/*********************************************************************
class.http.php
Http helper.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.http.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/
class Http {

function header_code_verbose($code) {
switch($code):
case 200: return '200 OK';
case 204: return '204 NoContent';
case 401: return '401 Unauthorized';
case 403: return '403 Forbidden';
case 405: return '405 Method Not Allowed';
case 416: return '416 Requested Range Not Satisfiable';
default: return '500 Internal Server Error';
endswitch;
}

function response($code,$content,$contentType='text/html',$charset='UTF-8') {

header('HTTP/1.1 '.Http::header_code_verbose($code));
header('Status: '.Http::header_code_verbose($code)."\r\n");
header("Connection: Close\r\n");
header("Content-Type: $contentType; charset=$charset\r\n");
header('Content-Length: '.strlen($content)."\r\n\r\n");
print $content;
exit;
}

function redirect($url,$delay=0,$msg='') {

if(strstr($_SERVER['SERVER_SOFTWARE'], 'IIS')){
header("Refresh: $delay; URL=$url");
}else{
header("Location: $url");
}
exit;
}
}
?>
@@ -0,0 +1,137 @@
<?php
/*********************************************************************
class.lock.php
Ticket lock handle.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.lock.php,v 1.1.2.1 2009/08/17 18:35:46 carlos.delfino Exp $
**********************************************************************/

/*
* Mainly used as a helper...
*/

class TicketLock {
var $id;
var $staff_id;
var $created;
var $expire;
var $expiretime;

function TicketLock($id,$load=true){
$this->id=$id;
if($load) $this->load();
}

function load() {

if(!$this->id)
return false;

$sql='SELECT *,TIME_TO_SEC(TIMEDIFF(expire,NOW())) as timeleft FROM '.TICKET_LOCK_TABLE.' WHERE lock_id='.db_input($this->id);
if(($res=db_query($sql)) && db_num_rows($res)) {
$info=db_fetch_array($res);
$this->id=$info['lock_id'];
$this->staff_id=$info['staff_id'];
$this->created=$info['created'];
$this->expire=$info['expire'];
$this->expiretime=time()+$info['timeleft'];
return true;
}
$this->id=0;
return false;
}

function reload() {
return $this->load();
}

//Create a ticket lock...this function assumes the caller check for access & validity of ticket & staff x-ship.
function acquire($ticketId,$staffId) {
global $cfg;

if(!$ticketId or !$staffId or !$cfg->getLockTime())
return 0;

//Cleanup any expired locks on the ticket.
db_query('DELETE FROM '.TICKET_LOCK_TABLE.' WHERE ticket_id='.db_input($ticketId).' AND expire<NOW()');
//TODO: cleanup any other locks owned by the user? (NOT a good idea.. could be working on 2 tickets at once??)
$sql='INSERT IGNORE INTO '.TICKET_LOCK_TABLE.' SET created=NOW() '.
',ticket_id='.db_input($ticketId).
',staff_id='.db_input($staffId).
',expire=DATE_ADD(NOW(),INTERVAL '.$cfg->getLockTime().' MINUTE) ';

return db_query($sql)?db_insert_id():0;
}

//Renew existing lock.
function renew() {
global $cfg;

$sql='UPDATE '.TICKET_LOCK_TABLE.' SET expire=DATE_ADD(NOW(),INTERVAL '.$cfg->getLockTime().' MINUTE) '.
' WHERE lock_id='.db_input($this->getId());
//echo $sql;
if(db_query($sql) && db_affected_rows()) {
$this->reload();
return true;
}
return false;
}

//release aka delete a lock.
function release(){
//FORCED release - we don't give a ....
$sql='DELETE FROM '.TICKET_LOCK_TABLE.' WHERE lock_id='.db_input($this->getId());
return (db_query($sql) && db_affected_rows())?true:false;
}

function getId(){
return $this->id;
}

function getStaffId(){
return $this->staff_id;
}

function getCreateTime() {
return $this->created;
}

function getExpireTime() {
return $this->expire;
}
//Get remaiming time before the lock expires
function getTime() {
return $this->isExpired()?0:($this->expiretime-time());
}

//Should we be doing realtime check here? (Ans: not really....expiretime is local & based on loadtime)
function isExpired(){
return (time()>$this->expiretime)?true:false;
}

//Simply remove ALL locks a user (staff) holds on a ticket(s).
function removeStaffLocks($staffId,$ticketId=0) {
$sql='DELETE FROM '.TICKET_LOCK_TABLE.' WHERE staff_id='.db_input($staffId);
if($ticketId)
$sql.=' AND ticket_id='.db_input($ticketId);

return db_query($sql)?true:false;
}

//Called via cron
function cleanup() {
//Cleanup any expired locks.
db_query('DELETE FROM '.TICKET_LOCK_TABLE.' WHERE expire<NOW()');
@db_query('OPTIMIZE TABLE '.TICKET_LOCK_TABLE);
}
}
?>
@@ -0,0 +1,367 @@
<?php
/*********************************************************************
class.mailfetch.php
mail fetcher class. Uses IMAP ext for now.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.mailfetch.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

require_once(INCLUDE_DIR.'class.mailparse.php');
require_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.dept.php');

class MailFetcher {
var $hostname;
var $username;
var $password;

var $port;
var $protocol;
var $encryption;

var $mbox;

var $charset= 'UTF-8';

function MailFetcher($username,$password,$hostname,$port,$protocol,$encryption='') {

if(!strcasecmp($protocol,'pop')) //force pop3
$protocol='pop3';

$this->hostname=$hostname;
$this->username=$username;
$this->password=$password;
$this->protocol=strtolower($protocol);
$this->port = $port;
$this->encryption = $encryption;

$this->serverstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
if(!strcasecmp($this->encryption,'SSL')){
$this->serverstr.='/ssl';
}
$this->serverstr.='/novalidate-cert}INBOX'; //add other flags here as needed.

//echo $this->serverstr;
//Charset to convert the mail to.
$this->charset='UTF-8';
//Set timeouts
if(function_exists('imap_timeout'))
imap_timeout(1,20); //Open timeout.
}

function connect() {
return $this->open()?true:false;
}

function open() {

//echo $this->serverstr;
if($this->mbox && imap_ping($this->mbox))
return $this->mbox;

$this->mbox =@imap_open($this->serverstr,$this->username,$this->password);

return $this->mbox;
}

function close() {
imap_close($this->mbox,CL_EXPUNGE);
}

function mailcount(){
return count(imap_headers($this->mbox));
}


function decode($encoding,$text) {

switch($encoding) {
case 1:
$text=imap_8bit($text);
break;
case 2:
$text=imap_binary($text);
break;
case 3:
$text=imap_base64($text);
break;
case 4:
$text=imap_qprint($text);
break;
case 5:
default:
$text=$text;
}
return $text;
}

//Convert text to desired encoding..defaults to utf8
function mime_encode($text,$charset=null,$enc='utf-8') { //Thank in part to afterburner

$encodings=array('UTF-8','WINDOWS-1251', 'ISO-8859-5', 'ISO-8859-1','KOI8-R');
if(function_exists("iconv") and $text) {
if($charset)
return iconv($charset,$enc.'//IGNORE',$text);
elseif(function_exists("mb_detect_encoding"))
return iconv(mb_detect_encoding($text,$encodings),$enc,$text);
}

return utf8_encode($text);
}

//Generic decoder - mirrors imap_utf8
function mime_decode($text) {

$a = imap_mime_header_decode($text);
$str = '';
foreach ($a as $k => $part)
$str.= $part->text;

return $str?$str:imap_utf8($text);
}

function getLastError(){
return imap_last_error();
}

function getMimeType($struct) {
$mimeType = array('TEXT', 'MULTIPART', 'MESSAGE', 'APPLICATION', 'AUDIO', 'IMAGE', 'VIDEO', 'OTHER');
if(!$struct || !$struct->subtype)
return 'TEXT/PLAIN';

return $mimeType[(int) $struct->type].'/'.$struct->subtype;
}

function getHeaderInfo($mid) {

$headerinfo=imap_headerinfo($this->mbox,$mid);
$sender=$headerinfo->from[0];

//Parse what we need...
$header=array(
'from' =>array('name' =>@$sender->personal,'email' =>strtolower($sender->mailbox).'@'.$sender->host),
'subject'=>@$headerinfo->subject,
'mid' =>$headerinfo->message_id);
return $header;
}

//search for specific mime type parts....encoding is the desired encoding.
function getPart($mid,$mimeType,$encoding=false,$struct=null,$partNumber=false){

if(!$struct && $mid)
$struct=@imap_fetchstructure($this->mbox, $mid);
//Match the mime type.
if($struct && !$struct->ifdparameters && strcasecmp($mimeType,$this->getMimeType($struct))==0){
$partNumber=$partNumber?$partNumber:1;
if(($text=imap_fetchbody($this->mbox, $mid, $partNumber))){
if($struct->encoding==3 or $struct->encoding==4) //base64 and qp decode.
$text=$this->decode($struct->encoding,$text);
$charset=null;
if($encoding) { //Convert text to desired mime encoding...
if($struct->ifparameters){
if(!strcasecmp($struct->parameters[0]->attribute,'CHARSET') && strcasecmp($struct->parameters[0]->value,'US-ASCII'))
$charset=trim($struct->parameters[0]->value);
}
$text=$this->mime_encode($text,$charset,$encoding);
}
return $text;
}
}
//Do recursive search
$text='';
if($struct && $struct->parts){
while(list($i, $substruct) = each($struct->parts)) {
if($partNumber)
$prefix = $partNumber . '.';
if(($result=$this->getPart($mid,$mimeType,$encoding,$substruct,$prefix.($i+1))))
$text.=$result;
}
}
return $text;
}

function getHeader($mid){
return imap_fetchheader($this->mbox, $mid,FT_PREFETCHTEXT);
}


function getPriority($mid){
return Mail_Parse::parsePriority($this->getHeader($mid));
}

function getBody($mid) {

$body ='';
if(!($body = $this->getpart($mid,'TEXT/PLAIN',$this->charset))) {
if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) {
//Convert tags of interest before we striptags
$body=str_replace("</DIV><DIV>", "\n", $body);
$body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
$body=Format::striptags($body); //Strip tags??
}
}
return $body;
}

function createTicket($mid,$emailid=0){
global $cfg;

$mailinfo=$this->getHeaderInfo($mid);

//Make sure the email is NOT one of the undeleted emails.
if($mailinfo['mid'] && ($id=Ticket::getIdByMessageId(trim($mailinfo['mid']),$mailinfo['from']['email']))){
//TODO: Move emails to a fetched folder when delete is false??
return false;
}

$var['name']=$this->mime_decode($mailinfo['from']['name']);
$var['email']=$mailinfo['from']['email'];
$var['subject']=$mailinfo['subject']?$this->mime_decode($mailinfo['subject']):'[No Subject]';
$var['message']=Format::stripEmptyLines($this->getBody($mid));
$var['header']=$this->getHeader($mid);
$var['emailId']=$emailid?$emailid:$cfg->getDefaultEmailId(); //ok to default?
$var['name']=$var['name']?$var['name']:$var['email']; //No name? use email
$var['mid']=$mailinfo['mid'];

if($cfg->useEmailPriority())
$var['pri']=$this->getPriority($mid);

$ticket=null;
$newticket=true;
//Check the subject line for possible ID.
if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
$extid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
$ticket= new Ticket(Ticket::getIdByExtId($extid));
//Allow mismatched emails?? For now NO.
if(!$ticket || strcasecmp($ticket->getEmail(),$var['email']))
$ticket=null;
}

$errors=array();
if(!$ticket) {
if(!($ticket=Ticket::create($var,$errors,'Email')) || $errors)
return null;
$msgid=$ticket->getLastMsgId();
}else{
$message=$var['message'];
//Strip quoted reply...TODO: figure out how mail clients do it without special tag..
if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
list($message)=split($tag,$var['message']);
$msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']);
}
//Save attachments if any.
if($msgid && $cfg->allowEmailAttachments()){
if(($struct = imap_fetchstructure($this->mbox,$mid)) && $struct->parts) {
if($ticket->getLastMsgId()!=$msgid)
$ticket->setLastMsgId($msgid);
$this->saveAttachments($ticket,$mid,$struct);

}
}
return $ticket;
}

function saveAttachments($ticket,$mid,$part,$index=0) {
global $cfg;

if($part && $part->ifdparameters && ($filename=$part->dparameters[0]->value)){ //attachment
$index=$index?$index:1;
if($ticket && $cfg->canUploadFileType($filename) && $cfg->getMaxFileSize()>=$part->bytes) {
//extract the attachments...and do the magic.
$data=$this->decode($part->encoding, imap_fetchbody($this->mbox,$mid,$index));
$ticket->saveAttachment($filename,$data,$ticket->getLastMsgId(),'M');
return;
}
//TODO: Log failure??
}

//Recursive attachment search!
if($part && $part->parts) {
foreach($part->parts as $k=>$struct) {
if($index) $prefix = $index.'.';
$this->saveAttachments($ticket,$mid,$struct,$prefix.($k+1));
}
}

}

function fetchTickets($emailid,$max=20,$deletemsgs=false){

$nummsgs=imap_num_msg($this->mbox);
//echo "New Emails: $nummsgs\n";
$msgs=$errors=0;
for($i=$nummsgs; $i>0; $i--){ //process messages in reverse. Latest first. FILO.
if($this->createTicket($i,$emailid)){
imap_setflag_full($this->mbox, imap_uid($this->mbox,$i), "\\Seen", ST_UID); //IMAP only??
if($deletemsgs)
imap_delete($this->mbox,$i);
$msgs++;
$errors=0; //We are only interested in consecutive errors.
}else{
$errors++;
}
if(($max && $msgs>=$max) || $errors>20)
break;
}
@imap_expunge($this->mbox);

return $msgs;
}

function fetchMail(){
global $cfg;

if(!$cfg->canFetchMail())
return;

//We require imap ext to fetch emails via IMAP/POP3
if(!function_exists('imap_open')) {
$msg='PHP must be compiled with IMAP extension enabled for IMAP/POP3 fetch to work!';
Sys::log(LOG_WARN,'Mail Fetch Error',$msg);
return;
}

$MAX_ERRORS=5; //Max errors before we start delayed fetch attempts - hardcoded for now.

$sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_errors,userid,userpass FROM '.EMAIL_TABLE.
' WHERE mail_active=1 AND (mail_errors<='.$MAX_ERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(),mail_lasterror))>5*60) )'.
' AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(),mail_lastfetch))>mail_fetchfreq*60) ';
//echo $sql;
if(!($accounts=db_query($sql)) || !db_num_rows($accounts))
return;

//TODO: Lock the table here??
while($row=db_fetch_array($accounts)) {
$fetcher = new MailFetcher($row['userid'],Misc::decrypt($row['userpass'],SECRET_SALT),
$row['mail_host'],$row['mail_port'],$row['mail_protocol'],$row['mail_encryption']);
if($fetcher->connect()){
$fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false);
$fetcher->close();
db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($row['email_id']));
}else{
$errors=$row['mail_errors']+1;
db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($row['email_id']));
if($errors>=$MAX_ERRORS){
//We've reached the MAX consecutive errors...will attempt logins at delayed intervals
$msg="\nThe system is having trouble fetching emails from the following mail account: \n".
"\nUser: ".$row['userid'].
"\nHost: ".$row['mail_host'].
"\nError: ".$fetcher->getLastError().
"\n\n ".$errors.' consecutive errors. Maximum of '.$MAX_ERRORS. ' allowed'.
"\n\n This could be connection issues related to the host. Next delayed login attempt in aprox. 10 minutes";
Sys::alertAdmin('Mail Fetch Failure Alert',$msg,true);
}
}
}
}
}
?>
@@ -0,0 +1,180 @@
<?php
/*********************************************************************
class.mailparse.php
Mail parsing helper class.
Mail parsing will change once we move to PHP5
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.mailparse.php,v 1.2.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

require_once('Mail/mimeDecode.php');
require_once('Mail/RFC822.php');

class Mail_Parse {

var $mime_message;
var $include_bodies;
var $decode_headers;
var $decode_bodies;

var $struct;

function Mail_parse($mimeMessage,$includeBodies=true,$decodeHeaders=TRUE,$decodeBodies=TRUE){

$this->mime_message=$mimeMessage;
$this->include_bodies=$includeBodies;
$this->decode_headers=$decodeHeaders;
$this->decode_bodies=$decodeBodies;
}

function decode() {

$params = array('crlf' => "\r\n",
'input' =>$this->mime_message,
'include_bodies'=> $this->include_bodies,
'decode_headers'=> $this->decode_headers,
'decode_bodies' => $this->decode_bodies);
$this->splitBodyHeader();
$this->struct=Mail_mimeDecode::decode($params);

return (PEAR::isError($this->struct) || !(count($this->struct->headers)>1))?FALSE:TRUE;
}

function splitBodyHeader() {

if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s",$this->mime_message, $match)) {
$this->header=$match[1];
}
}


function getStruct(){
return $this->struct;
}

function getHeader() {
if(!$this->header) $this->splitBodyHeader();

return $this->header;
}

function getError(){
return PEAR::isError($this->struct)?$this->struct->getMessage():'';
}


function getFromAddressList(){
return Mail_Parse::parseAddressList($this->struct->headers['from']);
}

function getToAddressList(){
//Delivered-to incase it was a BBC mail.
return Mail_Parse::parseAddressList($this->struct->headers['to']?$this->struct->headers['to']:$this->struct->headers['delivered-to']);
}

function getCcAddressList(){
return $this->struct->headers['cc']?Mail_Parse::parseAddressList($this->struct->headers['cc']):null;
}

function getMessageId(){
return $this->struct->headers['message-id'];
}

function getSubject(){
return $this->struct->headers['subject'];
}

function getBody(){

$body='';
if(!($body=$this->getPart($this->struct,'text/plain'))) {
if(($body=$this->getPart($this->struct,'text/html'))) {
//Cleanup the html.
$body=str_replace("</DIV><DIV>", "\n", $body);
$body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
$body=Format::striptags($body);
}
}
return $body;
}

function getPart($struct,$ctypepart) {

if($struct && !$struct->parts) {
$ctype = @strtolower($struct->ctype_primary.'/'.$struct->ctype_secondary);
if($ctype && strcasecmp($ctype,$ctypepart)==0)
return $struct->body;
}

$data='';
if($struct && $struct->parts) {
foreach($struct->parts as $i=>$part) {
if($part && !$part->disposition && ($text=$this->getPart($part,$ctypepart)))
$data.=$text;
}
}
return $data;
}

function getAttachments($part=null){

if($part==null)
$part=$this->getStruct();

if($part && $part->disposition
&& (!strcasecmp($part->disposition,'attachment')
|| !strcasecmp($part->disposition,'inline')
|| !strcasecmp($part->ctype_primary,'image'))){
if(!($filename=$part->d_parameters['filename']) && $part->d_parameters['filename*'])
$filename=$part->d_parameters['filename*']; //Do we need to decode?
return array(array('filename'=>$filename,'body'=>$part->body));
}

$files=array();
if($part->parts){
foreach($part->parts as $k=>$p){
if($p && ($result=$this->getAttachments($p))) {
$files=array_merge($files,$result);
}
}
}

return $files;
}

function getPriority(){
return Mail_Parse::parsePriority($this->getHeader());
}

function parsePriority($header=null){

$priority=0;
if($header && ($begin=strpos($header,'X-Priority:'))!==false){
$begin+=strlen('X-Priority:');
$xpriority=preg_replace("/[^0-9]/", "",substr($header, $begin, strpos($header,"\n",$begin) - $begin));
if(!is_numeric($xpriority))
$priority=0;
elseif($xpriority>4)
$priority=1;
elseif($xpriority>=3)
$priority=2;
elseif($xpriority>0)
$priority=3;
}
return $priority;
}

function parseAddressList($address){
return Mail_RFC822::parseAddressList($address, null, null,false);
}
}
@@ -0,0 +1,145 @@
<?php
/*********************************************************************
class.misc.php
Misc collection of useful generic helper functions.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.misc.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/
class Misc {

function randCode($len=8) {
return substr(strtoupper(base_convert(microtime(),10,16)),0,$len);
}

/* Helper used to generate ticket IDs */
function randNumber($len=6,$start=false,$end=false) {

mt_srand ((double) microtime() * 1000000);
$start=(!$len && $start)?$start:str_pad(1,$len,"0",STR_PAD_RIGHT);
$end=(!$len && $end)?$end:str_pad(9,$len,"9",STR_PAD_RIGHT);

return mt_rand($start,$end);
}

function encrypt($text, $salt) {

//if mcrypt extension is not installed--simply return unencryted text and log a warning.
if(!function_exists('mcrypt_encrypt') || !function_exists('mcrypt_decrypt')) {
$msg='Cryptography extension mcrypt is not enabled or installed. IMAP/POP passwords are being stored as plain text in database.';
Sys::log(LOG_WARN,'mcrypt missing',$msg);
return $text;
}

return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$salt, $text, MCRYPT_MODE_ECB,
mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}

function decrypt($text, $salt) {
if(!function_exists('mcrypt_encrypt') || !function_exists('mcrypt_decrypt'))
return $text;

return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB,
mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}

/* misc date helpers...this will go away once we move to php 5 */
function db2gmtime($var){
global $cfg;
if(!$var) return;

$dbtime=is_int($var)?$var:strtotime($var);
return $dbtime-($cfg->getMysqlTZoffset()*3600);
}

//Take user time or gmtime and return db (mysql) time.
function dbtime($var=null){
global $cfg;

if(is_null($var) || !$var)
$time=Misc::gmtime(); //gm time.
else{ //user time to GM.
$time=is_int($var)?$var:strtotime($var);
$offset=$_SESSION['TZ_OFFSET']+($_SESSION['daylight']?date('I',$time):0);
$time=$time-($offset*3600);
}
//gm to db time
return $time+($cfg->getMysqlTZoffset()*3600);
}

/*Helper get GM time based on timezone offset*/
function gmtime() {
return time()-date('Z');
}

//Current page
function currentURL() {

$str = 'http';
if ($_SERVER['HTTPS'] == 'on') {
$str .='s';
}
$str .= '://';
if (!isset($_SERVER['REQUEST_URI'])) { //IIS???
$_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'],1 );
if (isset($_SERVER['QUERY_STRING'])) {
$_SERVER['REQUEST_URI'].='?'.$_SERVER['QUERY_STRING'];
}
}
if ($_SERVER['SERVER_PORT']!=80) {
$str .= $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI'];
} else {
$str .= $_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
}

return $str;
}

function timeDropdown($hr=null, $min =null,$name='time') {
$hr =is_null($hr)?0:$hr;
$min =is_null($min)?0:$min;

//normalize;
if($hr>=24)
$hr=$hr%24;
elseif($hr<0)
$hr=0;

if($min>=45)
$min=45;
elseif($min>=30)
$min=30;
elseif($min>=15)
$min=15;
else
$min=0;

ob_start();
echo sprintf('<select name="%s" id="%s">',$name,$name);
echo '<option value="" selected>Time</option>';
for($i=23; $i>=0; $i--) {
for($minute=45; $minute>=0; $minute-=15) {
$sel=($hr==$i && $min==$minute)?'selected="selected"':'';
$_minute=str_pad($minute, 2, '0',STR_PAD_LEFT);
$_hour=str_pad($i, 2, '0',STR_PAD_LEFT);
echo sprintf('<option value="%s:%s" %s>%s:%s</option>',$_hour,$_minute,$sel,$_hour,$_minute);
}
}
echo '</select>';
$output = ob_get_contents();
ob_end_clean();

return $output;
}


}
?>
@@ -0,0 +1,217 @@
<?php
/*********************************************************************
class.msgtpl.php
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.msgtpl.php,v 1.1.2.1 2009/08/17 18:35:47 carlos.delfino Exp $
**********************************************************************/

class Template {

var $id;
var $name;

var $info;

function Template($id,$cId=0){
$this->load($id,$cId);
}

function load($id,$cId=0) {

if(!$id)
return false;

$sql='SELECT * FROM '.EMAIL_TEMPLATE_TABLE.' WHERE tpl_id='.db_input($id);
if($cId && is_numeric($cId))
$sql.=' AND cfg_id='.db_input($cId);

if(($res=db_query($sql)) && db_num_rows($res)) {
$info=db_fetch_array($res);
$this->id=$info['tpl_id'];
$this->cfgId=$info['cfg_id'];
$this->name=$info['name'];
$this->info=$info;
return true;
}
$this->id=0;

return false;
}

function reload() {
return $this->load($this->getId(),$this->getCfgId());
}

function getId(){
return $this->id;
}

function getCfgId(){
return $this->cfgId;
}

function getName(){
return $this->name;
}

function getInfo() {
return $this->info;
}

function getCreateDate() {
return $this->info['created'];
}

function getUpdateDate() {
return $this->info['updated'];
}


function update($var,&$errors){


$fields=array();
$fields['id'] = array('type'=>'int', 'required'=>1, 'error'=>'Internal Error');
$fields['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required');
//Notices sent to user
$fields['ticket_autoresp_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_autoresp_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['message_autoresp_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['message_autoresp_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['ticket_notice_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_notice_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['ticket_overlimit_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_overlimit_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['ticket_reply_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_reply_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
//Alerts sent to Staff
$fields['ticket_alert_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_alert_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['message_alert_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['message_alert_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['note_alert_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['note_alert_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['assigned_alert_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['assigned_alert_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');
$fields['ticket_overdue_subj'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required');
$fields['ticket_overdue_body'] = array('type'=>'string', 'required'=>1, 'error'=>'Template message required');

$validate = new Validator($fields);
if(!$validate->validate($var)){
$errors=array_merge($errors,$validate->errors());
}

if(!$errors && $var['id'] && $var['id']!=$this->getId())
$errors['err']='Internal error. Try again';

if(!$errors['name'] && ($tid=Template::getIdByName($var['name'])) && $tid!=$this->getId())
$errors['name']='Name already in use';

if(!$errors) {

$sql='UPDATE '.EMAIL_TEMPLATE_TABLE.' SET updated=NOW() '.
',name='.db_input(Format::striptags($var['name'])).
',notes='.db_input(Format::striptags($var['notes'])).
',ticket_autoresp_subj='.db_input(Format::striptags($var['ticket_autoresp_subj'])).
',ticket_autoresp_body='.db_input(Format::striptags($var['ticket_autoresp_body'])).
',message_autoresp_subj='.db_input(Format::striptags($var['message_autoresp_subj'])).
',message_autoresp_body='.db_input(Format::striptags($var['message_autoresp_body'])).
',ticket_notice_subj='.db_input(Format::striptags($var['ticket_notice_subj'])).
',ticket_notice_body='.db_input(Format::striptags($var['ticket_notice_body'])).
',ticket_alert_subj='.db_input(Format::striptags($var['ticket_alert_subj'])).
',ticket_alert_body='.db_input(Format::striptags($var['ticket_alert_body'])).
',message_alert_subj='.db_input(Format::striptags($var['message_alert_subj'])).
',message_alert_body='.db_input(Format::striptags($var['message_alert_body'])).
',note_alert_subj='.db_input(Format::striptags($var['note_alert_subj'])).
',note_alert_body='.db_input(Format::striptags($var['note_alert_body'])).
',assigned_alert_subj='.db_input(Format::striptags($var['assigned_alert_subj'])).
',assigned_alert_body='.db_input(Format::striptags($var['assigned_alert_body'])).
',ticket_overdue_subj='.db_input(Format::striptags($var['ticket_overdue_subj'])).
',ticket_overdue_body='.db_input(Format::striptags($var['ticket_overdue_body'])).
',ticket_overlimit_subj='.db_input(Format::striptags($var['ticket_overlimit_subj'])).
',ticket_overlimit_body='.db_input(Format::striptags($var['ticket_overlimit_body'])).
',ticket_reply_subj='.db_input(Format::striptags($var['ticket_reply_subj'])).
',ticket_reply_body='.db_input(Format::striptags($var['ticket_reply_body'])).
' WHERE tpl_id='.db_input($this->getId());

if(!db_query($sql) || !db_affected_rows())
$errors['err']='Unable to update. Internal error occured';

}

return $errors?false:true;

}


function getIdByName($name) {

$id=0;
$sql='SELECT tpl_id FROM '.EMAIL_TEMPLATE_TABLE.' WHERE name='.db_input($name);
if(($resp=db_query($sql)) && db_num_rows($resp))
list($id)=db_fetch_row($resp);

return $id;
}


function create($var,&$errors){
global $cfg;

if(!$var['name'])
$errors['name']='required';
elseif(!$errors && Template::getIdByName($var['name']))
$errors['name']='Name already in use';

if(!$var['copy_template'])
$errors['copy_template']='required';
else if(!$errors){
$template= new Template($var['copy_template'],$cfg->getId());
if(!is_object($template) || !$template->getId())
$errors['copy_template']='Unknown template';
}

$id=0;
if(!$errors && ($info=$template->getInfo())) {

$sql='INSERT INTO '.EMAIL_TEMPLATE_TABLE.' SET updated=NOW(), created=NOW() '.
',cfg_id='.db_input($cfg->getId()).
',name='.db_input(Format::striptags($var['name'])).
',notes='.db_input('New template: copy of '.$info['name']).
',ticket_autoresp_subj='.db_input(Format::striptags($info['ticket_autoresp_subj'])).
',ticket_autoresp_body='.db_input(Format::striptags($info['ticket_autoresp_body'])).
',message_autoresp_subj='.db_input(Format::striptags($info['message_autoresp_subj'])).
',message_autoresp_body='.db_input(Format::striptags($info['message_autoresp_body'])).
',ticket_notice_subj='.db_input(Format::striptags($info['ticket_notice_subj'])).
',ticket_notice_body='.db_input(Format::striptags($info['ticket_notice_body'])).
',ticket_alert_subj='.db_input(Format::striptags($info['ticket_alert_subj'])).
',ticket_alert_body='.db_input(Format::striptags($info['ticket_alert_body'])).
',message_alert_subj='.db_input(Format::striptags($info['message_alert_subj'])).
',message_alert_body='.db_input(Format::striptags($info['message_alert_body'])).
',note_alert_subj='.db_input(Format::striptags($info['note_alert_subj'])).
',note_alert_body='.db_input(Format::striptags($info['note_alert_body'])).
',assigned_alert_subj='.db_input(Format::striptags($info['assigned_alert_subj'])).
',assigned_alert_body='.db_input(Format::striptags($info['assigned_alert_body'])).
',ticket_overdue_subj='.db_input(Format::striptags($info['ticket_overdue_subj'])).
',ticket_overdue_body='.db_input(Format::striptags($info['ticket_overdue_body'])).
',ticket_overlimit_subj='.db_input(Format::striptags($info['ticket_overlimit_subj'])).
',ticket_overlimit_body='.db_input(Format::striptags($info['ticket_overlimit_body'])).
',ticket_reply_subj='.db_input(Format::striptags($info['ticket_reply_subj'])).
',ticket_reply_body='.db_input(Format::striptags($info['ticket_reply_body']));
//echo $sql;
if(!db_query($sql) || !($id=db_insert_id()))
$errors['err']='Unable to create the template. Internal error occured';
}
return $id;
}

}
?>
@@ -0,0 +1,103 @@
<?php
/*********************************************************************
class.nav.php
Navigation helper classes. Pointless BUT helps keep navigation clean and free from errors.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: $
**********************************************************************/
class StaffNav {
var $tabs=array();
var $submenu=array();

var $activetab;
var $ptype;

function StaffNav($pagetype='staff'){
global $thisuser;

$trl = $_SESSION['trl'];

$this->ptype=$pagetype;
$tabs=array();
if($thisuser->isAdmin() && strcasecmp($pagetype,'admin')==0) {
$desc = $trl->translate("LABEL_DASHBOARD");
$title = $trl->translate("LABEL_ADMIN_DASHBOARD");
$tabs['dashboard']=array('desc'=>$title,'href'=>'admin.php?t=dashboard','title'=>$tile);
$desc = $trl->translate("LABEL_SETTINGS");
$title = $trl->translate("LABEL_SYSTEM_SETTINGS");
$tabs['settings']=array('desc'=>$desc,'href'=>'admin.php?t=settings','title'=>$title);
$desc = $trl->_t('LABEL_EMAILS');
$title = $trl->_t('LABEL_EMAILS_SETTINGS');
$tabs['emails']=array('desc'=>$desc,'href'=>'admin.php?t=email','title'=>$title);
$desc = $trl->_t('LABEL_HELP_TOPICS');
$title = $trl->_t('LABEL_HELP_TOPICS');
$tabs['topics']=array('desc'=>$desc,'href'=>'admin.php?t=topics','title'=>$title);
$desc = $trl->_t('LABEL_STAFF');
$title = $trl->_t('LABEL_STAFF_MEMBERS');
$tabs['staff']=array('desc'=>$desc,'href'=>'admin.php?t=staff','title'=>$title);
$desc = $trl->_t('LABEL_DEPARTMENTS');
$title = $trl->_t('LABEL_DEPARTMENTS');
$tabs['depts']=array('desc'=>$desc,'href'=>'admin.php?t=depts','title'=>$title);
}else {
$tabs['tickets']=array('desc'=>'Tickets','href'=>'tickets.php','title'=>'Ticket Queue');
if($thisuser && $thisuser->canManageKb()){
$desc = $trl->translate('LABEL_KNOWLEDGE_BASE');
$title = $trl->translate('LABEL_KNOWLEDGE_BASE_PREMATE');
$tabs['kbase']=array('desc'=>$desc,'href'=>'kb.php','title'=>$title);
}
$desc = $trl->translate('LABEL_DIRECTORY');
$title = $trl->translate('LABEL_DIRETORY_STAFF');
$tabs['directory']=array('desc'=>$desc,'href'=>'directory.php','title'=>$title);
$desc = $trl->translate('LABEL_MY_ACCOUNT');
$title = $trl->translate('LABEL_MY_ACCOUNT');
$tabs['profile']=array('desc'=>$desc,'href'=>'profile.php','title'=>$title);
}
$this->tabs=$tabs;
}


function setTabActive($tab){

if($this->tabs[$tab]){
$this->tabs[$tab]['active']=true;
if($this->activetab && $this->activetab!=$tab && $this->tabs[$this->activetab])
$this->tabs[$this->activetab]['active']=false;
$this->activetab=$tab;
return true;
}
return false;
}

function addSubMenu($item,$tab=null) {

$tab=$tab?$tab:$this->activetab;
$this->submenu[$tab][]=$item;
}



function getActiveTab(){
return $this->activetab;
}

function getTabs(){
return $this->tabs;
}

function getSubMenu($tab=null){

$tab=$tab?$tab:$this->activetab;
return $this->submenu[$tab];
}

}
?>
@@ -0,0 +1,145 @@
<?php
/*********************************************************************
class.format.php
Pagenation support class
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2010 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.pagenate.php,v 1.1.2.2 2009/11/29 22:03:28 carlos.delfino Exp $
**********************************************************************/

class PageNate {

var $start;
var $limit;
var $total;
var $page;
var $pages;
var $trl;

function PageNate($total,$page,$limit=20,$trl=null, $url='') {
$this->total = intval($total);
$this->limit = max($limit, 1 );
$this->page = max($page, 1 );
$this->start = max((($page-1)*$this->limit),0);
$this->pages = ceil( $this->total / $this->limit );

if(isset($trl)){
$this->trl = $trl;
}else{
$this->trl = new Translator();
}
if (($this->limit > $this->total) || ($this->page>ceil($this->total/$this->limit))) {
$this->start = 0;
}
if (($this->limit-1)*$this->start > $this->total) {
$this->start -= $this->start % $this->limit;
}
$this->setURL($url);
}
function setURL($url='',$vars=''){
if($url){
if(strpos($url,'?')===false)
$url=$url.'?';
}else{
$url=THISPAGE.'?';
}
$this->url=$url.$vars;
}

function getStart() {
return $this->start;
}

function getLimit() {
return $this->limit;
}


function getNumPages(){
return $this->pages;
}

function getPage() {
return ceil(($this->start+1)/$this->limit);
}


function showing() {
$html = '';
$from= $this->start+1;
if ($this->start + $this->limit < $this->total) {
$to= $this->start + $this->limit;
} else {
$to= $this->total;
}
if(!isset($this->trl)){
$html="&nbsp;Showing&nbsp;&nbsp;";
if ($this->total > 0) {
$html .= "$from - $to of " .$this->total;
}else{
$html .= " 0 ";
}
}else{
if ($this->total > 0) {
$html .= $this->trl->translate('TEXT_SHOW_FROM_TO_OF_ALL',array($from, $to, $this->total));
}else{
$html .= $this->trl->translate('TEXT_SHOW_ZERO');
}
}
return $html;
}

function getPageLinks() {
$html = '';
$file =$this->url;
$displayed_span = 5;
$total_pages = ceil( $this->total / $this->limit );
$this_page = ceil( ($this->start+1) / $this->limit );

$last=$this_page-1;
$next=$this_page+1;

$start_loop = floor($this_page-$displayed_span);
$stop_loop = ceil($this_page + $displayed_span);



$stopcredit =($start_loop<1)?0-$start_loop:0;
$startcredit =($stop_loop>$total_pages)?$stop_loop-$total_pages:0;

$start_loop =($start_loop-$startcredit>0)?$start_loop-$startcredit:1;
$stop_loop =($stop_loop+$stopcredit>$total_pages)?$total_pages:$stop_loop+$stopcredit;

if($start_loop>1){
$lastspan=($start_loop-$displayed_span>0)?$start_loop-$displayed_span:1;
$html .= "\n<a href=\"$file&p=$lastspan\" ><strong>&laquo;</strong></a>";
}

for ($i=$start_loop; $i <= $stop_loop; $i++) {
$page = ($i - 1) * $this->limit;
if ($i == $this_page) {
$html .= "\n<b>[$i]</b>";
} else {
$html .= "\n<a href=\"$file&p=$i\" ><b>$i</b></a>";
}
}
if($stop_loop<$total_pages){
$nextspan=($stop_loop+$displayed_span>$total_pages)?$total_pages-$displayed_span:$stop_loop+$displayed_span;
$html .= "\n<a href=\"$file&p=$nextspan\" ><strong>&raquo;</strong></a>";
}



return $html;
}

}
?>
@@ -0,0 +1,3 @@
<?php
//No longer used. just used to clear the old file for now. Will be deleted in the upcoming versions.
?>
@@ -0,0 +1,340 @@
<?php
/*********************************************************************
class.staff.php
Everything about staff.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006,2007,2008,2009 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
$Id: class.staff.php,v 1.1.2.1 2009/08/17 18:38:50 carlos.delfino Exp $
**********************************************************************/
class Staff {

var $udata;
var $group_id;
var $dept_id;
var $passwd;
var $id;
var $fullname;
var $username;
var $email;

var $firstname;
var $lastname;
var $signature;

var $dept;

function Staff($var){
$this->id =0;
return ($this->lookup($var));
}

function lookup($var){

$sql=sprintf("SELECT * FROM ".STAFF_TABLE." LEFT JOIN ".GROUP_TABLE." USING(group_id) WHERE %s=%s ",
is_numeric($var)?'staff_id':'username',db_input($var));

$res=db_query($sql);
if(!$res || !db_num_rows($res))
return NULL;

$row=db_fetch_array($res);
$this->udata=$row;
$this->id = $row['staff_id'];
$this->group_id = $row['group_id'];
$this->dept_id = $row['dept_id'];
$this->firstname = ucfirst($row['firstname']);
$this->lastname = ucfirst($row['lastname']);
$this->fullname = ucfirst($row['firstname'].' '.$row['lastname']);
$this->passwd = $row['passwd'];
$this->username = $row['username'];
$this->email = $row['email'];
$this->signature = $row['signature'];

return($this->id);
}

function reload(){
$this->lookup($this->id);
}

function getInfo() {
return $this->udata;
}

/*compares user password*/
function check_passwd($password){
return (strlen($this->passwd) && strcmp($this->passwd, MD5($password))==0)?(TRUE):(FALSE);
}

function getTZoffset(){
global $cfg;

$offset=$this->udata['timezone_offset'];
return $offset?$offset:$cfg->getTZoffset();
}

function observeDaylight() {
return $this->udata['daylight_saving']?true:false;
}

function getRefreshRate(){
return $this->udata['auto_refresh_rate'];
}

function getPageLimit() {
global $cfg;
$limit=$this->udata['max_page_size'];
return $limit?$limit:$cfg->getPageSize();
}

function getData(){
return($this->udata);
}

function getId(){
return $this->id;
}

function getEmail(){
return($this->email);
}

function getUserName(){
return($this->username);
}

function getName(){
return($this->fullname);
}

function getFirstName(){
return $this->firstname;
}

function getLastName(){
return $this->lastname;
}

function getDeptId(){
return $this->dept_id;
}

function getGroupId(){
return $this->group_id;
}

function getSignature(){
return($this->signature);
}

function appendMySignature(){
return $this->signature?true:false;
}

function forcePasswdChange(){
return $this->udata['change_passwd']?true:false;
}

function getDepts(){
//Departments the user is allowed to access...based on the group they belong to + user's dept.
return array_filter(array_unique(array_merge(explode(',',$this->udata['dept_access']),array($this->dept_id)))); //Neptune help us
}

function getDept(){

if(!$this->dept && $this->dept_id)
$this->dept= new Dept($this->dept_id);

return $this->dept;
}


function isManager() {
return (($dept=$this->getDept()) && $dept->getManagerId()==$this->getId())?true:false;
}

function isStaff(){
return TRUE;
}

function isGroupActive() {
return ($this->udata['group_enabled'])?true:false;
}

function isactive(){
return ($this->udata['isactive'])?true:false;
}

function isVisible(){
return ($this->udata['isvisible'])?true:false;
}

function onVacation(){
return ($this->udata['onvacation'])?true:false;
}

function isAvailable() {
return (!$this->isactive() || !$this->isGroupActive() || $this->onVacation())?false:true;
}

function isadmin(){
return ($this->udata['isadmin'])?true:false;
}

/* canDos' logic explained
1) First check id the user is super admin...if yes...super..allow
2) Check if the user is allowed to do the Do...or a manager in some cases -- if yes...allow
3) Check if he user's group is allowed...if yes...allow
5) If I-2-3 fails...it is a NO.. you can cry yourself to sleep.
*/

function canAccessDept($deptid){
return ($this->isadmin() ||in_array($deptid,$this->getDepts()))?true:false;
}

function canCreateTickets(){
return ($this->isadmin() || $this->udata['can_create_tickets'])?true:false;
}

function canEditTickets(){
return ($this->isadmin() || $this->udata['can_edit_tickets'])?true:false;
}

function canDeleteTickets(){
return ($this->isadmin() || $this->udata['can_delete_tickets'])?true:false;
}

function canCloseTickets(){
return ($this->isadmin() || $this->udata['can_close_tickets'])?true:false;
}

function canTransferTickets() {
return ($this->isadmin() || $this->isManager() || $this->udata['can_transfer_tickets'])?true:false;
}

function canManageBanList() {
return ($this->isadmin() || $this->isManager() || $this->udata['can_ban_emails'])?true:false;
}

function canManageTickets() {
return ($this->isadmin()
|| $this->canDeleteTickets()
|| $this->canManageBanList()
|| $this->canCloseTickets())?true:false;
}

function canManageKb() { //kb = knowledge base.
return ($this->isadmin() || $this->udata['can_manage_kb'])?true:false;
}

function update($vars,&$errors) {
if($this->save($this->getId(),$vars,$errors)){
$this->reload();
return true;
}
return false;
}

function create($vars,&$errors) {
return Staff::save(0,$vars,$errors);
}


function save($id,$vars,&$errors) {

include_once(INCLUDE_DIR.'class.dept.php');

if($id && $id!=$vars['staff_id'])
$errors['err']='Internal Error';

if(!$vars['firstname'] || !$vars['lastname'])
$errors['name']='First and last name required';

if(!$vars['username'] || strlen($vars['username'])<3)
$errors['username']='Username required';
else{
//check if the username is already in-use.
$sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE username='.db_input($vars['username']);
if($id)
$sql.=' AND staff_id!='.db_input($id);

if(db_num_rows(db_query($sql)))
$errors['username']='Username already in-use';
}

if(!$vars['email'] || !Validator::is_email($vars['email']))
$errors['email']='Valid email required';
elseif(Email::getIdByEmail($vars['email']))
$errors['email']='Already in-use system email';

if($vars['phone'] && !Validator::is_phone($vars['phone']))
$errors['phone']='Valid number required';

if($vars['mobile'] && !Validator::is_phone($vars['mobile']))
$errors['mobile']='Valid number required';

if($vars['npassword'] || $vars['vpassword'] || !$id){
if(!$vars['npassword'] && !$id)
$errors['npassword']='Temp password required';
elseif($vars['npassword'] && strcmp($vars['npassword'],$vars['vpassword']))
$errors['vpassword']='Password(s) do not match';
elseif($vars['npassword'] && strlen($vars['npassword'])<6)
$errors['npassword']='Must be at least 6 characters';
}

if(!$vars['dept_id'])
$errors['dept']='Department required';

if(!$vars['group_id'])
$errors['group']='Group required';


if(!$errors){

$sql=' SET updated=NOW() '.
',isadmin='.db_input($vars['isadmin']).
',isactive='.db_input($vars['isactive']).
',isvisible='.db_input(isset($vars['isvisible'])?1:0).
',onvacation='.db_input(isset($vars['onvacation'])?1:0).
',dept_id='.db_input($vars['dept_id']).
',group_id='.db_input($vars['group_id']).
',username='.db_input(Format::striptags($vars['username'])).
',firstname='.db_input(Format::striptags($vars['firstname'])).
',lastname='.db_input(Format::striptags($vars['lastname'])).
',email='.db_input($vars['email']).
',phone="'.db_input($vars['phone'],false).'"'.
',phone_ext='.db_input($vars['phone_ext']).
',mobile="'.db_input($vars['mobile'],false).'"'.
',signature='.db_input(Format::striptags($vars['signature']));

if($vars['npassword'])
$sql.=',passwd='.db_input(md5($vars['npassword']));

if(isset($vars['resetpasswd']))
$sql.=',change_passwd=1';

if($id) {
$sql='UPDATE '.STAFF_TABLE.' '.$sql.' WHERE staff_id='.db_input($id);
if(!db_query($sql) || !db_affected_rows())
$errors['err']='Unable to update the user. Internal error occured';
}else{
$sql='INSERT INTO '.STAFF_TABLE.' '.$sql.',created=NOW()';
if(db_query($sql) && ($uID=db_insert_id()))
return $uID;

$errors['err']='Unable to create user. Internal error';
}
}

return $errors?false:true;
}
}
?>