Compare commits

...

56 Commits

Author SHA1 Message Date
Jared Hancock
7960e242cb docs: Add release notes for v1.8.8 2015-03-10 11:47:57 -05:00
Jared Hancock
a394f7cd6f login: Require CSRF token to login
This patch fixes a vulnerable scenario, where sequential login attempts can
be made without an existing session, and without a valid CSRF token. This
scenario lends itself well for brute force password attempts, because
attackers can avoid using a session and still send requests to determine if
a set of credentials are valid. This vector also avoids the authentication
lockout mechanism, because it requires an ongoing session to shutdown the
requests.

This patch addresses the issue by requiring a session and a valid CSRF token
generated by the server and placed in the session to be submitted with the
credentials. Therefore, an existing session and a Cookie header are required
to process a login attempt. Secondly, the CSRF token will be changed on the
server after each login processed. Therefore, for each session, a subsequent
GET request would be necessary before submitting another login attempt.
2015-03-10 11:42:09 -05:00
Jared Hancock
7b3800bf36 oops: Fix truncated random data 2015-03-10 11:40:35 -05:00
Jared Hancock
8a348a6924 Fix very predictable random data on some platforms
Misc::randCode does not generate significantly random data for Windows
platforms with a local database. This stems from the random seed using the
milliseconds from the current time of day and the database connection time,
in microseconds. Because Windows has especially poor sub-second time
resolution via the microtime() function, the seed does not have many
variations.

This patch addresses the issue by using the included Crypto::random()
function as a source of random data rather than the mt_rand() function, as
it uses native cryptographic random data generators if possible to generate
the data, and uses microtime() as a fallback if no other source of random
data is available on the platform.
2015-03-10 11:39:56 -05:00
Chefkeks
87249490f5 [FIX] Missing icon before "Add New Filter"
Fixes the missing icon before "Add new filter" in scp at the filters.php page
2015-03-10 11:39:26 -05:00
Jared Hancock
74b13887cd Revert "Disable auto-responses on staff created tickets" 2015-03-10 11:37:54 -05:00
Jared Hancock
ecb26c0aff thread: Remove collaborators when removing the thread 2015-03-10 11:37:28 -05:00
Peter Rotich
882c0aa6c0 Move Format::encode to Charset::transcode 2015-03-10 11:36:49 -05:00
Peter Rotich
22c0fac001 charset: Normalize charset
This pull request adds a cleanup util for bogus and invalid charsets, mostly
added by a nameless company out of Redmond, WA.
2015-03-10 11:33:38 -05:00
Jared Hancock
bdfece3569 oops: Fix inability to edit agents with only one admin 2015-01-07 12:36:39 -06:00
Jared Hancock
e9bfc44b3c oops: Fix advanced search regression from fcb34cfb
Don't add to endTime if not already set
2015-01-06 11:59:56 -06:00
Jared Hancock
ab7fd654fa lock: Set ticket lock on ticket-view
Since the automatic lock was being acquired but not passed to the autoLock
system, the automatically acquired lock was not being release on away
navigation.

This patch addresses the issue by passing the automatically acquired lock id
to the autoLock system on ticket-view page load and change the ::Init()
method so that the lock id is not cleared with the ::Init() method is called
by the page load.
2015-01-05 16:30:55 -06:00
Jared Hancock
c9577e6136 oops: Ensure local $vars in Ticket::open is unmodified 2015-01-05 15:46:35 -06:00
Jared Hancock
f5d8a21dd2 oops: Remove text localization 2015-01-05 15:43:14 -06:00
Peter Rotich
e5ada3280a forms: Use form's name as the heading on edit.
Show the form title on edit instead of "Custom Form" - which can be
misleading since the user might be editing a built-in form.
2015-01-05 15:42:06 -06:00
Jared Hancock
3561bee579 Add release notes for 1.8.7 2014-12-31 15:58:33 -06:00
Peter Rotich
78c87c02ee http: Use http build query
Use http::build_query instead of inline urlencode
2014-12-31 15:55:35 -06:00
Peter Rotich
cbd6117cea html: Replace htmlentities with htmlspecialchars 2014-12-31 15:55:35 -06:00
Peter Rotich
9ffff0efcd http: Add http_build_query wrapper
This is necessary so we can sanitize/encode inputs.
2014-12-31 15:55:35 -06:00
Jared Hancock
346222c5a0 ticket: No team alert on new ticket if assigned to an agent too
If a new ticket is assigned to both an individual agent and a team, do not
send the email alert to the team lead or the team members.
2014-12-31 15:55:35 -06:00
Jared Hancock
7a7ee45864 filters: Fix several small, major issues
* Fix early rejecting of tickets — even if a filter earlier in the
    matching filter list had "stop on match" set
  * Fix ::stopOnMatch referring to incorrect db field

The new logic abandons the early rejection logic in ticket create. Instead,
the normal validation is completed as usual. Thereafter, the filter is
initialized and applied to the ticket. Upon rejection, a RejectedException
is thrown by the ::apply() method of the TicketFilter. The Ticket::create()
method will handle the exception and reject the ticket.
2014-12-31 15:55:35 -06:00
Chris Wheeler
3b84d4caf3 date search fix
This resolves #1570
2014-12-31 15:55:35 -06:00
Jared Hancock
ab88c98f02 staff: Ensure an active admin always exists 2014-12-31 15:55:35 -06:00
Jared Hancock
1fd4dbe1a1 html2text: Avoid long, wrapped URLs in a tags 2014-12-31 15:55:34 -06:00
Jared Hancock
66e04a6ab6 faq: Ensure consistent formatting for all
Faq articles should be viewed in the .thread-body div in the client portal
like they are in the staff portal.
2014-12-31 15:55:34 -06:00
Peter Rotich
bf3879500f Do NOT reopen closed ticket due to autoreply
Do not reopen closed ticket, if the system can reliably determine that the new message is an
auto-response/reply from the end user.
2014-12-31 15:55:34 -06:00
Stephen Packer
be93b908a4 createTicket respects alert/autorespond negatives
It was previously not possible to use the `alert` and `autorespond` flags in a negative way to prevent those two events, since the ternary operator would have used the `false` ternary value, which was `true`.  This corrects that by allowing the default of `true` to be used only when the `$data` array does not have the appropriate keys set.  Assigning `$data['source']` was altered to use the same formatting and caution against an undefined index error.
2014-12-31 15:55:34 -06:00
Peter Rotich
17bd5c55d1 Disable auto-responses on staff created tickets
Take into consideration the auto-response settings when sending out new
ticket by staff notice to the end user.
2014-12-31 15:55:33 -06:00
Matt Kirman
481c83ef6c Dashboard statistics should use 'period' as the date limiter
The statistics module on the dashboard was using the incorrect query parameter
'stop'. This meant that the module was loading all tickets from the report start
date to the present day. This commit fixes this by using the 'period' parameter
instead.
2014-10-13 12:50:40 -05:00
Jared Hancock
6bc8ce4a23 Add release notes 2014-10-13 11:52:14 -05:00
Jared Hancock
24e957569b orm: Fix MySQL occasional "Commands OOS" error
Under certain intermittent circumstances (usually a significant number of
ORM queries), the ORM will trigger a MySQL error:

Commands out of sync; you can't run this command now

Usually this MySQL error is related to buffered versus unbuffered queries.
However, the ORM already uses buffered queries (MySQL calls it
"store_result"). In this case, it appears there is some sort of race between
fetching the result metadata before configuring the statement for buffering.
(By "race" I mean that the error is not reliably triggered).

This patch seems to fix the issue by configuring buffering before fetching
result metadata — necessary to configure the fetching (output) phase of the
statement.
2014-10-13 11:20:01 -05:00
Peter Rotich
4e98dec006 bug: Decode mailbox when parsing an email address
This addresses cases where incoming emails doesn't include charset and
mailbox may include non-ascii characters.
2014-10-13 11:15:50 -05:00
Jared Hancock
38437db08c forms: Support non-US locale on client portal
The staff portal has a feature where the date fields are converted to
YYYY-MM-DD prior to form submission. However, this code was not ported to
the client portal. Therefore, for non-US date formats (d/m/Y for instance)
would not be processed properly by the server and would be nulled prior to
validation.
2014-10-13 11:15:36 -05:00
Jared Hancock
e2889f66a3 pages: Fix incorrect lookup of inline images
In some cases, a POST might be sent to the server and there be no draft. In
such a case, neither the draft nor the body of the page can be inspected for
images. Even worse, in some cases the previous images might be unlinked from
the article without being relinked. Therefore, the images will no longer be
linked to the page and will likely be purged from the system.
2014-10-13 11:15:03 -05:00
Jared Hancock
a470033a49 email: Improve user identification from headers
Previously, the code would scan the email headers until it found a positive
match from any of the email headers scanned. Additionally, it would attempt
to find the user from the tagged email references header. However, this
algorithm assumed that the references header was constant and predictable in
its ordering. Recent tests with Gmail prove otherwise in some tests.

This patch changes the system so that only the tagged reference header is
included in the References header, and it will scan all items in a header
(namely the References header) until both the thread and a user are
identified. If a user can be identified, the thread and user are returned.
Otherwise, the first thread hit is returned.
2014-10-13 11:11:13 -05:00
Jared Hancock
5241efcb79 email: Add MAIL_EOL setting to ost-config.php file
This setting allows administrators to add (uncomment) a MAIL_EOL setting in
the ost-config.php config file to define the line ending used for mail
headers and encoded bodies in outbound mail (SMTP, for instance).

By default, CRLF is used by the SMTP email generator as per the RFC 822
standard. However, many administrators can benefit by setting LF (\n) as the
line ending.
2014-10-13 11:07:47 -05:00
Jared Hancock
5773711003 forms: Fix crash adding user with selection field 2014-10-13 11:07:30 -05:00
Jared Hancock
19053c7726 forms: Always attempt to look up selection value by name 2014-10-13 11:05:36 -05:00
Jared Hancock
7a51bdc7b5 forms: Fix html rendering of checkbox description 2014-10-13 11:03:15 -05:00
Jared Hancock
58fe8e47f5 Fix incorrect collaborator and owner email links
Also, fix duplicate emails where a user as a collaborator would be sent a
confirmation for their own respective email.
2014-10-13 10:58:02 -05:00
Peter Rotich
3da10a8471 Make sure ticket create date is used on export 2014-10-13 10:57:24 -05:00
Jared Hancock
caa7a8ff3a email: Always include a message-id token
Previously, if the quoted response mechanism was disabled, then outgoing
mail would also not include the message-id token. This breaks the
correlation of email to ticket-thread. Now, the message-id token is always
embedded in HTML emails even if the quoted-response removal system is
disabled.

(Turns out that the message-id token was always included in text bodies.)
2014-10-13 10:56:54 -05:00
Kyra ツ
064c71f43e Fix XSS Vulnerability In "tpl.inc.php"
Another area was also outputting the unsanitized value.
2014-10-13 10:51:57 -05:00
Jared Hancock
45bf1633f9 Apply numeric sort to the ticket number column 2014-10-13 10:49:55 -05:00
Kyra ツ
e5794fd10b Fix XSS Vulnerability In "tpl.inc.php"
Fix applied to where the value is directly output to browser instead of where fetched in case special chars are allowed in `code_name`, which may break logic prior to output.
2014-10-13 10:49:36 -05:00
Jared Hancock
e9a17b16ed Add release notes for v1.8.5 2014-07-31 16:19:45 -05:00
Jared Hancock
9aaee36e8f Fix potential XSS vulnerability on user's name
Add other locations as well a failsafe for the htmlentities() call
2014-07-31 16:19:45 -05:00
Peter Rotich
733edeb648 Fix XSS vulnerability on user's name
Names parsed from incoming emails are stored in the database as is. This
pull request addresses potential XSS vulnerability due to improper display
of unsanitized names. Going forward names will be scrubbed on create.
2014-07-31 16:19:45 -05:00
Jared Hancock
c33fb6f107 forms: Phone numbers with no digits = invalid
Previously, the characters would be removed and the data would be considered
empty which would bypass validation and clear the phone number on save
rather than triggering a validation error.
2014-07-31 16:19:45 -05:00
Ian Webb
315859f89e Fix typo in suggested permissions for config file 2014-07-31 16:19:45 -05:00
Jared Hancock
6b7ed3d3e5 email: No bounces for system alerts
Send an empty return-path envelope when sending out system alerts. If they
should happen to bounce for any reason, they should not return to the system
and create tickets.
2014-07-31 16:19:45 -05:00
Jared Hancock
17ae48d4cc session: Override PHP default for session lifetime
The PHP.ini default is 1440 seconds (24 minutes). This should be configured
to something significantly higher so that the settings in the admin panel
concerning session timeouts are relevant.

Ideally, the settings from the control panel would be used, but currently
there is an inter-dependency between session and config startups.
2014-07-31 16:19:45 -05:00
Jared Hancock
9d11a7c49c forms: Preserve data for help topic fields
This patch fixes a glitch in the dynamic forms processing system preventing
the validation and capture of data for help topic custom fields. Now the
`$vars` managed inside of `Ticket::create` is connected directly to the
`DynamicFormEntry` created for the data rather than using the magical
connection to `$_POST`.
2014-07-31 16:19:43 -05:00
M. Hagen
2ffe69c21b Update class.ticket.php
I think this is a mistake, however not sure.
Tested it my self, works fine.
2014-07-31 14:15:14 -05:00
Cory Gibbons
c9bbb7a6a8 Fix spelling error in documentation 2014-07-31 14:14:58 -05:00
Peter Rotich
c933754581 Add recipient variable to canned reply context 2014-07-31 14:14:46 -05:00
82 changed files with 783 additions and 419 deletions

View File

@@ -1,3 +1,79 @@
osTicket v1.8.8
===============
### Improvements
* Fix handling of some Redmond-specific character set encoding names (#1698)
* Delete collaborators when deleting tickets (#1709)
* Fix regression preventing auto-responses for staff new tickets (#1712)
* Fix missing icon for "add new filter", thanks @Chefkeks (#1735)
### Performance and Security
* Fix generation of random data on Windows® platforms (#1672)
* Fix possible DoS and brute force on login pages (#1727)
osTicket v1.8.7
===============
### Improvements
* Consider auto response checkbox and department setting for new ticket by
staff (#1509)
* Properly handle alert and auto response flags from API (#1435), thanks
@stevepacker
* Do not reopen tickets for automated responses (#1529)
* Display FAQ article consistently on client portal (#1553)
* Avoid wrapping password reset URLs on text emails (#1558)
* Forbid disabling the only active administrator (#1569)
* Searching for tickets searches to midnight of the end date (#1572),
thanks @grintor
* Fix rejection of tickets by filter, even if a previous matching filter
would stop on match (#1644)
* Fix matching of `User / Email Address` in ticket filters (#1644)
* Skip team assignment alert on new ticket if assigned to an agent
(fddb3c7)
* Fix release of ticket lock when navigating away from ticket view (#1552)
### Performance and Security
* Fix possible XSS vulnerability in sortable table view pages (#1639)
osTicket v1.8.6
===============
### Enhancements
* Add new ost-config.php setting, `MAIL_EOL` which permanently defeats the
newline corruption on outgoing email via the PHP `mail()` function
(#1248)
### Improvements
* Fix sorting by ticket number if using sequential numbers
* Fix threading if HTML is enabled and QR is disabled (#1197)
* Export ticket `created` date (#1201)
* Fix duplicate email where a collaborator would receive a confirmation
for his own message (#1235)
* Fix multi-line display of checkbox descriptions (#1160)
* Fix API validation failure for custom list selections (#1238)
* Fix crash adding a new user with a selection field custom data
* Fix failed user identification from email headers if `References` header
is sorted differently be mail client (#1263)
* Fix deletion of inline images on pages if draft was not saved (#1288)
* Fix corruption of custom date time fields on client portal if using non
US date format (#1320)
* Fix corruption of email mailbox if improperly encoded as ISO-8859-1
without RFC 2047 charset hint (#1332)
* Fix occasional MySQL Commands OOS error from ORM (#1334)
* Dashboard statistics should use 'period' as the date limiter (#1345)
### Performance and Security
* Fix XSS vulnerability in email template management (#1162, #1163)
osTicket v1.8.5
===============
### Improvements
* Fix missing `%{recipient}` variable used in canned reply (filters) (#1047)
* Fix `%{ticket.close_date}` variable in email message templates (#1090)
* Fix premature session expiration (#1111)
* Correctly handle custom data for help topics (#1105)
* Avoid system alert notices bouncing and creating tickets (#1115)
### Performance and Security
* Fix XSS vulnerability in user name (#1108, #1131)
osTicket v1.8.4
===============
### Improvements

View File

@@ -1,4 +1,4 @@
Customizng Your Theme
Customizing Your Theme
====
When modifying the default theme, it is recommended that you do not

View File

@@ -166,6 +166,9 @@ class TicketsAjaxAPI extends AjaxController {
//dates
$startTime =($req['startDate'] && (strlen($req['startDate'])>=8))?strtotime($req['startDate']):0;
$endTime =($req['endDate'] && (strlen($req['endDate'])>=8))?strtotime($req['endDate']):0;
if ($endTime)
// $endTime should be the last second of the day, not the first like $startTime
$endTime += (60 * 60 * 24) - 1;
if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0))
$startTime=$endTime=0;
@@ -389,15 +392,15 @@ class TicketsAjaxAPI extends AjaxController {
if ($user) {
if ($user->getId() == $ticket->getOwnerId())
$errors['err'] = sprintf('Ticket owner, %s, is a collaborator by default!',
$user->getName());
Format::htmlchars($user->getName()));
elseif (($c=$ticket->addCollaborator($user,
array('isactive'=>1), $errors))) {
$note = Format::htmlchars(sprintf('%s <%s> added as a collaborator',
$c->getName(), $c->getEmail()));
Format::htmlchars($c->getName()), $c->getEmail()));
$ticket->logNote('New Collaborator Added', $note,
$thisstaff, false);
$info = array('msg' => sprintf('%s added as a collaborator',
$c->getName()));
Format::htmlchars($c->getName())));
return self::_collaborators($ticket, $info);
}
}
@@ -426,7 +429,7 @@ class TicketsAjaxAPI extends AjaxController {
return self::_collaborator($c ,$user->getForms($_POST), $errors);
$info = array('msg' => sprintf('%s updated successfully',
$c->getName()));
Format::htmlchars($c->getName())));
return self::_collaborators($ticket, $info);
}

View File

@@ -81,7 +81,7 @@ class UsersAjaxAPI extends AjaxController {
Http::response(404, 'Unknown user');
$info = array(
'title' => sprintf('Update %s', $user->getName())
'title' => sprintf('Update %s', Format::htmlchars($user->getName()))
);
$forms = $user->getForms();

View File

@@ -115,18 +115,20 @@ class TicketApiController extends ApiController {
function createTicket($data) {
# Pull off some meta-data
$alert = $data['alert'] ? $data['alert'] : true;
$autorespond = $data['autorespond'] ? $data['autorespond'] : true;
$data['source'] = $data['source'] ? $data['source'] : 'API';
$alert = array_key_exists('alert', $data) ? $data['alert'] : true;
$autorespond = array_key_exists('autorespond', $data) ? $data['autorespond'] : true;
$data['source'] = array_key_exists('source', $data) ? $data['source'] : 'API';
# Create the ticket with the data (attempt to anyway)
$errors = array();
if ($topic=Topic::lookup($data['topicId'])) {
if ($form=DynamicForm::lookup($topic->ht['form_id'])) {
$form = $form->instanciate();
if (!$form->isValid())
$errors += $form->errors();
if ($topic_form = $topic->getForm()) {
$TF = $topic_form->getForm($data);
$topic_form = $topic_form->instanciate();
$topic_form->setSource($data);
if (!$TF->isValid())
$errors = array_merge($errors, $TF->errors());
}
}
@@ -146,9 +148,9 @@ class TicketApiController extends ApiController {
}
# Save dynamic form
if (isset($form)) {
$form->setTicketId($ticket->getId());
$form->save();
if (isset($topic_form)) {
$topic_form->setTicketId($ticket->getId());
$topic_form->save();
}
return $ticket;

View File

@@ -343,7 +343,7 @@ class ApiXmlDataParser extends XmlDataParser {
unset($value[":text"]);
}
if (isset($value['encoding']))
$value['body'] = Format::utf8encode($value['body'], $value['encoding']);
$value['body'] = Charset::utf8($value['body'], $value['encoding']);
if (!strcasecmp($value['type'], 'text/html'))
$value = new HtmlThreadBody($value['body']);

75
include/class.charset.php Normal file
View File

@@ -0,0 +1,75 @@
<?php
/*********************************************************************
class.charset.php
Charset util class
Copyright (c) 2015 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:
**********************************************************************/
class Charset {
const UTF8 = 'utf-8';
// Cleanup invalid charsets
// Thanks in part to https://github.com/mikel/mail/commit/88457e
static function normalize($charset) {
$match = array();
switch (true) {
// Windows charsets - force correct format
case preg_match('`^Windows-?(\d+)$`', $charset, $match):
return 'Windows-'.$match[1];
// ks_c_5601-1987: Korean alias for cp949
case preg_match('`^ks_c_5601-1987`', $charset):
return 'cp949';
// Incorrect, bogus, ambiguous or empty charsets
// ISO-8859-1 is assumed
case preg_match('`^(default|x-user-defined|iso|us-ascii)`', $charset):
case preg_match('`^\s*$`', $charset):
return 'ISO-8859-1';
}
// Hmmmm
return $charset;
}
// Translate characters ($text) from one encoding ($from) to another ($to)
static function transcode($text, $from, $to) {
//Try auto-detecting charset/encoding
if (!$from && function_exists('mb_detect_encoding'))
$from = mb_detect_encoding($text);
// Normalize bogus or ambiguous charsets
$from = self::normalize(trim($from));
$to = self::normalize(trim($to));
$original = $text;
if (function_exists('iconv'))
$text = iconv($from, $to.'//IGNORE', $text);
elseif (function_exists('mb_convert_encoding'))
$text = mb_convert_encoding($text, $to, $from);
elseif (!strcasecmp($to, 'utf-8')
&& function_exists('utf8_encode')
&& !strcasecmp($from, 'ISO-8859-1'))
$text = utf8_encode($text);
// If $text is false, then we have a (likely) invalid charset, use
// the original text and assume 8-bit (latin-1 / iso-8859-1)
// encoding
return (!$text && $original) ? $original : $text;
}
//Wrapper for utf-8 transcoding.
function utf8($text, $charset=null) {
return self::transcode($text, $charset, self::UTF8);
}
}
?>

View File

@@ -37,9 +37,13 @@ abstract class TicketUser {
$tag = substr($name, 3);
switch (strtolower($tag)) {
case 'ticket_link':
return sprintf('%s/view.php?auth=%s',
return sprintf('%s/view.php?%s',
$cfg->getBaseUrl(),
urlencode($this->getAuthToken()));
Http::build_query(
array('auth' => $this->getAuthToken()),
false
)
);
break;
}
@@ -129,8 +133,7 @@ abstract class TicketUser {
}
function isOwner() {
return ($this->user
&& $this->user->getId() == $this->getTicket()->getOwnerId());
return $this instanceof TicketOwner;
}
abstract function getTicketId();

View File

@@ -53,12 +53,15 @@ Class CSRF {
return $this->name;
}
function rotate() {
$this->csrf['token'] = sha1(session_id().Crypto::random(16).SECRET_SALT);
$this->csrf['time'] = time();
}
function getToken() {
if(!$this->csrf['token'] || $this->isExpired()) {
$this->csrf['token'] = sha1(session_id().Crypto::random(16).SECRET_SALT);
$this->csrf['time'] = time();
if (!$this->csrf['token'] || $this->isExpired()) {
$this->rotate();
} else {
//Reset the timer
$this->csrf['time'] = time();

View File

@@ -457,6 +457,7 @@ class DynamicFormEntry extends VerySimpleModel {
var $_form;
var $_errors = false;
var $_clean = false;
var $_source = null;
function getAnswers() {
if (!isset($this->_values)) {
@@ -506,12 +507,21 @@ class DynamicFormEntry extends VerySimpleModel {
function getFields() {
if (!isset($this->_fields)) {
$this->_fields = array();
foreach ($this->getAnswers() as $a)
$this->_fields[] = $a->getField();
foreach ($this->getAnswers() as $a) {
$T = $this->_fields[] = $a->getField();
$T->setForm($this);
}
}
return $this->_fields;
}
function getSource() {
return $this->_source ?: (isset($this->id) ? false : $_POST);
}
function setSource($source) {
$this->_source = $source;
}
function getField($name) {
foreach ($this->getFields() as $field)
@@ -631,8 +641,8 @@ class DynamicFormEntry extends VerySimpleModel {
if (count($this->dirty))
$this->set('updated', new SqlFunction('NOW'));
parent::save();
foreach ($this->getAnswers() as $a) {
$field = $a->getField();
foreach ($this->getFields() as $field) {
$a = $field->getAnswer();
if ($this->object_type == 'U'
&& in_array($field->get('name'), array('name','email')))
continue;
@@ -894,15 +904,20 @@ class SelectionField extends FormField {
function parse($value) {
$config = $this->getConfiguration();
if (is_int($value))
return $this->to_php($this->getWidget()->getEnteredValue(), (int) $value);
$val = $this->to_php($this->getWidget()->getEnteredValue(), (int) $value);
elseif (!$config['typeahead'])
return $this->to_php(null, (int) $value);
else
return $this->to_php($value);
$val = $this->to_php(null, (int) $value);
if (!$val)
$val = $this->to_php($value);
return $val;
}
function to_php($value, $id=false) {
if ($id && is_int($id))
if ($value === null && $id === null)
return null;
if ($value instanceof DynamicListItem)
$item = $value;
elseif ($id && is_int($id))
$item = DynamicListItem::lookup($id);
# Attempt item lookup by name too
if (!$item || ($value !== null && $value != $item->get('value'))) {

View File

@@ -57,8 +57,8 @@ class Export {
$sql = str_replace(' FROM ', ',' . implode(',', $select) . ' FROM ', $sql);
return self::dumpQuery($sql,
array(
'number' => 'Ticket Number',
'created' => 'Date',
'number' => 'Ticket Number',
'ticket_created' => 'Date',
'subject' => 'Subject',
'name' => 'From',
'email' => 'From Email',

View File

@@ -180,9 +180,7 @@ class FAQ {
// Inline images (attached to the draft)
$this->attachments->deleteInlines();
if (isset($vars['draft_id']) && $vars['draft_id'])
if ($draft = Draft::lookup($vars['draft_id']))
$this->attachments->upload($draft->getAttachmentIds(), true);
$this->attachments->upload(Draft::getAttachmentIds($vars['answer']));
$this->reload();

View File

@@ -124,7 +124,7 @@ class Filter {
}
function stopOnMatch() {
return ($this->ht['stop_on_match']);
return ($this->ht['stop_onmatch']);
}
function matchAllRules() {
@@ -716,7 +716,7 @@ class TicketFilter {
$res = $this->getAllActive();
if($res) {
while (list($id) = db_fetch_row($res))
array_push($this->filters, new Filter($id));
$this->filters[] = new Filter($id);
}
return $this->filters;
@@ -742,36 +742,25 @@ class TicketFilter {
return $this->short_list;
}
/**
* Determine if the filters that match the received vars indicate that
* the email should be rejected
*
* Returns FALSE if the email should be acceptable. If the email should
* be rejected, the first filter that matches and has reject ticket set is
* returned.
*/
function shouldReject() {
foreach ($this->getMatchingFilterList() as $filter) {
# Set reject if this filter indicates that the email should
# be blocked; however, don't unset $reject, because if it
# was set by another rule that did not set stopOnMatch(), we
# should still honor its configuration
if ($filter->rejectOnMatch()) return $filter;
}
return false;
}
/**
* Determine if any filters match the received email, and if so, apply
* actions defined in those filters to the ticket-to-be-created.
*
* Throws:
* RejectedException if the email should not be acceptable. If the email
* should be rejected, the first filter that matches and has reject
* ticket set is returned.
*/
function apply(&$ticket) {
foreach ($this->getMatchingFilterList() as $filter) {
if ($filter->rejectOnMatch())
throw new RejectedException($filter);
$filter->apply($ticket, $this->vars);
if ($filter->stopOnMatch()) break;
}
}
/* static */ function getAllActive() {
function getAllActive() {
$sql='SELECT id FROM '.FILTER_TABLE
.' WHERE isactive=1 '
@@ -927,6 +916,19 @@ class TicketFilter {
}
}
class RejectedException extends Exception {
var $filter;
function __construct(Filter $filter) {
parent::__construct('Ticket rejected by a filter');
$this->filter = $filter;
}
function getRejectingFilter() {
return $this->filter;
}
}
/**
* Function: endsWith
*

View File

@@ -14,6 +14,7 @@
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
include_once INCLUDE_DIR.'class.charset.php';
class Format {
@@ -30,52 +31,19 @@ class Format {
return round(($bytes/1048576),1).' mb';
}
/* encode text into desired encoding - taking into accout charset when available. */
function encode($text, $charset=null, $encoding='utf-8') {
//Try auto-detecting charset/encoding
if (!$charset && function_exists('mb_detect_encoding'))
$charset = mb_detect_encoding($text);
// Cleanup - incorrect, bogus, or ambiguous charsets
// ISO-8859-1 is assumed for empty charset.
if (!$charset || in_array(strtolower(trim($charset)),
array('default','x-user-defined','iso','us-ascii')))
$charset = 'ISO-8859-1';
$original = $text;
if (function_exists('iconv'))
$text = iconv($charset, $encoding.'//IGNORE', $text);
elseif (function_exists('mb_convert_encoding'))
$text = mb_convert_encoding($text, $encoding, $charset);
elseif (!strcasecmp($encoding, 'utf-8')
&& function_exists('utf8_encode')
&& !strcasecmp($charset, 'ISO-8859-1'))
$text = utf8_encode($text);
// If $text is false, then we have a (likely) invalid charset, use
// the original text and assume 8-bit (latin-1 / iso-8859-1)
// encoding
return (!$text && $original) ? $original : $text;
}
//Wrapper for utf-8 encoding.
function utf8encode($text, $charset=null) {
return Format::encode($text, $charset, 'utf-8');
}
function mimedecode($text, $encoding='UTF-8') {
if(function_exists('imap_mime_header_decode')
&& ($parts = imap_mime_header_decode($text))) {
$str ='';
foreach ($parts as $part)
$str.= Format::encode($part->text, $part->charset, $encoding);
$str.= Charset::transcode($part->text, $part->charset, $encoding);
$text = $str;
} elseif(function_exists('iconv_mime_decode')) {
} elseif($text[0] == '=' && function_exists('iconv_mime_decode')) {
$text = iconv_mime_decode($text, 0, $encoding);
} elseif(!strcasecmp($encoding, 'utf-8') && function_exists('imap_utf8')) {
} elseif(!strcasecmp($encoding, 'utf-8')
&& function_exists('imap_utf8')) {
$text = imap_utf8($text);
}
@@ -94,7 +62,7 @@ class Format {
$filename, $match))
// XXX: Currently we don't care about the language component.
// The encoding hint is sufficient.
return self::utf8encode(urldecode($match[3]), $match[1]);
return Charset::utf8(urldecode($match[3]), $match[1]);
else
return $filename;
}
@@ -186,7 +154,7 @@ class Format {
$s = str_replace('"','', $s);
}
if ($styles)
$attributes['style'] = Format::htmlencode(implode(';', $styles));
$attributes['style'] = Format::htmlchars(implode(';', $styles));
else
unset($attributes['style']);
}
@@ -243,18 +211,23 @@ class Format {
return $striptags?Format::striptags($text, false):$text;
}
function htmlchars($var) {
return Format::htmlencode($var);
}
function htmlchars($var, $sanitize = false) {
if (is_array($var))
return array_map(array('Format', 'htmlchars'), $var);
if ($sanitize)
$var = Format::sanitize($var);
function htmlencode($var) {
$flags = ENT_COMPAT;
if (phpversion() >= '5.4.0')
$flags |= ENT_HTML401;
return is_array($var)
? array_map(array('Format','htmlencode'), $var)
: htmlentities($var, $flags, 'UTF-8');
try {
return htmlspecialchars( (string) $var, $flags, 'UTF-8', false);
} catch(Exception $e) {
return $var;
}
}
function htmldecode($var) {
@@ -266,11 +239,11 @@ class Format {
if (phpversion() >= '5.4.0')
$flags |= ENT_HTML401;
return html_entity_decode($var, $flags, 'UTF-8');
return htmlspecialchars_decode($var, $flags);
}
function input($var) {
return Format::htmlencode($var);
return Format::htmlchars($var);
}
//Format text for display..
@@ -529,7 +502,7 @@ class Format {
$contents = base64_decode($contents);
}
if ($output_encoding && $charset)
$contents = Format::encode($contents, $charset, $output_encoding);
$contents = Charset::transcode($contents, $charset, $output_encoding);
return array(
'data' => $contents,

View File

@@ -588,6 +588,18 @@ class TextareaField extends FormField {
else
return nl2br(Format::htmlchars($value));
}
function export($value) {
return (!$value) ? $value : Format::html2text($value);
}
function parse($value) {
$config = $this->getConfiguration();
if ($config['html'])
return Format::sanitize($value);
else
return $value;
}
}
class PhoneField extends FormField {
@@ -634,7 +646,9 @@ class PhoneField extends FormField {
function parse($value) {
// NOTE: Value may have a legitimate 'X' to separate the number and
// extension parts. Don't remove the 'X'
return preg_replace('/[^\dX]/', '', $value);
$val = preg_replace('/[^\dX]/', '', $value);
// Pass completely-incorrect string for validation error
return $val ?: $value;
}
function toString($value) {
@@ -997,8 +1011,10 @@ class TextareaWidget extends Widget {
$cols = "cols=\"{$config['cols']}\"";
if (isset($config['length']) && $config['length'])
$maxlength = "maxlength=\"{$config['length']}\"";
if (isset($config['html']) && $config['html'])
if (isset($config['html']) && $config['html']) {
$class = 'class="richtext no-bar small"';
$this->value = Format::viewableImages($this->value);
}
?>
<span style="display:inline-block;width:100%">
<textarea <?php echo $rows." ".$cols." ".$maxlength." ".$class
@@ -1092,13 +1108,13 @@ class CheckboxWidget extends Widget {
function render() {
$config = $this->field->getConfiguration();
?>
<input type="checkbox" name="<?php echo $this->name; ?>[]" <?php
<input style="vertical-align:top;" type="checkbox" name="<?php echo $this->name; ?>[]" <?php
if ($this->value) echo 'checked="checked"'; ?> value="<?php
echo $this->field->get('id'); ?>"/>
<?php
if ($config['desc']) { ?>
<em style="display:inline-block"><?php
echo Format::htmlchars($config['desc']); ?></em>
echo Format::viewableImages($config['desc']); ?></em>
<?php }
}

View File

@@ -111,5 +111,10 @@ class Http {
exit;
}
}
static function build_query($vars, $encode=true, $separator='&amp;') {
return http_build_query(
($encode ? Format::htmlchars($vars) : $vars), '', $separator);
}
}
?>

View File

@@ -25,11 +25,12 @@ class Mailer {
var $ht = array();
var $attachments = array();
var $options = array();
var $smtp = array();
var $eol="\n";
function Mailer($email=null, $options=null) {
function Mailer($email=null, array $options=array()) {
global $cfg;
if(is_object($email) && $email->isSMTPEnabled() && ($info=$email->getSMTPInfo())) { //is SMTP enabled for the current email?
@@ -46,6 +47,7 @@ class Mailer {
$this->email = $email;
$this->attachments = array();
$this->options = $options;
}
function getEOL() {
@@ -114,7 +116,12 @@ class Mailer {
'X-Mailer' =>'osTicket Mailer',
);
if ($this->getEmail() instanceof Email)
// Add in the options passed to the constructor
$options = ($options ?: array()) + $this->options;
if (isset($options['nobounce']) && $options['nobounce'])
$headers['Return-Path'] = '<>';
elseif ($this->getEmail() instanceof Email)
$headers['Return-Path'] = $this->getEmail()->getEmail();
//Bulk.
@@ -148,6 +155,13 @@ class Mailer {
}
}
// Use Mail_mime default initially
$eol = null;
// MAIL_EOL setting can be defined in `ost-config.php`
if (defined('MAIL_EOL') && is_string(MAIL_EOL)) {
$eol = MAIL_EOL;
}
// The Suhosin patch will muck up the line endings in some
// cases
//
@@ -155,12 +169,12 @@ class Mailer {
// https://github.com/osTicket/osTicket-1.8/issues/202
// http://pear.php.net/bugs/bug.php?id=12032
// http://us2.php.net/manual/en/function.mail.php#97680
if ((extension_loaded('suhosin') || defined("SUHOSIN_PATCH"))
&& !$this->getSMTPInfo())
$mime = new Mail_mime("\n");
else
// Use defaults
$mime = new Mail_mime();
elseif ((extension_loaded('suhosin') || defined("SUHOSIN_PATCH"))
&& !$this->getSMTPInfo()
) {
$eol = "\n";
}
$mime = new Mail_mime($eol);
// If the message is not explicitly declared to be a text message,
// then assume that it needs html processing to create a valid text
@@ -169,10 +183,12 @@ class Mailer {
$mid_token = (isset($options['thread']))
? $options['thread']->asMessageId($to) : '';
if (!(isset($options['text']) && $options['text'])) {
if ($cfg && $cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator())
$tag = '';
if ($cfg && $cfg->stripQuotedReply()
&& (!isset($options['reply-tag']) || $options['reply-tag']))
$message = "<div style=\"display:none\"
data-mid=\"$mid_token\">$tag<br/><br/></div>$message";
$tag = $cfg->getReplySeparator() . '<br/><br/>';
$message = "<div style=\"display:none\"
data-mid=\"$mid_token\">$tag</div>$message";
// Make sure nothing unsafe has creeped into the message
$message = Format::safe_html($message); //XXX??
$txtbody = rtrim(Format::html2text($message, 90, false))
@@ -287,7 +303,7 @@ class Mailer {
//Emails using native php mail function - if DB connection doesn't exist.
//Don't use this function if you can help it.
function sendmail($to, $subject, $message, $from) {
$mailer = new Mailer();
$mailer = new Mailer(null, array('notice'=>true, 'nobounce'=>true));
$mailer->setFromAddress($from);
return $mailer->send($to, $subject, $message);
}

View File

@@ -207,7 +207,7 @@ class MailFetcher {
//Convert text to desired encoding..defaults to utf8
function mime_encode($text, $charset=null, $encoding='utf-8') { //Thank in part to afterburner
return Format::encode($text, $charset, $encoding);
return Charset::transcode($text, $charset, $encoding);
}
function mailbox_encode($mailbox) {
@@ -241,7 +241,7 @@ class MailFetcher {
if (function_exists('mb_detect_encoding'))
if (($src_enc = mb_detect_encoding($text))
&& (strcasecmp($src_enc, 'ASCII') !== 0))
return Format::encode($text, $src_enc, $encoding);
return Charset::transcode($text, $src_enc, $encoding);
// Handle ASCII text and RFC-2047 encoding
$str = '';

View File

@@ -320,7 +320,7 @@ class Mail_Parse {
$content = $struct->body;
//Encode to desired encoding - ONLY if charset is known??
if (isset($struct->ctype_parameters['charset']))
$content = Format::encode($content,
$content = Charset::transcode($content,
$struct->ctype_parameters['charset'], $this->charset);
return $content;
@@ -343,7 +343,7 @@ class Mail_Parse {
function mime_encode($text, $charset=null, $encoding='utf-8') {
return Format::encode($text, $charset, $encoding);
return Charset::transcode($text, $charset, $encoding);
}
function getAttachments($part=null){
@@ -498,12 +498,18 @@ class Mail_Parse {
$parsed = Mail_RFC822::parseAddressList($address, null, null,false);
if(PEAR::isError($parsed))
if (PEAR::isError($parsed))
return array();
// Decode name and mailbox
foreach ($parsed as $p) {
$p->personal = Format::mimedecode($p->personal, $this->charset);
// Some mail clients may send ISO-8859-1 strings without proper encoding.
// Also, handle the more sane case where the mailbox is properly encoded
// against RFC2047
$p->mailbox = Format::mimedecode($p->mailbox, $this->charset);
}
return $parsed;
}

View File

@@ -15,14 +15,30 @@
**********************************************************************/
class Misc {
function randCode($count=8, $chars=false) {
$chars = $chars ? $chars
: 'abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.';
$data = '';
$m = strlen($chars) - 1;
for ($i=0; $i < $count; $i++)
$data .= $chars[mt_rand(0,$m)];
return $data;
function randCode($len=8, $chars=false) {
$chars = $chars ?: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_=';
// Determine the number of bits we need
$char_count = strlen($chars);
$bits_per_char = ceil(log($char_count, 2));
$bytes = ceil(4 * $len / floor(32 / $bits_per_char));
// Pad to 4 byte boundary
$bytes += (4 - ($bytes % 4)) % 4;
// Fetch some random data blocks
$data = Crypto::random($bytes);
$mask = (1 << $bits_per_char) - 1;
$loops = (int) (32 / $bits_per_char);
$output = '';
$ints = unpack('V*', $data);
foreach ($ints as $int) {
for ($i = $loops; $i > 0; $i--) {
$output .= $chars[($int & $mask) % $char_count];
$int >>= $bits_per_char;
}
}
return substr($output, 0, $len);
}
function __rand_seed($value=0) {

View File

@@ -885,14 +885,20 @@ class MysqlExecutor {
}
function _prepare() {
$this->execute();
$this->_setup_output();
}
function execute() {
if (!($this->stmt = db_prepare($this->sql)))
throw new Exception('Unable to prepare query: '.db_error()
.' '.$this->sql);
if (count($this->params))
$this->_bind($this->params);
$this->stmt->execute();
$this->_setup_output();
$this->stmt->store_result();
if (!$this->stmt->execute() || ! $this->stmt->store_result()) {
throw new Exception('Unable to execute query: ' . $this->stmt->error);
}
return true;
}
function _bind($params) {

View File

@@ -240,7 +240,7 @@ class osTicket {
$email=$this->getConfig()->getDefaultEmail(); //will take the default email.
if($email) {
$email->sendAlert($to, $subject, $message, null, array('text'=>true));
$email->sendAlert($to, $subject, $message, null, array('text'=>true, 'reply-tag'=>false));
} else {//no luck - try the system mail.
Mailer::sendmail($to, $subject, $message, sprintf('"osTicket Alerts"<%s>',$to));
}

View File

@@ -22,9 +22,7 @@ class osTicketSession {
var $id = '';
function osTicketSession($ttl=0){
$this->ttl =$ttl?$ttl:get_cfg_var('session.gc_maxlifetime');
if(!$this->ttl)
$this->ttl=SESSION_TTL;
$this->ttl = $ttl ?: ini_get('session.gc_maxlifetime') ?: SESSION_TTL;
// Set osTicket specific session name.
session_name('OSTSESSID');
@@ -32,6 +30,9 @@ class osTicketSession {
// Forced cleanup on shutdown
register_shutdown_function('session_write_close');
// Set session cleanup time to match TTL
ini_set('session.gc_maxlifetime', $ttl);
if (OsticketConfig::getDBVersion())
return session_start();
@@ -48,7 +49,7 @@ class osTicketSession {
// Remote port specification, as it will make an invalid domain
list($domain) = explode(':', $_SERVER['HTTP_HOST']);
session_set_cookie_params(86400, ROOT_PATH, $domain,
session_set_cookie_params($ttl, ROOT_PATH, $domain,
osTicket::is_https());
//Set handlers.

View File

@@ -37,14 +37,19 @@ class PageNate {
}
$this->setURL($url);
}
function setURL($url='',$vars=''){
if($url){
if(strpos($url,'?')===false)
$url=$url.'?';
}else{
$url=THISPAGE.'?';
function setURL($url='',$vars='') {
if ($url) {
if (strpos($url, '?')===false)
$url .= '?';
} else {
$url = THISPAGE.'?';
}
$this->url=$url.$vars;
if ($vars && is_array($vars))
$vars = Http::build_query($vars);
$this->url = $url.$vars;
}
function getStart() {

View File

@@ -845,6 +845,19 @@ class Staff extends AuthenticatedUser {
if(!$vars['timezone_id'])
$errors['timezone_id']='Time zone required';
// Ensure we will still have an administrator with access
if ($vars['isadmin'] !== '1' || $vars['isactive'] !== '1') {
$sql = 'select count(*), max(staff_id) from '.STAFF_TABLE
.' WHERE isadmin=1 and isactive=1';
if (($res = db_query($sql))
&& (list($count, $sid) = db_fetch_row($res))) {
if ($count == 1 && $sid == $id) {
$errors['isadmin'] =
'Cowardly refusing to remove or lock out the only active administrator';
}
}
}
if($errors) return false;

View File

@@ -197,10 +197,18 @@ class Thread {
return false;
$this->deleteAttachments();
$this->removeCollaborators();
return true;
}
function removeCollaborators() {
$sql='DELETE FROM '.TICKET_COLLABORATOR_TABLE
.' WHERE ticket_id='.db_input($this->getTicketId());
return (db_query($sql) && db_affected_rows());
}
/* static */
function lookup($ticket) {
@@ -347,14 +355,14 @@ Class ThreadEntry {
return $this->ht['@headers'];
}
function getEmailReferences() {
if (!isset($this->_references)) {
$headers = self::getEmailHeaderArray();
if (isset($headers['References']) && $headers['References'])
$this->_references = $headers['References']." ";
$this->_references .= $this->getEmailMessageId();
}
return $this->_references;
function getEmailReferences($include_mid=true) {
$references = '';
$headers = self::getEmailHeaderArray();
if (isset($headers['References']) && $headers['References'])
$references = $headers['References']." ";
if ($include_mid)
$references .= $this->getEmailMessageId();
return $references;
}
function getTaggedEmailReferences($prefix, $refId) {
@@ -364,7 +372,7 @@ Class ThreadEntry {
$mid = substr_replace($this->getEmailMessageId(),
$ref, strpos($this->getEmailMessageId(), '@'), 0);
return sprintf('%s %s', $this->getEmailReferences(), $mid);
return sprintf('%s %s', $this->getEmailReferences(false), $mid);
}
function getEmailReferencesForUser($user) {
@@ -418,11 +426,11 @@ Class ThreadEntry {
if (!($ticket = $this->getTicket()))
return null;
if ($ticket->getOwnerId() == $ticket->getUserId())
if ($ticket->getOwnerId() == $this->getUserId())
$this->user = new TicketOwner(
User::lookup($this->getUserId()), $ticket);
else
$this->user = Collborator::lookup(array(
$this->user = Collaborator::lookup(array(
'userId'=>$this->getUserId(), 'ticketId'=>$this->getTicketId()));
}
@@ -834,7 +842,7 @@ Class ThreadEntry {
return ThreadEntry::lookup($id);
}
foreach (array('mid', 'in-reply-to', 'references') as $header) {
foreach (array('in-reply-to', 'references') as $header) {
$matches = array();
if (!isset($mailinfo[$header]) || !$mailinfo[$header])
continue;
@@ -848,6 +856,7 @@ Class ThreadEntry {
// (parent) on the far right.
// @see rfc 1036, section 2.2.5
// @see http://www.jwz.org/doc/threading.html
$thread = null;
foreach (array_reverse($matches[0]) as $mid) {
//Try to determine if it's a reply to a tagged email.
$ref = null;
@@ -858,20 +867,29 @@ Class ThreadEntry {
}
$res = db_query(sprintf($search, db_input($mid)));
while (list($id) = db_fetch_row($res)) {
if (!($t = ThreadEntry::lookup($id))) continue;
//We found a match - see if we can ID the user.
if (!($t = ThreadEntry::lookup($id)))
continue;
// Capture the first match thread item
if (!$thread)
$thread = $t;
// We found a match - see if we can ID the user.
// XXX: Check access of ref is enough?
if ($ref && ($uid = $t->getUIDFromEmailReference($ref))) {
if ($ref[0] =='s') //staff
$mailinfo['staffId'] = $uid;
else //user or collaborator.
else // user or collaborator.
$mailinfo['userId'] = $uid;
}
return $t;
// Best possible case — found the thread and the
// user
return $t;
}
}
}
// Second best case — found a thread but couldn't identify the
// user from the header. Return the first thread entry matched
if ($thread)
return $thread;
}
// Search for ticket by the [#123456] in the subject line

View File

@@ -1035,7 +1035,7 @@ class Ticket {
$options = array('inreplyto' => $entry->getEmailMessageId(),
'thread' => $entry);
foreach ($recipients as $recipient) {
if ($uid == $recipient->getId()) continue;
if ($uid == $recipient->getUserId()) continue;
$options['references'] = $entry->getEmailReferencesForUser($recipient);
$notice = $this->replaceVars($msg, array('recipient' => $recipient));
$email->send($recipient->getEmail(), $notice['subj'], $notice['body'], $attachments,
@@ -1069,7 +1069,11 @@ class Ticket {
}
// Reopen if closed.
if($this->isClosed()) $this->reopen();
// We're also checking autorespond flag because we don't want to
// reopen closed tickets on auto-reply from end user. This is not to
// confused with autorespond on new message setting
if ($autorespond && $this->isClosed())
$this->reopen();
/********** double check auto-response ************/
if (!($user = $message->getUser()))
@@ -1267,10 +1271,10 @@ class Ticket {
return $duedate;
break;
case 'close_date';
case 'close_date':
$closedate ='';
if($this->isClosed())
$duedate = Format::date(
$closedate = Format::date(
$cfg->getDateTimeFormat(),
Misc::db2gmtime($this->getCloseDate()),
$cfg->getTZOffset(),
@@ -1675,7 +1679,11 @@ class Ticket {
$signature='';
$msg = $this->replaceVars($msg->asArray(),
array('response' => $response, 'signature' => $signature));
array(
'response' => $response,
'signature' => $signature,
'recipient' => $this->getOwner(),
));
$attachments =($cfg->emailAttachments() && $files)?$response->getAttachments():array();
$options = array(
@@ -2160,7 +2168,8 @@ class Ticket {
*
* $autorespond and $alertstaff overrides config settings...
*/
function create($vars, &$errors, $origin, $autorespond=true, $alertstaff=true) {
static function create($vars, &$errors, $origin, $autorespond=true,
$alertstaff=true) {
global $ost, $cfg, $thisclient, $_FILES;
// Don't enforce form validation for email
@@ -2247,22 +2256,6 @@ class Ticket {
}
}
//Init ticket filters...
$ticket_filter = new TicketFilter($origin, $vars);
// Make sure email contents should not be rejected
if($ticket_filter
&& ($filter=$ticket_filter->shouldReject())) {
$errors = array(
'errno' => 403,
'err' => "This help desk is for use by authorized users
only");
$ost->logWarning('Ticket denied',
sprintf('Ticket rejected ( %s) by filter "%s"',
$vars['email'], $filter->getName()), true);
return 0;
}
$id=0;
$fields=array();
$fields['message'] = array('type'=>'*', 'required'=>1, 'error'=>'Message required');
@@ -2301,7 +2294,21 @@ class Ticket {
if (!$errors) {
# Perform ticket filter actions on the new ticket arguments
if ($ticket_filter) $ticket_filter->apply($vars);
try {
// Init ticket filters...
$ticket_filter = new TicketFilter($origin, $vars);
$ticket_filter->apply($vars);
}
catch (RejectedException $ex) {
$errors = array(
'errno' => 403,
'err' => "This help desk is for use by authorized users only");
$ost->logWarning('Ticket denied',
sprintf('Ticket rejected ( %s) by filter "%s"',
$vars['email'], $ex->getRejectingFilter()->getName()), true);
return 0;
}
// Allow vars to be changed in ticket filter and applied to the user
// account created or detected
@@ -2423,7 +2430,8 @@ class Ticket {
if ($vars['staffId'])
$ticket->assignToStaff($vars['staffId'], 'Auto Assignment');
if ($vars['teamId'])
$ticket->assignToTeam($vars['teamId'], 'Auto Assignment');
$ticket->assignToTeam($vars['teamId'], 'Auto Assignment',
!$vars['staffId']);
}
/********** double check auto-response ************/
@@ -2494,7 +2502,8 @@ class Ticket {
if (!$thisstaff->canAssignTickets())
unset($vars['assignId']);
if(!($ticket=Ticket::create($vars, $errors, 'staff', false)))
$create_vars = $vars;
if(!($ticket=Ticket::create($create_vars, $errors, 'staff', false)))
return false;
$vars['msgId']=$ticket->getLastMsgId();

View File

@@ -145,7 +145,7 @@ class User extends UserModel {
$info = array(
'id' => $this->getId(),
'name' => (string) $this->getName(),
'name' => Format::htmlchars($this->getName()),
'email' => (string) $this->getEmail(),
'phone' => (string) $this->getPhoneNumber());
@@ -187,7 +187,7 @@ class User extends UserModel {
$this->_entries[] = $g;
}
}
return $this->_entries;
return $this->_entries ?: array();
}
function getForms($data=null) {

View File

@@ -14,9 +14,9 @@ $category=$faq->getCategory();
</div>
<div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"></div>
<div class="clear"></div>
<p>
<div class="thread-body">
<?php echo Format::safe_html($faq->getAnswerWithImages()); ?>
</p>
</div>
<p>
<?php
if($faq->getNumAttachments()) { ?>

View File

@@ -1,10 +1,10 @@
<?php
if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid() || !$cfg->showRelatedTickets()) die('Access Denied');
$qstr='&'; //Query string collector
$qs = array();
$status=null;
if(isset($_REQUEST['status'])) { //Query string status has nothing to do with the real status used below.
$qstr.='status='.urlencode($_REQUEST['status']);
$qs += array('status' => $_REQUEST['status']);
//Status we are actually going to use on the query...making sure it is clean!
switch(strtolower($_REQUEST['status'])) {
case 'open':
@@ -64,7 +64,7 @@ if($status){
$search=($_REQUEST['a']=='search' && $_REQUEST['q']);
if($search) {
$qstr.='&a='.urlencode($_REQUEST['a']).'&q='.urlencode($_REQUEST['q']);
$qs += array('a' => $_REQUEST['a'], 'q' => $_REQUEST['q']);
if(is_numeric($_REQUEST['q'])) {
$qwhere.=" AND ticket.`number` LIKE '$queryterm%'";
} else {//Deep search!
@@ -83,7 +83,9 @@ if($search) {
$total=db_count('SELECT count(DISTINCT ticket.ticket_id) '.$qfrom.' '.$qwhere);
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('tickets.php', $qs);
//more stuff...
$qselect.=' ,count(attach_id) as attachments ';

View File

@@ -448,6 +448,11 @@ class HtmlAElement extends HtmlInlineElement {
$href = substr($href, 7);
$output = (($href != $output) ? "$href " : '') . "<$output>";
} elseif (mb_strwidth($href) > $width / 2) {
if (mb_strwidth($output) > $width / 2) {
// Parse URL and use relative path part
if ($PU = parse_url($output))
$output = $PU['host'] . $PU['path'];
}
if ($href != $output)
$id = $this->getRoot()->addFootnote($output, $href);
$output = "[$output][$id]";

View File

@@ -16,19 +16,6 @@
$Id: $
**********************************************************************/
/**
* If you have a strange HTTP server configuration and osTicket cannot
* discover the URL path of where your osTicket is installed, define
* ROOT_PATH here.
*
* The ROOT_PATH is the part of the URL used to access your osTicket
* helpdesk before the '/scp' part and after the hostname. For instance, for
* http://mycompany.com/support', the ROOT_PATH should be '/support/'
*
* ROOT_PATH *must* end with a forward-slash!
*/
# define('ROOT_PATH', '/support/');
#Disable direct access.
if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__)) || !defined('INCLUDE_DIR'))
die('kwaheri rafiki!');
@@ -48,13 +35,19 @@ define('SECRET_SALT','%CONFIG-SIRI');
#Default admin email. Used only on db connection issues and related alerts.
define('ADMIN_EMAIL','%ADMIN-EMAIL');
#Mysql Login info
# Database Options
# ---------------------------------------------------
# Mysql Login info
define('DBTYPE','mysql');
define('DBHOST','%CONFIG-DBHOST');
define('DBNAME','%CONFIG-DBNAME');
define('DBUSER','%CONFIG-DBUSER');
define('DBPASS','%CONFIG-DBPASS');
# Table prefix
define('TABLE_PREFIX','%CONFIG-PREFIX');
#
# SSL Options
# ---------------------------------------------------
# SSL options for MySQL can be enabled by adding a certificate allowed by
@@ -75,7 +68,42 @@ define('DBPASS','%CONFIG-DBPASS');
# define('DBSSLCERT','/path/to/client.crt');
# define('DBSSLKEY','/path/to/client.key');
#Table prefix
define('TABLE_PREFIX','%CONFIG-PREFIX');
#
# Mail Options
# ---------------------------------------------------
# Option: MAIL_EOL (default: \r\n)
#
# Some mail setups do not handle emails with \r\n (CRLF) line endings for
# headers and base64 and quoted-response encoded bodies. This is an error
# and a violation of the internet mail RFCs. However, because this is also
# outside the control of both osTicket development and many server
# administrators, this option can be adjusted for your setup. Many folks who
# experience blank or garbled email from osTicket can adjust this setting to
# use "\n" (LF) instead of the CRLF default.
#
# References:
# http://www.faqs.org/rfcs/rfc2822.html
# https://github.com/osTicket/osTicket-1.8/issues/202
# https://github.com/osTicket/osTicket-1.8/issues/700
# https://github.com/osTicket/osTicket-1.8/issues/759
# https://github.com/osTicket/osTicket-1.8/issues/1217
# define(MAIL_EOL, "\n");
#
# HTTP Server Options
# ---------------------------------------------------
# Option: ROOT_PATH (default: <auto detect>, fallback: /)
#
# If you have a strange HTTP server configuration and osTicket cannot
# discover the URL path of where your osTicket is installed, define
# ROOT_PATH here.
#
# The ROOT_PATH is the part of the URL used to access your osTicket
# helpdesk before the '/scp' part and after the hostname. For instance, for
# http://mycompany.com/support', the ROOT_PATH should be '/support/'
#
# ROOT_PATH *must* end with a forward-slash!
# define('ROOT_PATH', '/support/');
?>

View File

@@ -1,23 +1,23 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info=$qs = array();
if($api && $_REQUEST['a']!='add'){
$title='Update API Key';
$action='update';
$submit_text='Save Changes';
$info=$api->getHashtable();
$qstr.='&id='.$api->getId();
$qs += array('id' => $api->getId());
}else {
$title='Add New API Key';
$action='add';
$submit_text='Add Key';
$info['isactive']=isset($info['isactive'])?$info['isactive']:1;
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="apikeys.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="apikeys.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT * FROM '.API_KEY_TABLE.' WHERE 1';
$sortOptions=array('key'=>'apikey','status'=>'isactive','ip'=>'ipaddr','date'=>'created','created'=>'created','updated'=>'updated');
$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
@@ -27,9 +27,11 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.API_KEY_TABLE.' ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total,$page,PAGE_LIMIT);
$pageNav->setURL('apikeys.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('apikeys.php', $qs);
$qstr.='&amp;order='.($order=='DESC'?'ASC':'DESC');
$query="$sql ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$filter) die('Access Denied');
$qstr='';
$qs = array();
$select='SELECT rule.* ';
$from='FROM '.FILTER_RULE_TABLE.' rule ';
$where='WHERE rule.filter_id='.db_input($filter->getId());
@@ -41,8 +41,10 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(DISTINCT rule.id) '.$from.' '.$where);
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('banlist.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('banlist.php', $qs);
$qstr.='&amp;order='.($order=='DESC'?'ASC':'DESC');
$query="$select $from $where ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
//echo $query;
?>

View File

@@ -1,25 +1,25 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info=$qs= array();
if($rule && $_REQUEST['a']!='add'){
$title='Update Ban Rule';
$action='update';
$submit_text='Update';
$info=$rule->getInfo();
$info['id']=$rule->getId();
$qstr.='&id='.$rule->getId();
$qs += array('id' => $rule->getId());
}else {
$title='Add New Email Address to Ban List';
$action='add';
$submit_text='Add';
$info['isactive']=isset($info['isactive'])?$info['isactive']:1;
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="banlist.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="banlist.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,14 +1,13 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
$info=array();
$qstr='';
$info=$qs = array();
if($canned && $_REQUEST['a']!='add'){
$title='Update Canned Response';
$action='update';
$submit_text='Save Changes';
$info=$canned->getInfo();
$info['id']=$canned->getId();
$qstr.='&id='.$canned->getId();
$qs += array('id' => $canned->getId());
// Replace cid: scheme with downloadable URL for inline images
$info['response'] = $canned->getResponseWithImages();
$info['notes'] = Format::viewableImages($info['notes']);
@@ -17,12 +16,12 @@ if($canned && $_REQUEST['a']!='add'){
$action='create';
$submit_text='Add Response';
$info['isenabled']=isset($info['isenabled'])?$info['isenabled']:1;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="canned.php?<?php echo $qstr; ?>" method="post" id="save" enctype="multipart/form-data">
<form action="canned.php?<?php echo Http::build_query($qs); ?>" method="post" id="save" enctype="multipart/form-data">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT canned.*, count(attach.file_id) as files, dept.dept_name as department '.
' FROM '.CANNED_TABLE.' canned '.
' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=canned.dept_id) '.
@@ -36,9 +36,11 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.CANNED_TABLE.' canned ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('canned.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('canned.php', $qs);
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr .= '&order='.($order=='DESC'?'ASC':'DESC');
$query="$sql GROUP BY canned.canned_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT cat.category_id, cat.name, cat.ispublic, cat.updated, count(faq.faq_id) as faqs '.
' FROM '.FAQ_CATEGORY_TABLE.' cat '.
' LEFT JOIN '.FAQ_TABLE.' faq ON (faq.category_id=cat.category_id) ';
@@ -30,8 +30,9 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.FAQ_CATEGORY_TABLE.' cat ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('categories.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('categories.php', $qs);
$qstr = '&amp;order='.($order=='DESC'?'ASC':'DESC');
$query="$sql GROUP BY cat.category_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canManageFAQ()) die('Access Denied');
$info=array();
$qstr='';
$qs = array();
if($category && $_REQUEST['a']!='add'){
$title='Update Category: '.$category->getName();
$action='update';
@@ -9,17 +9,17 @@ if($category && $_REQUEST['a']!='add'){
$info=$category->getHashtable();
$info['id']=$category->getId();
$info['notes'] = Format::viewableImages($category->getNotes());
$qstr.='&id='.$category->getId();
$qs += array('id' => $category->getId());
}else {
$title='Add New Category';
$action='create';
$submit_text='Add';
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="categories.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="categories.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($dept && $_REQUEST['a']!='add') {
//Editing Department.
$title='Update Department';
@@ -10,8 +9,7 @@ if($dept && $_REQUEST['a']!='add') {
$info=$dept->getInfo();
$info['id']=$dept->getId();
$info['groups'] = $dept->getAllowedGroups();
$qstr.='&id='.$dept->getId();
$qs += array('id' => $dept->getId());
} else {
$title='Add New Department';
$action='create';
@@ -22,11 +20,11 @@ if($dept && $_REQUEST['a']!='add') {
if (!isset($info['group_membership']))
$info['group_membership'] = 1;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="departments.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="departments.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT dept.dept_id,dept_name,email.email_id,email.email,email.name as email_name,ispublic,count(staff.staff_id) as users '.
',CONCAT_WS(" ",mgr.firstname,mgr.lastname) as manager,mgr.staff_id as manager_id,dept.created,dept.updated FROM '.DEPT_TABLE.' dept '.
' LEFT JOIN '.STAFF_TABLE.' mgr ON dept.manager_id=mgr.staff_id '.
@@ -30,7 +30,8 @@ $x=$sort.'_sort';
$$x=' class="'.strtolower($order).'" ';
$order_by="$order_column $order ";
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qs += array('order' => ($order=='DESC' ? 'ASC' : 'DESC'));
$qstr = '&amp;'. Http::build_query($qs);
$query="$sql GROUP BY dept.dept_id ORDER BY $order_by";
$res=db_query($query);

View File

@@ -1,6 +1,6 @@
<?php
if(!defined('OSTSTAFFINC') || !$thisstaff || !$thisstaff->isStaff()) die('Access Denied');
$qstr='';
$qs = array();
$select='SELECT staff.*,CONCAT_WS(" ",firstname,lastname) as name,dept.dept_name as dept ';
$from='FROM '.STAFF_TABLE.' staff '.
'LEFT JOIN '.DEPT_TABLE.' dept ON(staff.dept_id=dept.dept_id) ';
@@ -25,7 +25,7 @@ if($_REQUEST['q']) {
if($_REQUEST['did'] && is_numeric($_REQUEST['did'])) {
$where.=' AND staff.dept_id='.db_input($_REQUEST['did']);
$qstr.='&did='.urlencode($_REQUEST['did']);
$qs += array('did' => $_REQUEST['did']);
}
$sortOptions=array('name'=>'staff.firstname,staff.lastname','email'=>'staff.email','dept'=>'dept.dept_name',
@@ -54,9 +54,11 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where);
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('directory.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('directory.php', $qs);
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr.='&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$select $from $where GROUP BY staff.staff_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
//echo $query;
?>

View File

@@ -2,7 +2,7 @@
$info=array();
if($form && $_REQUEST['a']!='add') {
$title = 'Update custom form section';
$title = 'Update form section';
$action = 'update';
$url = "?id=".urlencode($_REQUEST['id']);
$submit_text='Save Changes';
@@ -23,14 +23,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo $action; ?>">
<input type="hidden" name="id" value="<?php echo $info['id']; ?>">
<h2>Custom Form</h2>
<h2><?php echo $form ? Format::htmlchars($form->getTitle()) : 'Custom Form'; ?></h2>
<table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
<thead>
<tr>
<th colspan="2">
<h4><?php echo $title; ?></h4>
<em>Custom forms are used to allow custom data to be
associated with tickets</em>
<em>Forms are used to allow for collection of custom
data</em>
</th>
</tr>
</thead>

View File

@@ -59,7 +59,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
$page = ($_GET['p'] && is_numeric($_GET['p'])) ? $_GET['p'] : 1;
$count = $list->getItemCount();
$pageNav = new Pagenate($count, $page, PAGE_LIMIT);
$pageNav->setURL('dynamic-list.php', 'id='.urlencode($_REQUEST['id']));
$pageNav->setURL('dynamic-list.php', array('id' => $list->getId()));
$showing=$pageNav->showing().' list items';
?>
<?php }

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($email && $_REQUEST['a']!='add'){
$title='Update Email';
$action='update';
@@ -17,7 +16,7 @@ if($email && $_REQUEST['a']!='add'){
if($info['userpass'])
$passwdtxt='To change password enter new password above.';
$qstr.='&id='.$email->getId();
$qs += array('id' => $email->getId());
}else {
$title='Add New Email';
$action='create';
@@ -25,12 +24,12 @@ if($email && $_REQUEST['a']!='add'){
$info['ispublic']=isset($info['ispublic'])?$info['ispublic']:1;
$info['ticket_auto_response']=isset($info['ticket_auto_response'])?$info['ticket_auto_response']:1;
$info['message_auto_response']=isset($info['message_auto_response'])?$info['message_auto_response']:1;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<h2>Email Address</h2>
<form action="emails.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="emails.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT email.*,dept.dept_name as department,priority_desc as priority '.
' FROM '.EMAIL_TABLE.' email '.
' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=email.dept_id) '.
@@ -31,9 +31,9 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.EMAIL_TABLE.' email ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('emails.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('emails.php', $qs);
$qstr = '&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$sql GROUP BY email.email_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canManageFAQ()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($faq){
$title='Update FAQ: '.$faq->getQuestion();
$action='update';
@@ -11,18 +10,19 @@ if($faq){
$info['topics']=$faq->getHelpTopicsIds();
$info['answer']=Format::viewableImages($faq->getAnswer());
$info['notes']=Format::viewableImages($faq->getNotes());
$qstr='id='.$faq->getId();
$qs += array('id' => $faq->getId());
}else {
$title='Add New FAQ';
$action='create';
$submit_text='Add FAQ';
if($category) {
$qstr='cid='.$category->getId();
$qs += array('cid' => $category->getId());
$info['category_id']=$category->getId();
}
}
//TODO: Add attachment support.
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
$qstr = Http::build_query($qs);
?>
<form action="faq.php?<?php echo $qstr; ?>" method="post" id="save" enctype="multipart/form-data">
<?php csrf_token(); ?>

View File

@@ -4,25 +4,24 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access
$matches=Filter::getSupportedMatches();
$match_types=Filter::getSupportedMatchTypes();
$info=array();
$qstr='';
$info = $qs = array();
if($filter && $_REQUEST['a']!='add'){
$title='Update Filter';
$action='update';
$submit_text='Save Changes';
$info=array_merge($filter->getInfo(),$filter->getFlatRules());
$info['id']=$filter->getId();
$qstr.='&id='.$filter->getId();
$qs += array('id' => $filter->getId());
}else {
$title='Add New Filter';
$action='add';
$submit_text='Add Filter';
$info['isactive']=isset($info['isactive'])?$info['isactive']:0;
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="filters.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="filters.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$targets = Filter::getTargets();
$qstr='';
$qs = array();
$sql='SELECT filter.*,count(rule.id) as rules '.
'FROM '.FILTER_TABLE.' filter '.
'LEFT JOIN '.FILTER_RULE_TABLE.' rule ON(rule.filter_id=filter.id) '.
@@ -31,9 +31,10 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.FILTER_TABLE.' filter ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('filters.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('filters.php', $qs);
$qstr.='&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$sql ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))
@@ -47,7 +48,7 @@ else
<h2>Ticket Filters</h2>
</div>
<div style="float:right;text-align:right;padding-top:5px;padding-right:5px;">
<b><a href="filters.php?a=add" class="Icon newEmailFilter">Add New Filter</a></b></div>
<b><a href="filters.php?a=add" class="Icon newTicketFilter">Add New Filter</a></b></div>
<div class="clear"></div>
<form action="filters.php" method="POST" name="filters">
<?php csrf_token(); ?>
@@ -57,7 +58,7 @@ else
<caption><?php echo $showing; ?></caption>
<thead>
<tr>
<th width="7">&nbsp;</th>
<th width="7">&nbsp;</th>
<th width="320"><a <?php echo $name_sort; ?> href="filters.php?<?php echo $qstr; ?>&sort=name">Name</a></th>
<th width="80"><a <?php echo $status_sort; ?> href="filters.php?<?php echo $qstr; ?>&sort=status">Status</a></th>
<th width="80" style="text-align:center;"><a <?php echo $order_sort; ?> href="filters.php?<?php echo $qstr; ?>&sort=order">Order</a></th>
@@ -79,7 +80,7 @@ else
?>
<tr id="<?php echo $row['id']; ?>">
<td width=7px>
<input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['id']; ?>"
<input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['id']; ?>"
<?php echo $sel?'checked="checked"':''; ?>>
</td>
<td>&nbsp;<a href="filters.php?id=<?php echo $row['id']; ?>"><?php echo Format::htmlchars($row['name']); ?></a></td>

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($group && $_REQUEST['a']!='add'){
$title='Update Group';
$action='update';
@@ -9,18 +8,18 @@ if($group && $_REQUEST['a']!='add'){
$info=$group->getInfo();
$info['id']=$group->getId();
$info['depts']=$group->getDepartments();
$qstr.='&id='.$group->getId();
$qs += array('id' => $group->getId());
}else {
$title='Add New Group';
$action='create';
$submit_text='Create Group';
$info['isactive']=isset($info['isactive'])?$info['isactive']:1;
$info['can_create_tickets']=isset($info['can_create_tickets'])?$info['can_create_tickets']:1;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="groups.php?<?php echo $qstr; ?>" method="post" id="save" name="group">
<form action="groups.php?<?php echo Http::build_query($qs); ?>" method="post" id="save" name="group">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,8 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT grp.*,count(DISTINCT staff.staff_id) as users, count(DISTINCT dept.dept_id) as depts '
.' FROM '.GROUP_TABLE.' grp '
.' LEFT JOIN '.STAFF_TABLE.' staff ON(staff.group_id=grp.group_id) '
@@ -30,7 +29,7 @@ $x=$sort.'_sort';
$$x=' class="'.strtolower($order).'" ';
$order_by="$order_column $order ";
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qs += array('order' => ($order=='DESC' ? 'ASC' : 'DESC'));
$query="$sql GROUP BY grp.group_id ORDER BY $order_by";
$res=db_query($query);
if($res && ($num=db_num_rows($res)))
@@ -38,6 +37,9 @@ if($res && ($num=db_num_rows($res)))
else
$showing='No groups found!';
$qstr = '&amp;'.Http::build_query($qs);
?>
<div style="width:700px;padding-top:5px; float:left;">
<h2>User Groups</h2>

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($topic && $_REQUEST['a']!='add') {
$title='Update Help Topic';
$action='update';
@@ -9,18 +8,18 @@ if($topic && $_REQUEST['a']!='add') {
$info=$topic->getInfo();
$info['id']=$topic->getId();
$info['pid']=$topic->getPid();
$qstr.='&id='.$topic->getId();
$qs += array('id' => $topic->getId());
} else {
$title='Add New Help Topic';
$action='create';
$submit_text='Add Topic';
$info['isactive']=isset($info['isactive'])?$info['isactive']:1;
$info['ispublic']=isset($info['ispublic'])?$info['ispublic']:1;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="helptopics.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="helptopics.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -6,8 +6,7 @@ $pageTypes = array(
'thank-you' => 'Thank you page',
'other' => 'Other',
);
$info=array();
$qstr='';
$info = $qs = array();
if($page && $_REQUEST['a']!='add'){
$title='Update Page';
$action='update';
@@ -16,17 +15,17 @@ if($page && $_REQUEST['a']!='add'){
$info['body'] = Format::viewableImages($page->getBody());
$info['notes'] = Format::viewableImages($info['notes']);
$slug = Format::slugify($info['name']);
$qstr.='&id='.$page->getId();
$qs += array('id' => $page->getId());
}else {
$title='Add New Page';
$action='add';
$submit_text='Add Page';
$info['isactive']=isset($info['isactive'])?$info['isactive']:0;
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="pages.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="pages.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT page.id, page.isactive, page.name, page.created, page.updated, '
.'page.type, count(topic.topic_id) as topics '
.' FROM '.PAGE_TABLE.' page '
@@ -36,9 +36,11 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.PAGE_TABLE.' page ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('pages.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('pages.php', $qs);
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr .= '&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$sql GROUP BY page.id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -12,10 +12,11 @@ if($plugin && $_REQUEST['a']!='add') {
$submit_text='Save Changes';
$info = $plugin->ht;
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
$info = Format::htmlchars(($errors && $_POST) ? $_POST : $info);
?>
<form action="?id=<?php echo urlencode($_REQUEST['id']); ?>" method="post" id="save">
<form action="?<?php echo Http::build_query(array('id' => $_REQUEST['id'])); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="id" value="<?php echo $info['id']; ?>">

View File

@@ -1,14 +1,13 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($sla && $_REQUEST['a']!='add'){
$title='Update SLA Plan';
$action='update';
$submit_text='Save Changes';
$info=$sla->getInfo();
$info['id']=$sla->getId();
$qstr.='&id='.$sla->getId();
$qs += array('id' => $sla->getId());
}else {
$title='Add New SLA Plan';
$action='add';
@@ -16,11 +15,11 @@ if($sla && $_REQUEST['a']!='add'){
$info['isactive']=isset($info['isactive'])?$info['isactive']:1;
$info['enable_priority_escalation']=isset($info['enable_priority_escalation'])?$info['enable_priority_escalation']:1;
$info['disable_overdue_alerts']=isset($info['disable_overdue_alerts'])?$info['disable_overdue_alerts']:0;
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="slas.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="slas.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT * FROM '.SLA_TABLE.' sla WHERE 1';
$sortOptions=array('name'=>'sla.name','status'=>'sla.isactive','period'=>'sla.grace_period','date'=>'sla.created','updated'=>'sla.updated');
$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
@@ -27,9 +27,12 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.SLA_TABLE.' sla ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('slas.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('slas.php', $qs);
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr .= '&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$sql ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,8 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($staff && $_REQUEST['a']!='add'){
//Editing Department.
$title='Update Staff';
@@ -12,7 +11,7 @@ if($staff && $_REQUEST['a']!='add'){
$info=$staff->getInfo();
$info['id']=$staff->getId();
$info['teams'] = $staff->getTeams();
$qstr.='&id='.$staff->getId();
$qs += array('id' => $staff->getId());
}else {
$title='Add New Staff';
$action='create';
@@ -23,11 +22,11 @@ if($staff && $_REQUEST['a']!='add'){
$info['isactive']=1;
$info['isvisible']=1;
$info['isadmin']=0;
$qstr.='&a=add';
$qs += array('a' => 'add');
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="staff.php?<?php echo $qstr; ?>" method="post" id="save" autocomplete="off">
<form action="staff.php?<?php echo Http::build_query($qs); ?>" method="post" id="save" autocomplete="off">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,6 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$select='SELECT staff.*,CONCAT_WS(" ",firstname,lastname) as name, grp.group_name, dept.dept_name as dept,count(m.team_id) as teams ';
$from='FROM '.STAFF_TABLE.' staff '.
'LEFT JOIN '.GROUP_TABLE.' grp ON(staff.group_id=grp.group_id) '.
@@ -10,17 +10,17 @@ $where='WHERE 1 ';
if($_REQUEST['did'] && is_numeric($_REQUEST['did'])) {
$where.=' AND staff.dept_id='.db_input($_REQUEST['did']);
$qstr.='&did='.urlencode($_REQUEST['did']);
$qs += array('did' => $_REQUEST['did']);
}
if($_REQUEST['gid'] && is_numeric($_REQUEST['gid'])) {
$where.=' AND staff.group_id='.db_input($_REQUEST['gid']);
$qstr.='&gid='.urlencode($_REQUEST['gid']);
$qs += array('gid' => $_REQUEST['gid']);
}
if($_REQUEST['tid'] && is_numeric($_REQUEST['tid'])) {
$where.=' AND m.team_id='.db_input($_REQUEST['tid']);
$qstr.='&tid='.urlencode($_REQUEST['tid']);
$qs += array('tid' => $_REQUEST['tid']);
}
$sortOptions=array('name'=>'staff.firstname,staff.lastname','username'=>'staff.username','status'=>'isactive',
@@ -48,9 +48,11 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where);
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total,$page,PAGE_LIMIT);
$pageNav->setURL('staff.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('staff.php', $qs);
$qstr .= '&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$select $from $where GROUP BY staff.staff_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
//echo $query;
?>

View File

@@ -1,9 +1,9 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
if($_REQUEST['type']) {
$qstr.='&amp;type='.urlencode($_REQUEST['type']);
$qs += array('type' => $_REQUEST['type']);
}
$type=null;
switch(strtolower($_REQUEST['type'])){
@@ -38,11 +38,11 @@ if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)){
}else{
if($startTime){
$qwhere.=' AND created>=FROM_UNIXTIME('.$startTime.')';
$qstr.='&startDate='.urlencode($_REQUEST['startDate']);
$qs += array('startDate' => $_REQUEST['startDate']);
}
if($endTime){
$qwhere.=' AND created<=FROM_UNIXTIME('.$endTime.')';
$qstr.='&endDate='.urlencode($_REQUEST['endDate']);
$qs += array('endDate' => $_REQUEST['endDate']);
}
}
$sortOptions=array('id'=>'log.log_id', 'title'=>'log.title','type'=>'log_type','ip'=>'log.ip_address'
@@ -73,8 +73,9 @@ $total=db_count("SELECT count(*) $qfrom $qwhere");
$page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
//pagenate
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('logs.php',$qstr);
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$pageNav->setURL('logs.php',$qs);
$qs += array('order' => ($order=='DESC' ? 'ASC' : 'DESC'));
$qstr = '&amp;'. Http::build_query($qs);
$query="$qselect $qfrom $qwhere ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -1,7 +1,6 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($team && $_REQUEST['a']!='add'){
//Editing Team
$title='Update Team';
@@ -9,18 +8,18 @@ if($team && $_REQUEST['a']!='add'){
$submit_text='Save Changes';
$info=$team->getInfo();
$info['id']=$team->getId();
$qstr.='&id='.$team->getId();
$qs += array('id' => $team->getId());
}else {
$title='Add New Team';
$action='create';
$submit_text='Create Team';
$info['isenabled']=1;
$info['noalerts']=0;
$qstr.='&a='.$_REQUEST['a'];
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="teams.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="teams.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT team.*,count(m.staff_id) as members,CONCAT_WS(" ",lead.firstname,lead.lastname) as team_lead '.
' FROM '.TEAM_TABLE.' team '.
' LEFT JOIN '.TEAM_MEMBER_TABLE.' m ON(m.team_id=team.team_id) '.
@@ -28,7 +28,8 @@ $x=$sort.'_sort';
$$x=' class="'.strtolower($order).'" ';
$order_by="$order_column $order ";
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qs += array('order' => ($order=='DESC' ? 'ASC' : 'DESC'));
$qstr = '&amp;'. Http::build_query($qs);
$query="$sql GROUP BY team.team_id ORDER BY $order_by";
$res=db_query($query);

View File

@@ -1,26 +1,25 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
$info=array();
$qstr='';
$info = $qs = array();
if($template && $_REQUEST['a']!='add'){
$title='Update Template';
$action='update';
$submit_text='Save Changes';
$info=$template->getInfo();
$info['tpl_id']=$template->getId();
$qstr.='&tpl_id='.$template->getId();
$qs += array('tpl_id' => $template->getId());
}else {
$title='Add New Template';
$action='add';
$submit_text='Add Template';
$info['isactive']=isset($info['isactive'])?$info['isactive']:0;
$info['lang_id'] = $cfg->getSystemLanguage();
$qstr.='&a='.urlencode($_REQUEST['a']);
$qs += array('a' => $_REQUEST['a']);
}
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
?>
<form action="templates.php?<?php echo $qstr; ?>" method="post" id="save">
<form action="templates.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
<?php csrf_token(); ?>
<input type="hidden" name="do" value="<?php echo $action; ?>">
<input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">

View File

@@ -1,7 +1,7 @@
<?php
if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
$qstr='';
$qs = array();
$sql='SELECT tpl.*,count(dept.tpl_id) as depts '.
'FROM '.EMAIL_TEMPLATE_GRP_TABLE.' tpl '.
'LEFT JOIN '.DEPT_TABLE.' dept USING(tpl_id) '.
@@ -30,9 +30,10 @@ $order_by="$order_column $order ";
$total=db_count('SELECT count(*) FROM '.EMAIL_TEMPLATE_GRP_TABLE.' tpl ');
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$pageNav->setURL('templates.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
//Ok..lets roll...create the actual query
$qstr.='&order='.($order=='DESC'?'ASC':'DESC');
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('templates.php', $qs);
$qstr .= '&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
$query="$sql GROUP BY tpl.tpl_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
$res=db_query($query);
if($res && ($num=db_num_rows($res)))

View File

@@ -8,7 +8,7 @@ if (($users=$ticket->getCollaborators())) {?>
echo sprintf('<tr><td %s><i class="icon-%s"></i> %s <em>&lt;%s&gt;</em></td></tr>',
($user->isActive()? '' : 'class="faded"'),
($user->isActive()? 'comments' : 'comment-alt'),
$user->getName(),
Format::htmlchars($user->getName()),
$user->getEmail());
}
} else {

View File

@@ -27,7 +27,7 @@ if(($users=$ticket->getCollaborators())) {?>
$user->getId(),
$checked,
$user->getId(),
$user->getName(),
Format::htmlchars($user->getName()),
$user->getEmail(),
$user->getId(),
$user->getId());

View File

@@ -40,7 +40,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
});
return false;
"><i class="icon-user"></i>
<span id="user-name"><?php echo $user->getName(); ?></span>
<span id="user-name"><?php echo Format::htmlchars($user->getName()); ?></span>
&lt;<span id="user-email"><?php echo $user->getEmail(); ?></span>&gt;
</a>
<a class="action-button" style="float:none;overflow:inherit" href="#"

View File

@@ -438,7 +438,9 @@ $tcount+= $ticket->getNumNotes();
<td>
<?php
# XXX: Add user-to-name and user-to-email HTML ID#s
$to =sprintf('%s &lt;%s&gt;', $ticket->getName(), $ticket->getReplyToEmail());
$to =sprintf('%s &lt;%s&gt;',
Format::htmlchars($ticket->getName()),
$ticket->getReplyToEmail());
$emailReply = (!isset($info['emailreply']) || $info['emailreply']);
?>
<select id="emailreply" name="emailreply">
@@ -1017,5 +1019,12 @@ $(function() {
}
});
});
<?php
// Set the lock if one exists
if ($lock) { ?>
autoLock.setLock({
id:<?php echo $lock->getId(); ?>,
time: <?php echo $cfg->getLockTime(); ?>}, 'acquire');
<?php } ?>
});
</script>

View File

@@ -1,9 +1,9 @@
<?php
if(!defined('OSTSCPINC') || !$thisstaff || !@$thisstaff->isStaff()) die('Access Denied');
$qstr='&'; //Query string collector
$qs= array(); //Query string collector
if($_REQUEST['status']) { //Query string status has nothing to do with the real status used below; gets overloaded.
$qstr.='status='.urlencode($_REQUEST['status']);
$qs += array('status' => $_REQUEST['status']);
}
//See if this is a search
@@ -81,7 +81,7 @@ if($status) {
if (isset($_REQUEST['uid']) && $_REQUEST['uid']) {
$qwhere .= ' AND (ticket.user_id='.db_input($_REQUEST['uid'])
.' OR collab.user_id='.db_input($_REQUEST['uid']).') ';
$qstr .= '&uid='.urlencode($_REQUEST['uid']);
$qs += array('uid' => $_REQUEST['uid']);
}
//Queues: Overloaded sub-statuses - you've got to just have faith!
@@ -110,12 +110,10 @@ if($staffId && ($staffId==$thisstaff->getId())) { //My tickets
//Search?? Somebody...get me some coffee
$deep_search=false;
if($search):
$qstr.='&a='.urlencode($_REQUEST['a']);
$qstr.='&t='.urlencode($_REQUEST['t']);
$qs += array('a' => $_REQUEST['a'], 't' => $_REQUEST['t']);
//query
if($searchTerm){
$qstr.='&query='.urlencode($searchTerm);
$qs += array('query' => $searchTerm);
$queryterm=db_real_escape($searchTerm,false); //escape the term ONLY...no quotes.
if (is_numeric($searchTerm)) {
$qwhere.=" AND ticket.`number` LIKE '$queryterm%'";
@@ -141,12 +139,12 @@ if($search):
endif;
if ($_REQUEST['advsid'] && isset($_SESSION['adv_'.$_REQUEST['advsid']])) {
$qstr.='advsid='.$_REQUEST['advsid'];
$qs += array('advsid' => $_REQUEST['advsid']);
$qwhere .= ' AND ticket.ticket_id IN ('. implode(',',
db_input($_SESSION['adv_'.$_REQUEST['advsid']])).')';
}
$sortOptions=array('date'=>'effective_date','ID'=>'ticket.`number`',
$sortOptions=array('date'=>'effective_date','ID'=>'ticket.`number`*1',
'pri'=>'pri.priority_urgency','name'=>'user.name','subj'=>'cdata.subject',
'status'=>'ticket.status','assignee'=>'assigned','staff'=>'staff',
'dept'=>'dept.dept_name');
@@ -196,7 +194,7 @@ $x=$sort.'_sort';
$$x=' class="'.strtolower($order).'" ';
if($_GET['limit'])
$qstr.='&limit='.urlencode($_GET['limit']);
$qs += array('limit' => $_GET['limit']);
$qselect ='SELECT ticket.ticket_id,tlock.lock_id,ticket.`number`,ticket.dept_id,ticket.staff_id,ticket.team_id '
.' ,user.name'
@@ -225,12 +223,15 @@ $total=db_count("SELECT count(DISTINCT ticket.ticket_id) $qfrom $sjoin $qwhere")
$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:PAGE_LIMIT;
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total,$page,$pagelimit);
$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
$qstr = '&amp;'.http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('tickets.php', $qs);
//ADD attachment,priorities, lock and other crap
$qselect.=' ,IF(ticket.duedate IS NULL,IF(sla.id IS NULL, NULL, DATE_ADD(ticket.created, INTERVAL sla.grace_period HOUR)), ticket.duedate) as duedate '
.' ,CAST(GREATEST(IFNULL(ticket.lastmessage, 0), IFNULL(ticket.closed, 0), IFNULL(ticket.reopened, 0), ticket.created) as datetime) as effective_date '
.' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team '
.' ,ticket.created as ticket_created, CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team '
.' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned '
.' ,IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as helptopic '
.' ,cdata.priority_id, cdata.subject, pri.priority_desc, pri.priority_color';
@@ -295,7 +296,9 @@ if ($results) {
<input type="hidden" name="a" value="search">
<table>
<tr>
<td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>"
<td><input type="text" id="basic-ticket-search" name="query"
size=30 value="<?php echo Format::htmlchars($_REQUEST['query'],
true); ?>"
autocomplete="off" autocorrect="off" autocapitalize="off"></td>
<td><input type="submit" name="basic_search" class="button" value="Search"></td>
<td>&nbsp;&nbsp;<a href="" id="go-advanced">[advanced]</a></td>
@@ -311,7 +314,8 @@ if ($results) {
<a class="refresh" href="<?php echo Format::htmlchars($_SERVER['REQUEST_URI']); ?>">Refresh</a>
<input type="hidden" name="a" value="mass_process" >
<input type="hidden" name="do" id="action" value="" >
<input type="hidden" name="status" value="<?php echo Format::htmlchars($_REQUEST['status']); ?>" >
<input type="hidden" name="status" value="<?php echo
Format::htmlchars($_REQUEST['status'], true); ?>" >
<table class="list" border="0" cellspacing="1" cellpadding="2" width="940">
<caption><?php echo $showing; ?>&nbsp;&nbsp;&nbsp;<?php echo $results_type; ?></caption>
<thead>
@@ -424,7 +428,8 @@ if ($results) {
echo '<i class="icon-fixed-width icon-paperclip"></i>&nbsp;';
?>
</td>
<td nowrap>&nbsp;<?php echo Format::truncate($row['name'],22,strpos($row['name'],'@')); ?>&nbsp;</td>
<td nowrap>&nbsp;<?php echo Format::htmlchars(
Format::truncate($row['name'], 22, strpos($row['name'], '@'))); ?>&nbsp;</td>
<?php
if($search && !$status){
$displaystatus=ucfirst($row['status']);
@@ -465,8 +470,10 @@ if ($results) {
<?php
if($num>0){ //if we actually had any tickets returned.
echo '<div>&nbsp;Page:'.$pageNav->getPageLinks().'&nbsp;';
echo '<a class="export-csv" href="?a=export&h='
.$hash.'&status='.$_REQUEST['status'] .'">Export</a></div>';
echo sprintf('<a class="export-csv" href="?%s">Export</a></div>',
Http::build_query(array(
'a' => 'export', 'h' => $hash,
'status' => $_REQUEST['status'])));
?>
<?php
if($thisstaff->canManageTickets()) { ?>

View File

@@ -76,7 +76,7 @@ $tpl=$msgtemplates[$selected];
<form action="templates.php?id=<?php echo $id; ?>&amp;a=manage" method="post" id="save">
<?php csrf_token(); ?>
<?php foreach ($extras as $k=>$v) { ?>
<input type="hidden" name="<?php echo $k; ?>" value="<?php echo $v; ?>" />
<input type="hidden" name="<?php echo $k; ?>" value="<?php echo Format::htmlchars($v); ?>" />
<?php } ?>
<input type="hidden" name="id" value="<?php echo $id; ?>">
<input type="hidden" name="a" value="manage">
@@ -105,7 +105,7 @@ $tpl=$msgtemplates[$selected];
</div>
<input type="hidden" name="draft_id" value=""/>
<textarea name="body" cols="21" rows="16" style="width:98%;" wrap="soft"
class="richtext draft" data-draft-namespace="tpl.<?php echo $selected; ?>"
class="richtext draft" data-draft-namespace="tpl.<?php echo Format::htmlchars($selected); ?>"
data-draft-object-id="<?php echo $tpl_id; ?>"><?php echo $info['body']; ?></textarea>
</td>
</tr>

View File

@@ -341,7 +341,7 @@ class TnefAttributeStreamReader extends TnefStreamReader {
/* Read and truncate to length. */
$text = substr($this->_getx($datalen), 0, $length);
if ($type == self::TypeUnicode) {
$text = Format::encode($text, 'ucs2');
$text = Charset::utf8($text, 'ucs2');
}
return $text;
@@ -543,7 +543,7 @@ class TnefMessage extends AbstractTnefObject {
// Transcode it
if ($encoding && $charset)
$body = Format::encode($body, $charset, $encoding);
$body = Charset::transcode($body, $charset, $encoding);
return $body;
}

View File

@@ -214,3 +214,16 @@ showImagesInline = function(urls, thread_id) {
}
});
}
$(document).on('submit', 'form', function() {
// Reformat dates
$('.dp', $(this)).each(function(i, e) {
var $e = $(e),
d = $e.datepicker('getDate');
if (!d) return;
var day = ('0'+d.getDate()).substr(-2),
month = ('0'+(d.getMonth()+1)).substr(-2),
year = d.getFullYear();
$e.val(year+'-'+month+'-'+day);
});
});

View File

@@ -25,7 +25,19 @@ require_once(INCLUDE_DIR.'class.client.php');
require_once(INCLUDE_DIR.'class.ticket.php');
$inc = 'login.inc.php';
// Check the CSRF token, and ensure that future requests will have to use a
// different CSRF token. This will help ward off both parallel and serial
// brute force attacks, because new tokens will have to be requested for
// each attempt.
if ($_POST) {
// Check CSRF token
if (!$ost->checkCSRFToken())
Http::response(400, __('Valid CSRF Token Required'));
// Rotate the CSRF token (original cannot be reused)
$ost->getCSRF()->rotate();
if (!$_POST['lticket'] || !Validator::is_email($_POST['lemail']))
$errors['err'] = 'Valid email address and ticket number required';
elseif (($user = UserAuthenticationBackend::process($_POST['lemail'],
@@ -34,7 +46,7 @@ if ($_POST) {
// force attempts (which doesn't buy much since the link is emailed)
$user->sendAccessLink();
$msg = sprintf("%s - access link sent to your email!",
$user->getName()->getFirst());
Format::htmlchars($user->getName()->getFirst()));
$_POST = null;
} elseif(!$errors['err']) {
$errors['err'] = 'Invalid email or ticket number - try again!';

View File

@@ -31,11 +31,13 @@ if($_POST):
$form = false;
if ($topic = Topic::lookup($vars['topicId'])) {
if ($form = DynamicForm::lookup($topic->ht['form_id'])) {
if ($form = $topic->getForm()) {
$TF = $form->getForm($vars);
$form = $form->instanciate();
$form->setSource($vars);
// Don't require internal fields (they're not shown)
if (!$form->isValid(function($f) { return !$f->get('private'); }))
$errors += $form->errors();
if (!$TF->isValid(function($f) { return !$f->get('private'); }))
$errors = array_merge($errors, $TF->errors());
}
}

View File

@@ -140,7 +140,7 @@
method: 'GET',
dataType: 'json',
url: 'ajax.php/report/overview/table',
data: {group: group, start: start, stop: stop},
data: {group: group, start: start, period: stop},
success: function(json) {
var q = $('<table>').attr({'class':'table table-condensed table-striped'}),
h = $('<tr>').appendTo($('<thead>').appendTo(q)),

View File

@@ -15,6 +15,20 @@
**********************************************************************/
var autoLock = {
// Defaults
lockId: 0,
timerId: 0,
lasteventTime: 0,
lastattemptTime: 0,
acquireTime: 0,
renewTime: 0,
renewFreq: 0, //renewal frequency in seconds...based on returned lock time.
time: 0,
lockAttempts: 0, //Consecutive lock attempt errors
maxattempts: 2, //Maximum failed lock attempts before giving up.
warn: true,
retry: true,
addEvent: function(elm, evType, fn, useCapture) {
if(elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
@@ -108,18 +122,6 @@ var autoLock = {
void(autoLock.tid=parseInt($(':input[name=id]',fObj).val()));
void(autoLock.lockTime=parseInt($(':input[name=locktime]',fObj).val()));
autoLock.lockId=0;
autoLock.timerId=0;
autoLock.lasteventTime=0;
autoLock.lastattemptTime=0;
autoLock.acquireTime=0;
autoLock.renewTime=0;
autoLock.renewFreq=0; //renewal frequency in seconds...based on returned lock time.
autoLock.time=0;
autoLock.lockAttempts=0; //Consecutive lock attempt errors
autoLock.maxattempts=2; //Maximum failed lock attempts before giving up.
autoLock.warn=true;
autoLock.retry=true;
autoLock.watchDocument();
autoLock.resetTimer();
autoLock.addEvent(window,'unload',autoLock.releaseLock,true); //Release lock regardless of any activity.

View File

@@ -25,6 +25,16 @@ $msg = $msg?$msg:'Authentication Required';
$dest=($dest && (!strstr($dest,'login.php') && !strstr($dest,'ajax.php')))?$dest:'index.php';
$show_reset = false;
if($_POST) {
// Check the CSRF token, and ensure that future requests will have to
// use a different CSRF token. This will help ward off both parallel and
// serial brute force attacks, because new tokens will have to be
// requested for each attempt.
if (!$ost->checkCSRFToken())
Http::response(400, __('Valid CSRF Token Required'));
// Rotate the CSRF token (original cannot be reused)
$ost->getCSRF()->rotate();
// Lookup support backends for this staff
$username = trim($_POST['userid']);
if ($user = StaffAuthenticationBackend::process($username,

View File

@@ -27,11 +27,9 @@ if($_POST) {
$_REQUEST['a'] = null;
$msg='Page added successfully';
// Attach inline attachments from the editor
if (isset($_POST['draft_id'])
&& ($draft = Draft::lookup($_POST['draft_id']))
&& ($page = Page::lookup($pageId)))
if ($page = Page::lookup($pageId))
$page->attachments->upload(
$draft->getAttachmentIds($_POST['response']), true);
Draft::getAttachmentIds($_POST['body']), true);
Draft::deleteForNamespace('page');
} elseif(!$errors['err'])
$errors['err'] = 'Unable to add page. Try again!';
@@ -43,13 +41,10 @@ if($_POST) {
$msg='Page updated successfully';
$_REQUEST['a']=null; //Go back to view
// Attach inline attachments from the editor
if (isset($_POST['draft_id'])
&& ($draft = Draft::lookup($_POST['draft_id']))) {
$page->attachments->deleteInlines();
$page->attachments->upload(
$draft->getAttachmentIds($_POST['response']),
true);
}
$page->attachments->deleteInlines();
$page->attachments->upload(
Draft::getAttachmentIds($_POST['body']),
true);
Draft::deleteForNamespace('page.'.$page->getId());
} elseif(!$errors['err'])
$errors['err'] = 'Unable to update page. Try again!';

View File

@@ -198,9 +198,11 @@ if($_POST && !$errors):
case 'edit':
case 'update':
$forms=DynamicFormEntry::forTicket($ticket->getId());
foreach ($forms as $form)
foreach ($forms as $form) {
$form->setSource($_POST);
if (!$form->isValid())
$errors = array_merge($errors, $form->errors());
}
if(!$ticket || !$thisstaff->canEditTickets())
$errors['err']='Permission Denied. You are not allowed to edit tickets';
elseif($ticket->update($_POST,$errors)) {
@@ -343,7 +345,7 @@ if($_POST && !$errors):
} elseif (!$_POST['user_id'] || !($user=User::lookup($_POST['user_id']))) {
$errors['err'] = 'Unknown user selected!';
} elseif ($ticket->changeOwner($user)) {
$msg = 'Ticket ownership changed to '.$user->getName();
$msg = 'Ticket ownership changed to ' . Format::htmlchars($user->getName());
} else {
$errors['err'] = 'Unable to change tiket ownership. Try again';
}
@@ -472,10 +474,12 @@ if($_POST && !$errors):
case 'open':
$ticket=null;
if ($topic=Topic::lookup($_POST['topicId'])) {
if ($form = DynamicForm::lookup($topic->ht['form_id'])) {
if ($form = $topic->getForm()) {
$TF = $form->getForm($_POST);
$form = $form->instanciate();
if (!$form->getForm()->isValid())
$errors = array_merge($errors, $form->getForm()->errors());
$form->setSource($_POST);
if (!$TF->isValid())
$errors = array_merge($errors, $TF->errors());
}
}
if(!$thisstaff || !$thisstaff->canCreateTickets()) {

View File

@@ -10,7 +10,7 @@ $url=URL;
<h2>Config file permission:</h2>
Change permission of ost-config.php to remove write access as shown below.
<ul>
<li><b>CLI</b>:<br><i>chmod 0664 include/ost-config.php</i></li>
<li><b>CLI</b>:<br><i>chmod 0644 include/ost-config.php</i></li>
<li><b>FTP</b>:<br>Using WS_FTP this would be right hand clicking on the file, selecting chmod, and then remove write access</li>
<li><b>Cpanel</b>:<br>Click on the file, select change permission, and then remove write access.</li>
</ul>

View File

@@ -39,9 +39,11 @@ if($_POST && is_object($ticket) && $ticket->getId()):
$errors['err']='Access Denied. Client updates are currently disabled';
else {
$forms=DynamicFormEntry::forTicket($ticket->getId());
foreach ($forms as $form)
foreach ($forms as $form) {
$form->setSource($_POST);
if (!$form->isValid())
$errors = array_merge($errors, $form->errors());
}
}
if (!$errors) {
foreach ($forms as $f) $f->save();