function decode() { $params = array('crlf' => "\r\n", 'charset' => $this->charset, 'include_bodies' => $this->include_bodies, 'decode_headers' => $this->decode_headers, 'decode_bodies' => $this->decode_bodies); $info = array('raw' => &$this->mime_message); Signal::send('mail.received', $this, $info); $this->splitBodyHeader(); $decoder = new Mail_mimeDecode($this->mime_message); $this->struct = $decoder->decode($params); if (PEAR::isError($this->struct)) { return false; } $info = array('raw_header' => &$this->header, 'headers' => &$this->struct->headers, 'body' => &$this->struct->parts, 'type' => $this->struct->ctype_primary . '/' . $this->struct->ctype_secondary, 'mail' => $this->struct, 'decoder' => $decoder); // Allow signal handlers to interact with the processing Signal::send('mail.decoded', $decoder, $info); // Handle wrapped emails when forwarded if ($this->struct && $this->struct->parts) { $outer = $this->struct; $ctype = $outer->ctype_primary . '/' . $outer->ctype_secondary; if (strcasecmp($ctype, 'message/rfc822') === 0) { // Capture Delivered-To header from the outer mail $dt = $this->struct->headers['delivered-to']; // Capture Message-Id from outer mail $mid = $this->struct->headers['message-id']; $this->struct = $outer->parts[0]; // Add (clobber) delivered to header from the outer mail if ($dt) { $this->struct->headers['delivered-to'] = $dt; } // Ensure the nested mail has a Message-Id if (!isset($this->struct->headers['message-id'])) { $this->struct->headers['message-id'] = $mid; } // Use headers of the wrapped message $headers = array(); foreach ($this->struct->headers as $h => $v) { $headers[mb_convert_case($h, MB_CASE_TITLE)] = $v; } $this->header = Format::array_implode(": ", "\n", $headers); } } // Look for application/tnef attachment and process it if ($this->struct && $this->struct->parts) { foreach ($this->struct->parts as $i => $part) { if (!@$part->parts && $part->ctype_primary == 'application' && $part->ctype_secondary == 'ms-tnef') { try { $tnef = new TnefStreamParser($part->body); $this->tnef = $tnef->getMessage(); // No longer considered an attachment unset($this->struct->parts[$i]); } catch (TnefException $ex) { // TNEF will remain an attachment $this->notes[] = 'TNEF parsing exception: ' . $ex->getMessage(); } } } } return count($this->struct->headers) > 1; }
static function getTtfFonts() { if (!class_exists('Phar')) { return; } $fonts = $subs = array(); foreach (self::availableLanguages() as $code => $info) { if (!$info['phar'] || !isset($info['fonts'])) { continue; } foreach ($info['fonts'] as $simple => $collection) { foreach ($collection as $type => $name) { list($name, $url) = $name; $ttffile = 'phar://' . $info['path'] . '/fonts/' . $name; if (file_exists($ttffile)) { $fonts[$simple][$type] = $ttffile; } } if (@$collection[':sub']) { $subs[] = $simple; } } } $rv = array($fonts, $subs); Signal::send('config.ttfonts', null, $rv); return $rv; }
static function process($username, $password = null, &$errors) { if (!$username) { return false; } $backends = static::getAllowedBackends($username); foreach (static::allRegistered() as $bk) { if ($backends && $bk->supportsAuthentication() && !in_array($bk::$id, $backends)) { // User cannot be authenticated against this backend continue; } // All backends are queried here, even if they don't support // authentication so that extensions like lockouts and audits // can be supported. $result = $bk->authenticate($username, $password); if ($result instanceof AuthenticatedUser && $bk->login($result, $bk)) { return $result; } elseif ($result instanceof AccessDenied) { break; } } if (!$result) { $result = new AccessDenied('Access denied'); } if ($result && $result instanceof AccessDenied) { $errors['err'] = $result->reason; } $info = array('username' => $username, 'password' => $password); Signal::send('auth.login.failed', null, $info); self::authAudit($result, $info); }
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: **********************************************************************/ # Override staffLoginPage() defined in staff.inc.php to return an # HTTP/Forbidden status rather than the actual login page. # XXX: This should be moved to the AjaxController class function staffLoginPage($msg = 'Unauthorized') { Http::response(403, 'Must login: '******'AJAX_REQUEST', 1); require 'staff.inc.php'; //Clean house...don't let the world see your crap. ini_set('display_errors', '0'); //Disable error display ini_set('display_startup_errors', '0'); //TODO: disable direct access via the browser? i,e All request must have REFER? if (!defined('INCLUDE_DIR')) { Http::response(500, 'Server configuration error'); } require_once INCLUDE_DIR . '/class.dispatcher.php'; require_once INCLUDE_DIR . '/class.ajax.php'; $dispatcher = patterns('', url('^/kb/', patterns('ajax.kbase.php:KbaseAjaxAPI', url_get('^canned-response/(?P<id>\\d+).(?P<format>json|txt)', 'cannedResp'), url_get('^faq/(?P<id>\\d+)', 'faq'))), url('^/content/', patterns('ajax.content.php:ContentAjaxAPI', url_get('^log/(?P<id>\\d+)', 'log'), url_get('^ticket_variables', 'ticket_variables'), url_get('^signature/(?P<type>\\w+)(?:/(?P<id>\\d+))?$', 'getSignature'), url_get('^(?P<id>\\d+)/(?:(?P<lang>\\w+)/)?manage$', 'manageContent'), url_get('^(?P<id>[\\w-]+)/(?:(?P<lang>\\w+)/)?manage$', 'manageNamedContent'), url_post('^(?P<id>\\d+)(?:/(?P<lang>\\w+))?$', 'updateContent'))), url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', url_get('^scp', 'scp'), url_get('^links', 'templateLinks'))), url('^/form/', patterns('ajax.forms.php:DynamicFormsAjaxAPI', url_get('^help-topic/(?P<id>\\d+)$', 'getFormsForHelpTopic'), url_get('^field-config/(?P<id>\\d+)$', 'getFieldConfiguration'), url_post('^field-config/(?P<id>\\d+)$', 'saveFieldConfiguration'), url_delete('^answer/(?P<entry>\\d+)/(?P<field>\\d+)$', 'deleteAnswer'))), url('^/list/', patterns('ajax.forms.php:DynamicFormsAjaxAPI', url_get('^item/(?P<id>\\d+)/properties$', 'getListItemProperties'), url_post('^item/(?P<id>\\d+)/properties$', 'saveListItemProperties'))), url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI', url_get('^graph$', 'getPlotData'), url_get('^table/groups$', 'enumTabularGroups'), url_get('^table/export$', 'downloadTabularData'), url_get('^table$', 'getTabularData'))), url('^/users', patterns('ajax.users.php:UsersAjaxAPI', url_get('^$', 'search'), url_get('^/local$', 'search', array('local')), url_get('^/remote$', 'search', array('remote')), url_get('^/(?P<id>\\d+)$', 'getUser'), url_post('^/(?P<id>\\d+)$', 'updateUser'), url_get('^/(?P<id>\\d+)/preview$', 'preview'), url_get('^/(?P<id>\\d+)/edit$', 'editUser'), url('^/lookup$', 'getUser'), url_get('^/lookup/form$', 'lookup'), url_post('^/lookup/form$', 'addUser'), url_get('^/add$', 'addUser'), url('^/import$', 'importUsers'), url_get('^/select$', 'selectUser'), url_get('^/select/(?P<id>\\d+)$', 'selectUser'), url_get('^/select/auth:(?P<bk>\\w+):(?P<id>.+)$', 'addRemoteUser'), url_get('^/(?P<id>\\d+)/register$', 'register'), url_post('^/(?P<id>\\d+)/register$', 'register'), url_get('^/(?P<id>\\d+)/delete$', 'delete'), url_post('^/(?P<id>\\d+)/delete$', 'delete'), url_get('^/(?P<id>\\d+)/manage(?:/(?P<target>\\w+))?$', 'manage'), url_post('^/(?P<id>\\d+)/manage(?:/(?P<target>\\w+))?$', 'manage'), url_get('^/(?P<id>\\d+)/org(?:/(?P<orgid>\\d+))?$', 'updateOrg'), url_post('^/(?P<id>\\d+)/org$', 'updateOrg'), url_get('^/staff$', 'searchStaff'), url_post('^/(?P<id>\\d+)/note$', 'createNote'), url_get('^/(?P<id>\\d+)/forms/manage$', 'manageForms'), url_post('^/(?P<id>\\d+)/forms/manage$', 'updateForms'))), url('^/orgs', patterns('ajax.orgs.php:OrgsAjaxAPI', url_get('^$', 'search'), url_get('^/search$', 'search'), url_get('^/(?P<id>\\d+)$', 'getOrg'), url_post('^/(?P<id>\\d+)$', 'updateOrg'), url_post('^/(?P<id>\\d+)/profile$', 'updateOrg', array(true)), url_get('^/(?P<id>\\d+)/edit$', 'editOrg'), url_get('^/lookup/form$', 'lookup'), url_post('^/lookup/form$', 'addOrg'), url_get('^/add$', 'addOrg'), url_post('^/add$', 'addOrg'), url_get('^/select$', 'selectOrg'), url_get('^/select/(?P<id>\\d+)$', 'selectOrg'), url_get('^/(?P<id>\\d+)/add-user(?:/(?P<userid>\\d+))?$', 'addUser'), url_get('^/(?P<id>\\d+)/add-user(?:/auth:(?P<userid>.+))?$', 'addUser', array(true)), url_post('^/(?P<id>\\d+)/add-user$', 'addUser'), url('^/(?P<id>\\d+)/import-users$', 'importUsers'), url_get('^/(?P<id>\\d+)/delete$', 'delete'), url_delete('^/(?P<id>\\d+)/delete$', 'delete'), url_post('^/(?P<id>\\d+)/note$', 'createNote'), url_get('^/(?P<id>\\d+)/forms/manage$', 'manageForms'), url_post('^/(?P<id>\\d+)/forms/manage$', 'updateForms'))), url('^/tickets/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<tid>\\d+)/change-user$', 'changeUserForm'), url_post('^(?P<tid>\\d+)/change-user$', 'changeUser'), url_get('^(?P<tid>\\d+)/user$', 'viewUser'), url_post('^(?P<tid>\\d+)/user$', 'updateUser'), url_get('^(?P<tid>\\d+)/preview', 'previewTicket'), url_post('^(?P<tid>\\d+)/lock$', 'acquireLock'), url_post('^(?P<tid>\\d+)/lock/(?P<id>\\d+)/renew', 'renewLock'), url_post('^(?P<tid>\\d+)/lock/(?P<id>\\d+)/release', 'releaseLock'), url_get('^(?P<tid>\\d+)/collaborators/preview$', 'previewCollaborators'), url_get('^(?P<tid>\\d+)/collaborators$', 'showCollaborators'), url_post('^(?P<tid>\\d+)/collaborators$', 'updateCollaborators'), url_get('^(?P<tid>\\d+)/add-collaborator/(?P<uid>\\d+)$', 'addCollaborator'), url_get('^(?P<tid>\\d+)/add-collaborator/auth:(?P<bk>\\w+):(?P<id>.+)$', 'addRemoteCollaborator'), url('^(?P<tid>\\d+)/add-collaborator$', 'addCollaborator'), url_get('^lookup', 'lookup'), url_get('^search', 'search'), url_get('^(?P<tid>\\d+)/forms/manage$', 'manageForms'), url_post('^(?P<tid>\\d+)/forms/manage$', 'updateForms'), url_get('^(?P<tid>\\d+)/canned-resp/(?P<cid>\\w+).(?P<format>json|txt)', 'cannedResponse'))), url('^/collaborators/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<cid>\\d+)/view$', 'viewCollaborator'), url_post('^(?P<cid>\\d+)$', 'updateCollaborator'))), url('^/draft/', patterns('ajax.draft.php:DraftAjaxAPI', url_post('^(?P<id>\\d+)$', 'updateDraft'), url_delete('^(?P<id>\\d+)$', 'deleteDraft'), url_post('^(?P<id>\\d+)/attach$', 'uploadInlineImage'), url_get('^(?P<namespace>[\\w.]+)$', 'getDraft'), url_post('^(?P<namespace>[\\w.]+)$', 'createDraft'), url_get('^images/browse$', 'getFileList'))), url('^/note/', patterns('ajax.note.php:NoteAjaxAPI', url_get('^(?P<id>\\d+)$', 'getNote'), url_post('^(?P<id>\\d+)$', 'updateNote'), url_delete('^(?P<id>\\d+)$', 'deleteNote'), url_post('^attach/(?P<ext_id>\\w\\d+)$', 'createNote'))), url_post('^/upgrader', array('ajax.upgrader.php:UpgraderAjaxAPI', 'upgrade')), url('^/help/', patterns('ajax.tips.php:HelpTipAjaxAPI', url_get('^tips/(?P<namespace>[\\w_.]+)$', 'getTipsJson'), url_get('^(?P<lang>[\\w_]+)?/tips/(?P<namespace>[\\w_.]+)$', 'getTipsJsonForLang')))); Signal::send('ajax.scp', $dispatcher); # Call the respective function print $dispatcher->resolve($ost->get_path_info());
function createTicket($mid) { global $ost; if (!($mailinfo = $this->getHeaderInfo($mid))) { return false; } // TODO: If the content-type of the message is 'message/rfc822', // then this is a message with the forwarded message as the // attachment. Download the body and pass it along to the mail // parsing engine. $info = Mail_Parse::splitHeaders($mailinfo['header']); if (strtolower($info['Content-Type']) == 'message/rfc822') { if ($wrapped = $this->getPart($mid, 'message/rfc822')) { require_once INCLUDE_DIR . 'api.tickets.php'; // Simulate piping the contents into the system $api = new TicketApiController(); $parser = new EmailDataParser(); if ($data = $parser->parse($wrapped)) { return $api->processEmail($data); } } // If any of this fails, create the ticket as usual } //Is the email address banned? if ($mailinfo['email'] && TicketFilter::isBanned($mailinfo['email'])) { //We need to let admin know... $ost->logWarning(_S('Ticket denied'), sprintf(_S('Banned email — %s'), $mailinfo['email']), false); return true; //Report success (moved or delete) } // Parse MS TNEF emails if (($struct = imap_fetchstructure($this->mbox, $mid)) && ($attachments = $this->getAttachments($struct))) { foreach ($attachments as $i => $info) { if (0 === strcasecmp('application/ms-tnef', $info['type'])) { try { $data = $this->decode(imap_fetchbody($this->mbox, $mid, $info['index']), $info['encoding']); $tnef = new TnefStreamParser($data); $this->tnef = $tnef->getMessage(); // No longer considered an attachment unset($attachments[$i]); // There should only be one of these break; } catch (TnefException $ex) { // Noop -- winmail.dat remains an attachment } } } } $vars = $mailinfo; $vars['name'] = $mailinfo['name']; $vars['subject'] = $mailinfo['subject'] ?: '[No Subject]'; $vars['emailId'] = $mailinfo['emailId'] ?: $this->getEmailId(); $vars['to-email-id'] = $mailinfo['emailId'] ?: 0; $vars['flags'] = new ArrayObject(); if ($this->isBounceNotice($mid)) { // Fetch the original References and assign to 'references' if ($headers = $this->getOriginalMessageHeaders($mid)) { $vars['references'] = $headers['references']; $vars['in-reply-to'] = @$headers['in-reply-to'] ?: null; } // Fetch deliver status report $vars['message'] = $this->getDeliveryStatusMessage($mid) ?: $this->getBody($mid); $vars['thread-type'] = 'N'; $vars['flags']['bounce'] = true; } else { $vars['message'] = $this->getBody($mid); $vars['flags']['bounce'] = TicketFilter::isBounce($info); } //Missing FROM name - use email address. if (!$vars['name']) { list($vars['name']) = explode('@', $vars['email']); } if ($ost->getConfig()->useEmailPriority()) { $vars['priorityId'] = $this->getPriority($mid); } $ticket = null; $newticket = true; $errors = array(); $seen = false; // Use the settings on the thread entry on the ticket details // form to validate the attachments in the email $tform = TicketForm::objects()->one()->getForm(); $messageField = $tform->getField('message'); $fileField = $messageField->getWidget()->getAttachments(); // Fetch attachments if any. if ($messageField->isAttachmentsEnabled()) { // Include TNEF attachments in the attachments list if ($this->tnef) { foreach ($this->tnef->attachments as $at) { $attachments[] = array('cid' => @$at->AttachContentId ?: false, 'data' => $at, 'size' => @$at->DataSize ?: null, 'type' => @$at->AttachMimeTag ?: false, 'name' => $at->getName()); } } $vars['attachments'] = array(); foreach ($attachments as $a) { $file = array('name' => $a['name'], 'type' => $a['type']); if (@$a['data'] instanceof TnefAttachment) { $file['data'] = $a['data']->getData(); } else { // only fetch the body if necessary $self = $this; $file['data'] = function () use($self, $mid, $a) { return $self->decode(imap_fetchbody($self->mbox, $mid, $a['index']), $a['encoding']); }; } // Include the Content-Id if specified (for inline images) $file['cid'] = isset($a['cid']) ? $a['cid'] : false; // Validate and save immediately try { $file['id'] = $fileField->uploadAttachment($file); } catch (FileUploadError $ex) { $file['error'] = $file['name'] . ': ' . $ex->getMessage(); } $vars['attachments'][] = $file; } } // Allow signal handlers to interact with the message decoding Signal::send('mail.processed', $this, $vars); $seen = false; if (($thread = ThreadEntry::lookupByEmailHeaders($vars, $seen)) && ($t = $thread->getTicket()) && ($vars['staffId'] || !$t->isClosed() || $t->isReopenable()) && ($message = $thread->postEmail($vars))) { if (!$message instanceof ThreadEntry) { // Email has been processed previously return $message; } $ticket = $message->getTicket(); } elseif ($seen) { // Already processed, but for some reason (like rejection), no // thread item was created. Ignore the email return true; } elseif ($ticket = Ticket::create($vars, $errors, 'Email')) { $message = $ticket->getLastMessage(); } else { //Report success if the email was absolutely rejected. if (isset($errors['errno']) && $errors['errno'] == 403) { // Never process this email again! ThreadEntry::logEmailHeaders(0, $vars['mid']); return true; } // Log an error to the system logs $mailbox = Email::lookup($vars['emailId']); $ost->logError(_S('Mail Processing Exception'), sprintf(_S("Mailbox: %s | Error(s): %s"), $mailbox->getEmail(), print_r($errors, true)), false); // Indicate failure of mail processing return null; } return $ticket; }
if ($sec < 180 || !$ost || $ost->isUpgradePending()) ob_end_clean(); require_once(INCLUDE_DIR.'class.cron.php'); // Clear staff obj to avoid false credit internal notes & auto-assignment $thisstaff = null; // Release the session to prevent locking a future request while this is // running $_SESSION['lastcroncall'] = time(); session_write_close(); // Age tickets: We're going to age tickets regardless of cron settings. Cron::TicketMonitor(); // Run file purging about every 20 cron runs (1h40 on a five minute cron) if (mt_rand(1, 20) == 4) Cron::CleanOrphanedFiles(); if($cfg && $cfg->isAutoCronEnabled()) { //ONLY fetch tickets if autocron is enabled! Cron::MailFetcher(); //Fetch mail. $ost->logDebug(_S('Auto Cron'), sprintf(_S('Mail fetcher cron call [%s]'), $caller)); } $data = array('autocron'=>true); Signal::send('cron', $data); ob_end_clean(); ?>
function save($id, $vars, &$errors, $validation = false) { //Cleanup. $vars['question'] = Format::striptags(trim($vars['question'])); //validate if ($id && $id != $vars['id']) { $errors['err'] = __('Internal error. Try again'); } if (!$vars['question']) { $errors['question'] = __('Question required'); } elseif (($qid = self::findIdByQuestion($vars['question'])) && $qid != $id) { $errors['question'] = __('Question already exists'); } if (!$vars['category_id'] || !($category = Category::lookup($vars['category_id']))) { $errors['category_id'] = __('Category is required'); } if (!$vars['answer']) { $errors['answer'] = __('FAQ answer is required'); } if ($errors || $validation) { return !$errors; } //save $sql = ' updated=NOW() ' . ', question=' . db_input($vars['question']) . ', answer=' . db_input(Format::sanitize($vars['answer'], false)) . ', category_id=' . db_input($vars['category_id']) . ', ispublished=' . db_input(isset($vars['ispublished']) ? $vars['ispublished'] : 0) . ', notes=' . db_input(Format::sanitize($vars['notes'])); if ($id) { $sql = 'UPDATE ' . FAQ_TABLE . ' SET ' . $sql . ' WHERE faq_id=' . db_input($id); if (db_query($sql)) { return true; } $errors['err'] = sprintf(__('Unable to update %s.'), __('this FAQ article')); } else { $sql = 'INSERT INTO ' . FAQ_TABLE . ' SET ' . $sql . ',created=NOW()'; if (db_query($sql) && ($id = db_insert_id())) { Signal::send('model.created', FAQ::lookup($id)); return $id; } $errors['err'] = sprintf(__('Unable to create %s.'), __('this FAQ article')) . ' ' . __('Internal error occurred'); } return false; }
static function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $ost, $cfg, $thisclient, $_FILES; // Don't enforce form validation for email $field_filter = function ($type) use($origin) { return function ($f) use($origin, $type) { // Ultimately, only offer validation errors for web for // non-internal fields. For email, no validation can be // performed. For other origins, validate as usual switch (strtolower($origin)) { case 'email': return false; case 'staff': // Required 'Contact Information' fields aren't required // when staff open tickets return $type != 'user' || in_array($f->get('name'), array('name', 'email')); case 'web': return !$f->get('private'); default: return true; } }; }; $reject_ticket = function ($message) use(&$errors) { global $ost; $errors = array('errno' => 403, 'err' => __('This help desk is for use by authorized users only')); $ost->logWarning(_S('Ticket Denied'), $message, false); return 0; }; Signal::send('ticket.create.before', null, $vars); // Create and verify the dynamic form entry for the new ticket $form = TicketForm::getNewInstance(); $form->setSource($vars); // If submitting via email or api, ensure we have a subject and such if (!in_array(strtolower($origin), array('web', 'staff'))) { foreach ($form->getFields() as $field) { $fname = $field->get('name'); if ($fname && isset($vars[$fname]) && !$field->value) { $field->value = $field->parse($vars[$fname]); } } } if (!$form->isValid($field_filter('ticket'))) { $errors += $form->errors(); } /*INICIO Creado por Anthony Parisi 2016-02-01 Con las siguientes lineas de código, se crea el ticket mediante la API.*/ if (!in_array(strtolower($origin), array('web', 'staff'))) { $errors = array(); } /* FIN */ if ($vars['uid']) { $user = User::lookup($vars['uid']); } $id = 0; $fields = array(); $fields['message'] = array('type' => '*', 'required' => 1, 'error' => __('Message content is required')); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Select a help topic')); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 0, 'error' => __('Department selection is required')); $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Help topic selection is required')); $fields['duedate'] = array('type' => 'date', 'required' => 0, 'error' => __('Invalid date format - must be MM/DD/YY')); case 'api': $fields['source'] = array('type' => 'string', 'required' => 1, 'error' => __('Indicate ticket source')); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => __('Unknown system email')); break; default: # TODO: Return error message $errors['err'] = $errors['origin'] = __('Invalid ticket origin given'); } if (!Validator::process($fields, $vars, $errors) && !$errors['err']) { $errors['err'] = __('Missing or invalid data - check the errors and try again'); } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = __('Select a time from the list'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = __('Invalid due date'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = __('Due date must be in the future'); } } if (!$errors) { # Perform ticket filter actions on the new ticket arguments $__form = null; if ($vars['topicId']) { if (($__topic = Topic::lookup($vars['topicId'])) && ($__form = $__topic->getForm())) { $__form = $__form->instanciate(); $__form->setSource($vars); } } try { $vars = self::filterTicketData($origin, $vars, array($form, $__form), $user); } catch (RejectedException $ex) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) by filter "%s"'), $ex->vars['email'], $ex->getRejectingFilter()->getName())); } //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($_user = TicketUser::lookupByEmail($vars['email'])) && ($openTickets = $_user->getNumOpenTickets()) && $openTickets >= $cfg->getMaxOpenTickets()) { $errors = array('err' => __("You've reached the maximum open tickets allowed.")); $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']), sprintf(_S('Max open tickets (%1$d) reached for %2$s'), $cfg->getMaxOpenTickets(), $vars['email']), false); return 0; } // Allow vars to be changed in ticket filter and applied to the user // account created or detected if (!$user && $vars['email']) { $user = User::lookupByEmail($vars['email']); } if (!$user) { // Reject emails if not from registered clients (if // configured) if (strcasecmp($origin, 'email') === 0 && !$cfg->acceptUnregisteredEmail()) { list($mailbox, $domain) = explode('@', $vars['email'], 2); // Users not yet created but linked to an organization // are still acceptable if (!Organization::forDomain($domain)) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) (unregistered client)'), $vars['email'])); } } $user_form = UserForm::getUserForm()->getForm($vars); if (!$user_form->isValid($field_filter('user')) || !($user = User::fromVars($user_form->getClean()))) { $errors['user'] = __('Incomplete client information'); } } } if ($vars['topicId']) { if ($topic = Topic::lookup($vars['topicId'])) { if ($topic_form = $topic->getForm()) { $TF = $topic_form->getForm($vars); $topic_form = $topic_form->instanciate(); $topic_form->setSource($vars); if (!$TF->isValid($field_filter('topic'))) { $errors = array_merge($errors, $TF->errors()); } } } else { $errors['topicId'] = 'Invalid help topic selected'; } } // Any error above is fatal. if ($errors) { return 0; } Signal::send('ticket.create.validated', null, $vars); # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) { $autorespond = $vars['autorespond']; } # Apply filter-specific priority if ($vars['priorityId']) { $form->setAnswer('priority', null, $vars['priorityId']); } // If the filter specifies a help topic which has a form associated, // and there was previously either no help topic set or the help // topic did not have a form, there's no need to add it now as (1) // validation is closed, (2) there may be a form already associated // and filled out from the original help topic, and (3) staff // members can always add more forms now // OK...just do it. $statusId = $vars['statusId']; $deptId = $vars['deptId']; //pre-selected Dept if any. $source = ucfirst($vars['source']); // Apply email settings for emailed tickets. Email settings should // trump help topic settins if the email has an associated help // topic if ($vars['emailId'] && ($email = Email::lookup($vars['emailId']))) { $deptId = $deptId ?: $email->getDeptId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $email->getPriorityId()); } if ($autorespond) { $autorespond = $email->autoRespond(); } if (!isset($topic) && ($T = $email->getTopic()) && $T->isActive()) { $topic = $T; } $email = null; $source = 'Email'; } if (!isset($topic)) { // This may return NULL, no big deal $topic = $cfg->getDefaultTopic(); } // Intenal mapping magic...see if we need to override anything if (isset($topic)) { $deptId = $deptId ?: $topic->getDeptId(); $statusId = $statusId ?: $topic->getStatusId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $topic->getPriorityId()); } if ($autorespond) { $autorespond = $topic->autoRespond(); } //Auto assignment. if (!isset($vars['staffId']) && $topic->getStaffId()) { $vars['staffId'] = $topic->getStaffId(); } elseif (!isset($vars['teamId']) && $topic->getTeamId()) { $vars['teamId'] = $topic->getTeamId(); } //set default sla. if (isset($vars['slaId'])) { $vars['slaId'] = $vars['slaId'] ?: $cfg->getDefaultSLAId(); } elseif ($topic && $topic->getSLAId()) { $vars['slaId'] = $topic->getSLAId(); } } // Auto assignment to organization account manager if (($org = $user->getOrganization()) && $org->autoAssignAccountManager() && ($code = $org->getAccountManagerId())) { if (!isset($vars['staffId']) && $code[0] == 's') { $vars['staffId'] = substr($code, 1); } elseif (!isset($vars['teamId']) && $code[0] == 't') { $vars['teamId'] = substr($code, 1); } } // Last minute checks $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $cfg->getDefaultPriorityId()); } $deptId = $deptId ?: $cfg->getDefaultDeptId(); $statusId = $statusId ?: $cfg->getDefaultTicketStatusId(); $topicId = isset($topic) ? $topic->getId() : 0; $ipaddress = $vars['ip'] ?: $_SERVER['REMOTE_ADDR']; $source = $source ?: 'Web'; //We are ready son...hold on to the rails. $number = $topic ? $topic->getNewTicketNumber() : $cfg->getNewTicketNumber(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,user_id=' . db_input($user->getId()) . ' ,`number`=' . db_input($number) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); if (isset($vars['emailId']) && $vars['emailId']) { $sql .= ', email_id=' . db_input($vars['emailId']); } //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ // Save the (common) dynamic form $form->setTicketId($id); $form->save(); // Save the form data from the help-topic form, if any if ($topic_form) { $topic_form->setTicketId($id); $topic_form->save(); } $ticket->loadDynamicData(); $dept = $ticket->getDept(); // Add organizational collaborators if ($org && $org->autoAddCollabs()) { $pris = $org->autoAddPrimaryContactsAsCollabs(); $members = $org->autoAddMembersAsCollabs(); $settings = array('isactive' => true); $collabs = array(); foreach ($org->allMembers() as $u) { if ($members || $pris && $u->isPrimaryContact()) { if ($c = $ticket->addCollaborator($u, $settings, $errors)) { $collabs[] = (string) $c; } } } //TODO: Can collaborators add others? if ($collabs) { //TODO: Change EndUser to name of user. $ticket->logNote(sprintf(_S('Collaborators for %s organization added'), $org->getName()), implode("<br>", $collabs), $org->getName(), false); } } //post the message. $vars['title'] = $vars['subject']; //Use the initial subject as title of the post. $vars['userId'] = $ticket->getUserId(); $message = $ticket->postMessage($vars, $origin, false); // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); // Assign ticket to staff or team (new ticket by staff) if ($vars['assignId']) { $ticket->assign($vars['assignId'], $vars['note']); } else { // Auto assign staff or team - auto assignment based on filter // rules. Both team and staff can be assigned if ($vars['staffId']) { $ticket->assignToStaff($vars['staffId'], _S('Auto Assignment')); } if ($vars['teamId']) { // No team alert if also assigned to an individual agent $ticket->assignToTeam($vars['teamId'], _S('Auto Assignment'), !$vars['staffId']); } } // Apply requested status — this should be done AFTER assignment, // because if it is requested to be closed, it should not cause the // ticket to be reopened for assignment. if ($statusId) { $ticket->setStatus($statusId, false, false); } /********** double check auto-response ************/ //Override auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if (isset($vars['flags']) && $vars['flags']['bounce']) { $autorespond = false; } if ($autorespond && $message->isAutoReply()) { $autorespond = false; } //post canned auto-response IF any (disables new ticket auto-response). if ($vars['cannedResponseId'] && $ticket->postCannedReply($vars['cannedResponseId'], $message->getId(), $autorespond)) { $ticket->markUnAnswered(); //Leave the ticket as unanswred. $autorespond = false; } //Check department's auto response settings // XXX: Dept. setting doesn't affect canned responses. if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } //Don't send alerts to staff when the message is a bounce // this is necessary to avoid possible loop (especially on new ticket) if ($alertstaff && $message->isBounce()) { $alertstaff = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($message, $autorespond, $alertstaff); /************ check if the user JUST reached the max. open tickets limit **********/ if ($cfg->getMaxOpenTickets() > 0 && ($user = $ticket->getOwner()) && $user->getNumOpenTickets() == $cfg->getMaxOpenTickets()) { $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff')); } /* Start tracking ticket lifecycle events */ $ticket->logEvent('created'); // Fire post-create signal (for extra email sending, searching) Signal::send('model.created', $ticket); /*INICIO Anthony Parisi 2016-02-05 Con las siguientes lineas de código, se actualizan los campos de Detalle de su Solicitud en las tablas descritas en la Sentencia SQL*/ if (!in_array(strtolower($origin), array('web', 'staff'))) { //echo "<pre>"; //var_dump($vars); //die($vars['valores']); foreach ($ticket as $key => $value) { if ($key == "id") { $ticket_idAPI = $value; } if ($key == "last_message") { $last_message = $value; $datos = explode("\n", $last_message); $nombre = $vars['name']; $correo = $vars['email']; $telefono = $vars['phone']; $valores = $vars['valores']; $adicional = explode("%%", $valores); //die($adicional[4]); /*$nombre = ucwords(strtolower(substr($datos[0], 20, strlen($datos[0])-21))); $correo = strtolower(substr($datos[1], 20, strlen($datos[1])-21)); $telefono = substr($datos[2], 22, strlen($datos[2])-23); $i = 5; $mensaje = ""; while(strpos($datos[$i], "------------------------------------------------------") === false){ $mensaje .= $datos[$i]; $i++; } for($i=5;$i < (count($datos)-6);$i++){ if(strpos($datos[$i], "TIPO DE PASAJE: ") > -1) $pasaje = substr($datos[$i], 28, strlen($datos[$i])-29); elseif(strpos($datos[$i], "CIUDAD DE ORIGEN: ") > -1) $origen = substr($datos[$i], 18, strlen($datos[$i])-19); elseif(strpos($datos[$i], "CIUDAD DE DESTINO: ") > -1) $destino = substr($datos[$i], 21, strlen($datos[$i])-22); elseif(strpos($datos[$i], "FECHA DE SALIDA: ") > -1) $salida = substr($datos[$i], 17, strlen($datos[$i])-18); elseif(strpos($datos[$i], "FECHA DE REGRESO: ") > -1) $regreso = substr($datos[$i], 20, strlen($datos[$i])-21); elseif(strpos($datos[$i], "CLASE: ") > -1) $clase = substr($datos[$i], 19, strlen($datos[$i])-20); elseif(strpos($datos[$i], "AEROL") > -1) $aerolinea = substr($datos[$i], 14, strlen($datos[$i])-15); } $adultos = substr($datos[count($datos)-5], 9, strlen($datos[count($datos)-5])-10); $mayores = substr($datos[count($datos)-4], 11, strlen($datos[count($datos)-4])-12); $ninos = substr($datos[count($datos)-3], 9, strlen($datos[count($datos)-3])-10); $bebes = substr($datos[count($datos)-2], 8, strlen($datos[count($datos)-2])-9);*/ } } $detail = '{"88":"Cotizacion PopPup"}'; $mysqli = new mysqli(DBHOST, DBUSER, DBPASS, DBNAME); $mysqli->query("UPDATE `ost_form_entry_values` SET `value` = '{$detail}' WHERE field_id = '20' AND `entry_id` = (SELECT id FROM ost_form_entry WHERE object_id = '{$ticket_idAPI}' AND object_type = 'T');"); $mysqli->query("INSERT INTO `ost_ticket__cdata` SET `subject`='88', `ticket_id`= '{$ticket_idAPI}' ON DUPLICATE KEY UPDATE `subject`='88';"); $sqlUser = $mysqli->query("SELECT id FROM ost_user WHERE id = '" . $user->getId() . "' AND `org_id` = 30 LIMIT 1;"); $rowUser = mysqli_num_rows($sqlUser); if ($rowUser <= 0) { $mysqli->query("UPDATE ost_user SET `org_id` = 30, `updated` = NOW() WHERE id = " . $user->getId() . " LIMIT 1;"); } $mysqli->query("INSERT INTO \n `ost_cotizaciones` (\n `ticket_id`, \n `nombre`, \n `correo`, \n `telefono`, \n `mensaje`, \n `tipo_vuelo`, \n `origen`, \n `destino`, \n `salida`, \n `regreso`, \n `clase`, \n `aerolinea`, \n `adultos`, \n `mayores`, \n `ninos`, \n `bebe`) \n VALUES (\n '{$ticket_idAPI}', \n '{$nombre}', \n '{$correo}', \n '{$telefono}', \n '{$adicional['0']}', \n '{$adicional['1']}', \n '{$adicional['2']}', \n '{$adicional['3']}', \n '{$adicional['4']}', \n '{$adicional['5']}', \n '{$adicional['6']}', \n '{$adicional['7']}', \n '{$adicional['8']}', \n '{$adicional['9']}', \n '{$adicional['10']}', \n '{$adicional['11']}');"); } /* FIN */ /* Phew! ... time for tea (KETEPA) */ return $ticket; }
function run() { //called by outside cron NOT autocron global $ost; if (!$ost || $ost->isUpgradePending()) { return; } self::MailFetcher(); self::TicketMonitor(); self::PurgeLogs(); self::CleanOrphanedFiles(); self::PurgeDrafts(); self::MaybeOptimizeTables(); Signal::send('cron', null); }
protected function sendUnlockEmail($template) { global $ost, $cfg; $token = Misc::randCode(48); // 290-bits $email = $cfg->getDefaultEmail(); $content = Page::lookup(Page::getIdByType($template)); if (!$email || !$content) { return new Error(sprintf(_S('%s: Unable to retrieve template'), $template)); } $vars = array('url' => $ost->getConfig()->getBaseUrl(), 'token' => $token, 'user' => $this->getUser(), 'recipient' => $this->getUser(), 'link' => sprintf("%s/pwreset.php?token=%s", $ost->getConfig()->getBaseUrl(), $token)); $vars['reset_link'] =& $vars['link']; $info = array('email' => $email, 'vars' => &$vars, 'log' => true); Signal::send('auth.pwreset.email', $this->getUser(), $info); $msg = $ost->replaceTemplateVariables(array('subj' => $content->getName(), 'body' => $content->getBody()), $vars); $_config = new Config('pwreset'); $_config->set($vars['token'], $this->getUser()->getId()); $email->send($this->getUser()->getEmail(), Format::striptags($msg['subj']), $msg['body']); return true; }
function create($vars) { global $cfg; //Must have... if (!$vars['ticketId'] || !$vars['type'] || !in_array($vars['type'], array('M', 'R', 'N'))) { return false; } if (!$vars['body'] instanceof ThreadBody) { if ($cfg->isHtmlThreadEnabled()) { $vars['body'] = new HtmlThreadBody($vars['body']); } else { $vars['body'] = new TextThreadBody($vars['body']); } } // Drop stripped images if ($vars['attachments']) { foreach ($vars['body']->getStrippedImages() as $cid) { foreach ($vars['attachments'] as $i => $a) { if (@$a['cid'] && $a['cid'] == $cid) { // Inline referenced attachment was stripped unset($vars['attachments'][$i]); } } } } // Handle extracted embedded images (<img src="data:base64,..." />). // The extraction has already been performed in the ThreadBody // class. Here they should simply be added to the attachments list if ($atts = $vars['body']->getEmbeddedHtmlImages()) { if (!is_array($vars['attachments'])) { $vars['attachments'] = array(); } foreach ($atts as $info) { $vars['attachments'][] = $info; } } if (!($body = $vars['body']->getClean())) { $body = '-'; } //Special tag used to signify empty message as stored. $poster = $vars['poster']; if ($poster && is_object($poster)) { $poster = (string) $poster; } $sql = ' INSERT INTO ' . TICKET_THREAD_TABLE . ' SET created=NOW() ' . ' ,thread_type=' . db_input($vars['type']) . ' ,ticket_id=' . db_input($vars['ticketId']) . ' ,title=' . db_input(Format::sanitize($vars['title'], true)) . ' ,format=' . db_input($vars['body']->getType()) . ' ,staff_id=' . db_input($vars['staffId']) . ' ,user_id=' . db_input($vars['userId']) . ' ,poster=' . db_input($poster) . ' ,source=' . db_input($vars['source']); if (!isset($vars['attachments']) || !$vars['attachments']) { // Otherwise, body will be configured in a block below (after // inline attachments are saved and updated in the database) $sql .= ' ,body=' . db_input($body); } if (isset($vars['pid'])) { $sql .= ' ,pid=' . db_input($vars['pid']); } elseif (isset($vars['reply_to']) && $vars['reply_to'] instanceof ThreadEntry) { $sql .= ' ,pid=' . db_input($vars['reply_to']->getId()); } if ($vars['ip_address']) { $sql .= ' ,ip_address=' . db_input($vars['ip_address']); } //echo $sql; if (!db_query($sql) || !($entry = self::lookup(db_insert_id(), $vars['ticketId']))) { return false; } /************* ATTACHMENTS *****************/ //Upload/save attachments IF ANY if ($vars['files']) { //expects well formatted and VALIDATED files array. $entry->uploadFiles($vars['files']); } //Canned attachments... if ($vars['cannedattachments'] && is_array($vars['cannedattachments'])) { $entry->saveAttachments($vars['cannedattachments']); } //Emailed or API attachments if (isset($vars['attachments']) && $vars['attachments']) { foreach ($vars['attachments'] as &$a) { if (isset($a['cid']) && $a['cid'] && strpos($body, 'cid:' . $a['cid']) !== false) { $a['inline'] = true; } } unset($a); $entry->importAttachments($vars['attachments']); foreach ($vars['attachments'] as $a) { // Change <img src="cid:"> inside the message to point to // a unique hash-code for the attachment. Since the // content-id will be discarded, only the unique hash-code // will be available to retrieve the image later if ($a['cid'] && $a['key']) { $body = preg_replace('/src=("|\'|\\b)(?:cid:)?' . preg_quote($a['cid'], '/') . '\\1/i', 'src="cid:' . $a['key'] . '"', $body); } } $sql = 'UPDATE ' . TICKET_THREAD_TABLE . ' SET body=' . db_input($body) . ' WHERE `id`=' . db_input($entry->getId()); if (!db_query($sql) || !db_affected_rows()) { return false; } } // Email message id (required for all thread posts) if (!isset($vars['mid'])) { $vars['mid'] = sprintf('<%s@%s>', Misc::randCode(24), substr(md5($cfg->getUrl()), -10)); } $entry->saveEmailInfo($vars); // Inline images (attached to the draft) $entry->saveAttachments(Draft::getAttachmentIds($body)); Signal::send('model.created', $entry); return $entry; }
break; case 'newpasswd': // TODO: Compare passwords $tpl = 'pwreset.login.php'; $_config = new Config('pwreset'); if (($staff = new StaffSession($_POST['userid'])) && !$staff->getId()) { $msg = 'Invalid user-id given'; } elseif (!($id = $_config->get($_POST['token'])) || $id != $staff->getId()) { $msg = 'Invalid reset token'; } elseif (!($ts = $_config->lastModified($_POST['token'])) && $ost->getConfig()->getPwResetWindow() < time() - strtotime($ts)) { $msg = 'Invalid reset token'; } elseif (!$staff->forcePasswdRest()) { $msg = 'Unable to reset password'; } else { $info = array('page' => 'index.php'); Signal::send('auth.pwreset.login', $staff, $info); Staff::_do_login($staff, $_POST['userid']); $_SESSION['_staff']['reset-token'] = $_POST['token']; header('Location: ' . $info['page']); exit; } break; } } elseif ($_GET['token']) { $msg = 'Re-enter your username or email'; $_config = new Config('pwreset'); if (($id = $_config->get($_GET['token'])) && ($staff = Staff::lookup($id))) { $tpl = 'pwreset.login.php'; } else { header('Location: index.php'); }
<?php /********************************************************************* http.php HTTP controller for the osTicket API Jared Hancock Copyright (c) 2006-2013 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: **********************************************************************/ // Use sessions — it's important for SSO authentication, which uses // /api/auth/ext define('DISABLE_SESSION', false); require 'api.inc.php'; # Include the main api urls require_once INCLUDE_DIR . "class.dispatcher.php"; $dispatcher = patterns('', url_post("^/tickets\\.(?P<format>xml|json|email)\$", array('api.tickets.php:TicketApiController', 'create')), url('^/tasks/', patterns('', url_post("^cron\$", array('api.cron.php:CronApiController', 'execute'))))); Signal::send('api', $dispatcher); # Call the respective function print $dispatcher->resolve($ost->get_path_info());
function onUnhandledException($ex) { $info = array('exception' => $ex); Signal::send('php.exception', $this, $info); }
function dump($error_stream) { // Allow plugins to change the tables exported Signal::send('export.tables', $this, $this->tables); $this->dump_header(); foreach ($this->tables as $t) { if ($error_stream) { $error_stream->write("{$t}\n"); } // Inspect schema $table = array(); $res = db_query("select column_name from information_schema.columns\n where table_schema=DATABASE() and table_name='{$t}'"); while (list($field) = db_fetch_row($res)) { $table[] = $field; } if (!$table) { if ($error_stream) { $error_stream->write($t . ': Cannot export table with no fields' . "\n"); } die; } $this->write_block(array('table', substr($t, strlen(TABLE_PREFIX)), $table)); db_query("select * from {$t}"); // Dump row data while ($row = db_fetch_row($res)) { $this->write_block($row); } $this->write_block(array('end-table')); } }
function log($priority, $title, $message, $alert = false, $force = false) { //We are providing only 3 levels of logs. Windows style. switch ($priority) { case LOG_EMERG: case LOG_ALERT: case LOG_CRIT: case LOG_ERR: $level = 1; //Error break; case LOG_WARN: case LOG_WARNING: $level = 2; //Warning break; case LOG_NOTICE: case LOG_INFO: case LOG_DEBUG: default: $level = 3; //Debug } $loglevel = array(1 => 'Error', 'Warning', 'Debug'); $info = array('title' => &$title, 'level' => $loglevel[$level], 'level_id' => $level, 'body' => &$message); Signal::send('syslog', null, $info); //Logging everything during upgrade. if ($this->getConfig()->getLogLevel() < $level && !$force) { return false; } //Alert admin if enabled... if ($alert && $this->getConfig()->getLogLevel() >= $level) { $this->alertAdmin($title, $message); } //Save log based on system log level settings. $sql = 'INSERT INTO ' . SYSLOG_TABLE . ' SET created=NOW(), updated=NOW() ' . ',title=' . db_input(Format::sanitize($title, true)) . ',log_type=' . db_input($loglevel[$level]) . ',log=' . db_input(Format::sanitize($message, false)) . ',ip_address=' . db_input($_SERVER['REMOTE_ADDR']); db_query($sql, false); return true; }
function login($client, $bk) { $_SESSION['_client']['reset-token'] = $_POST['token']; Signal::send('auth.pwreset.login', $client); return parent::login($client, $bk); }
function update($vars, &$errors) { $valid = true; $forms = $this->getForms($vars); foreach ($forms as $cd) { if (!$cd->isValid()) { $valid = false; } if ($cd->get('type') == 'O' && ($form = $cd->getForm($vars)) && ($f = $form->getField('name')) && $f->getClean() && ($o = Organization::lookup(array('name' => $f->getClean()))) && $o->id != $this->getId()) { $valid = false; $f->addError(__('Organization with the same name already exists')); } } if ($vars['domain']) { foreach (explode(',', $vars['domain']) as $d) { if (!Validator::is_email('t@' . trim($d))) { $errors['domain'] = __('Enter a valid email domain, like domain.com'); } } } if ($vars['manager']) { switch ($vars['manager'][0]) { case 's': if ($staff = Staff::lookup(substr($vars['manager'], 1))) { break; } case 't': if ($vars['manager'][0] == 't' && ($team = Team::lookup(substr($vars['manager'], 1)))) { break; } default: $errors['manager'] = __('Select an agent or team from the list'); } } if (!$valid || $errors) { return false; } foreach ($this->getDynamicData() as $cd) { if (($f = $cd->getForm()) && $f->get('type') == 'O' && ($name = $f->getField('name'))) { $this->name = $name->getClean(); $this->save(); } $cd->setSource($vars); if ($cd->save()) { $this->updated = SqlFunction::NOW(); } } // Set flags foreach (array('collab-all-flag' => Organization::COLLAB_ALL_MEMBERS, 'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT, 'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER) as $ck => $flag) { if ($vars[$ck]) { $this->setStatus($flag); } else { $this->clearStatus($flag); } } // Set staff and primary contacts $this->set('domain', $vars['domain']); $this->set('manager', $vars['manager'] ?: ''); if ($vars['contacts'] && is_array($vars['contacts'])) { foreach ($this->allMembers() as $u) { $u->setPrimaryContact(array_search($u->id, $vars['contacts']) !== false); $u->save(); } } // Send signal for search engine updating if not modifying the // fields specific to the organization if (count($this->dirty) === 0) { Signal::send('model.updated', $this); } return $this->save(); }
function sendResetEmail($template = 'pwreset-staff', $log = true) { global $ost, $cfg; $content = Page::lookup(Page::getIdByType($template)); $token = Misc::randCode(48); // 290-bits if (!$content) { return new Error('Unable to retrieve password reset email template'); } $vars = array('url' => $ost->getConfig()->getBaseUrl(), 'token' => $token, 'staff' => $this, 'recipient' => $this, 'reset_link' => sprintf("%s/scp/pwreset.php?token=%s", $ost->getConfig()->getBaseUrl(), $token)); $vars['link'] =& $vars['reset_link']; if (!($email = $cfg->getAlertEmail())) { $email = $cfg->getDefaultEmail(); } $info = array('email' => $email, 'vars' => &$vars, 'log' => $log); Signal::send('auth.pwreset.email', $this, $info); if ($info['log']) { $ost->logWarning(_S('Agent Password Reset'), sprintf(_S('Password reset was attempted for agent: %1$s<br><br> Requested-User-Id: %2$s<br> Source-Ip: %3$s<br> Email-Sent-To: %4$s<br> Email-Sent-Via: %5$s'), $this->getName(), $_POST['userid'], $_SERVER['REMOTE_ADDR'], $this->getEmail(), $email->getEmail()), false); } $msg = $ost->replaceTemplateVariables(array('subj' => $content->getName(), 'body' => $content->getBody()), $vars); $_config = new Config('pwreset'); $_config->set($vars['token'], $this->getId()); $email->send($this->getEmail(), Format::striptags($msg['subj']), $msg['body']); }
function sendResetEmail() { global $ost, $cfg; if (!($tpl = $this->getDept()->getTemplate())) { $tpl = $ost->getConfig()->getDefaultTemplate(); } $token = Misc::randCode(48); // 290-bits if (!($template = $tpl->getMsgTemplate('staff.pwreset'))) { return new Error('Unable to retrieve password reset email template'); } $vars = array('url' => $ost->getConfig()->getBaseUrl(), 'token' => $token, 'reset_link' => sprintf("%s/scp/pwreset.php?token=%s", $ost->getConfig()->getBaseUrl(), $token)); if (!($email = $cfg->getAlertEmail())) { $email = $cfg->getDefaultEmail(); } $info = array('email' => $email, 'vars' => &$vars); Signal::send('auth.pwreset.email', $this, $info); $msg = $ost->replaceTemplateVariables($template->asArray(), $vars); $_config = new Config('pwreset'); $_config->set($vars['token'], $this->getId()); $email->send($this->getEmail(), $msg['subj'], $msg['body']); }
function run() { //called by outside cron NOT autocron global $ost; if (!$ost || $ost->isUpgradePending()) { return; } self::MailFetcher(); self::TicketMonitor(); self::PurgeLogs(); // Run file purging about every 10 cron runs if (mt_rand(1, 9) == 4) { self::CleanOrphanedFiles(); } self::PurgeDrafts(); self::MaybeOptimizeTables(); $data = array('autocron' => false); Signal::send('cron', $data); }
function save($refetch = false) { $pk = static::$meta['pk']; if (!is_array($pk)) { $pk = array($pk); } if ($this->__new__) { $sql = 'INSERT INTO ' . static::$meta['table']; } else { $sql = 'UPDATE ' . static::$meta['table']; } $filter = $fields = array(); if (count($this->dirty) === 0) { return true; } foreach ($this->dirty as $field => $old) { if ($this->__new__ or !in_array($field, $pk)) { if (@get_class($this->get($field)) == 'SqlFunction') { $fields[] = $field . ' = ' . $this->get($field)->toSql(); } else { $fields[] = $field . ' = ' . db_input($this->get($field)); } } } $sql .= ' SET ' . implode(', ', $fields); if (!$this->__new__) { foreach ($pk as $p) { $filter[] = $p . ' = ' . db_input($this->get($p)); } $sql .= ' WHERE ' . implode(' AND ', $filter); $sql .= ' LIMIT 1'; } if (!db_query($sql) || db_affected_rows() != 1) { throw new Exception(db_error()); } if ($this->__new__) { if (count($pk) == 1) { $this->ht[$pk[0]] = db_insert_id(); } $this->__new__ = false; // Setup lists again $this->__setupForeignLists(); Signal::send('model.created', $this); } else { $data = array('dirty' => $this->dirty); Signal::send('model.updated', $this, $data); } # Refetch row from database # XXX: Too much voodoo if ($refetch) { # XXX: Support composite PK $criteria = array($pk[0] => $this->get($pk[0])); $self = static::lookup($criteria); $this->ht = $self->ht; } $this->dirty = array(); return $this->get($pk[0]); }
function update($vars, &$errors) { global $cfg; $rtoken = $_SESSION['_client']['reset-token']; if ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd'] || $rtoken) { if (!$vars['passwd1']) { $errors['passwd1'] = __('New password is required'); } elseif ($vars['passwd1'] && strlen($vars['passwd1']) < 6) { $errors['passwd1'] = __('Password must be at least 6 characters'); } elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) { $errors['passwd2'] = __('Passwords do not match'); } if ($rtoken) { $_config = new Config('pwreset'); if ($_config->get($rtoken) != $this->getUserId()) { $errors['err'] = __('Invalid reset token. Logout and try again'); } elseif (!($ts = $_config->lastModified($rtoken)) && $cfg->getPwResetWindow() < time() - strtotime($ts)) { $errors['err'] = __('Invalid reset token. Logout and try again'); } } elseif ($this->get('passwd')) { if (!$vars['cpasswd']) { $errors['cpasswd'] = __('Current password is required'); } elseif (!$this->hasCurrentPassword($vars['cpasswd'])) { $errors['cpasswd'] = __('Invalid current password!'); } elseif (!strcasecmp($vars['passwd1'], $vars['cpasswd'])) { $errors['passwd1'] = __('New password MUST be different from the current password!'); } } } if (!$vars['timezone_id']) { $errors['timezone_id'] = __('Time zone selection is required'); } if ($errors) { return false; } $this->set('timezone_id', $vars['timezone_id']); $this->set('dst', isset($vars['dst']) ? 1 : 0); // Change language $this->set('lang', $vars['lang'] ?: null); $_SESSION['client:lang'] = null; TextDomain::configureForUser($this); if ($vars['backend']) { $this->set('backend', $vars['backend']); if ($vars['username']) { $this->set('username', $vars['username']); } } if ($vars['passwd1']) { $this->set('passwd', Passwd::hash($vars['passwd1'])); $info = array('password' => $vars['passwd1']); Signal::send('auth.pwchange', $this->getUser(), $info); $this->cancelResetTokens(); $this->clearStatus(UserAccountStatus::REQUIRE_PASSWD_RESET); } return $this->save(); }
function install($vars) { $this->errors=$f=array(); $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>__('Name required')); $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>__('Valid email required')); $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>__('First name required')); $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>__('Last name required')); $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>__('Valid email required')); $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>__('Username required')); $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>__('Password required')); $f['passwd2'] = array('type'=>'password', 'required'=>1, 'error'=>__('Confirm Password')); $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>__('Table prefix required')); $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>__('Host name required')); $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>__('Database name required')); $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>__('Username required')); $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>__('Password required')); $vars = array_map('trim', $vars); if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) $this->errors['err']=__('Missing or invalid data - correct the errors and try again.'); //Staff's email can't be same as system emails. if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) $this->errors['admin_email']=__('Conflicts with system email above'); //Admin's pass confirmation. if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) $this->errors['passwd2']=__('Password(s) do not match'); //Check table prefix underscore required at the end! if($vars['prefix'] && substr($vars['prefix'], -1)!='_') $this->errors['prefix']=__('Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''); //Make sure admin username is not very predictable. XXX: feels dirty but necessary if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) $this->errors['username']=__('Bad username'); // Support port number specified in the hostname with a colon (:) list($host, $port) = explode(':', $vars['dbhost']); if ($port && is_numeric($port) && ($port < 1 || $port > 65535)) $this->errors['db'] = __('Invalid database port number'); //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) if(!$this->errors) { if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) $this->errors['db']=sprintf(__('Unable to connect to MySQL server: %s'), db_connect_error()); elseif(explode('.', db_version()) < explode('.', $this->getMySQLVersion())) $this->errors['db']=sprintf(__('osTicket requires MySQL %s or later!'),$this->getMySQLVersion()); elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { $this->errors['dbname']=__("Database doesn't exist"); $this->errors['db']=__('Unable to create the database.'); } elseif(!db_select_database($vars['dbname'])) { $this->errors['dbname']=__('Unable to select the database'); } else { //Abort if we have another installation (or table) with same prefix. $sql = 'SELECT * FROM `'.$vars['prefix'].'config` LIMIT 1'; if(db_query($sql, false)) { $this->errors['err'] = __('We have a problem - another installation with same table prefix exists!'); $this->errors['prefix'] = __('Prefix already in-use'); } else { //Try changing charset and collation of the DB - no bigie if we fail. db_query('ALTER DATABASE '.$vars['dbname'].' DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci', false); } } } //bailout on errors. if($this->errors) return false; /*************** We're ready to install ************************/ define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. define('TABLE_PREFIX',$vars['prefix']); //Table prefix Bootstrap::defineTables(TABLE_PREFIX); Bootstrap::loadCode(); $debug = true; // Change it to false to squelch SQL errors. //Last minute checks. if(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) $this->errors['err']=__('Unable to read config file. Permission denied! (#2)'); elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) $this->errors['err']=__('Unable to open config file for writing. Permission denied! (#3)'); else { $streams = DatabaseMigrater::getUpgradeStreams(INCLUDE_DIR.'upgrader/streams/'); foreach ($streams as $stream=>$signature) { $schemaFile = INC_DIR."streams/$stream/install-mysql.sql"; if (!file_exists($schemaFile) || !($fp2 = fopen($schemaFile, 'rb'))) $this->errors['err'] = sprintf( __('%s: Internal Error - please make sure your download is the latest (#1)'), $stream); elseif ( // TODO: Make the hash algo configurable in the streams // configuration ( core : md5 ) !($hash = md5(fread($fp2, filesize($schemaFile)))) || strcasecmp($signature, $hash)) $this->errors['err'] = sprintf( __('%s: Unknown or invalid schema signature (%s .. %s)'), $stream, $signature, $hash); elseif (!$this->load_sql_file($schemaFile, $vars['prefix'], true, $debug)) $this->errors['err'] = sprintf( __('%s: Error parsing SQL schema! Get help from developers (#4)'), $stream); } } if(!$this->errors) { // TODO: Use language selected from install worksheet $i18n = new Internationalization($vars['lang_id']); $i18n->loadDefaultData(); Signal::send('system.install', $this); $sql='SELECT `id` FROM '.TABLE_PREFIX.'sla ORDER BY `id` LIMIT 1'; $sla_id_1 = db_result(db_query($sql, false)); $sql='SELECT `dept_id` FROM '.TABLE_PREFIX.'department ORDER BY `dept_id` LIMIT 1'; $dept_id_1 = db_result(db_query($sql, false)); $sql='SELECT `tpl_id` FROM '.TABLE_PREFIX.'email_template_group ORDER BY `tpl_id` LIMIT 1'; $template_id_1 = db_result(db_query($sql, false)); $sql='SELECT `group_id` FROM '.TABLE_PREFIX.'groups ORDER BY `group_id` LIMIT 1'; $group_id_1 = db_result(db_query($sql, false)); $sql='SELECT `value` FROM '.TABLE_PREFIX.'config WHERE namespace=\'core\' and `key`=\'default_timezone_id\' LIMIT 1'; $default_timezone = db_result(db_query($sql, false)); //Create admin user. $sql='INSERT INTO '.TABLE_PREFIX.'staff SET created=NOW() ' .", isactive=1, isadmin=1, group_id='$group_id_1', dept_id='$dept_id_1'" .", timezone_id='$default_timezone', max_page_size=25" .', email='.db_input($vars['admin_email']) .', firstname='.db_input($vars['fname']) .', lastname='.db_input($vars['lname']) .', username='******'username']) .', passwd='.db_input(Passwd::hash($vars['passwd'])); if(!db_query($sql, false) || !($uid=db_insert_id())) $this->errors['err']=__('Unable to create admin user (#6)'); } if(!$this->errors) { //Create default emails! $email = $vars['email']; list(,$domain)=explode('@',$vars['email']); $sql='INSERT INTO '.TABLE_PREFIX.'email (`name`,`email`,`created`,`updated`) VALUES ' ." ('Support','$email',NOW(),NOW())" .",('osTicket Alerts','alerts@$domain',NOW(),NOW())" .",('','noreply@$domain',NOW(),NOW())"; $support_email_id = db_query($sql, false) ? db_insert_id() : 0; $sql='SELECT `email_id` FROM '.TABLE_PREFIX."email WHERE `email`='alerts@$domain' LIMIT 1"; $alert_email_id = db_result(db_query($sql, false)); //Create config settings---default settings! $defaults = array( 'default_email_id'=>$support_email_id, 'alert_email_id'=>$alert_email_id, 'default_dept_id'=>$dept_id_1, 'default_sla_id'=>$sla_id_1, 'default_template_id'=>$template_id_1, 'admin_email'=>$vars['admin_email'], 'schema_signature'=>$streams['core'], 'helpdesk_url'=>URL, 'helpdesk_title'=>$vars['name']); $config = new Config('core'); if (!$config->updateAll($defaults)) $this->errors['err']=__('Unable to create config settings').' (#7)'; // Set company name require_once(INCLUDE_DIR.'class.company.php'); $company = new Company(); $company->getForm()->setAnswer('name', $vars['name']); $company->getForm()->save(); foreach ($streams as $stream=>$signature) { if ($stream != 'core') { $config = new Config($stream); if (!$config->update('schema_signature', $signature)) $this->errors['err']=__('Unable to create config settings').' (#8)'; } } } if($this->errors) return false; //Abort on internal errors. //Rewrite the config file - MUST be done last to allow for installer recovery. $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); $configFile= str_replace('%CONFIG-SIRI',Misc::randCode(32),$configFile); if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { $this->errors['err']=__('Unable to write to config file. Permission denied! (#5)'); return false; } @fclose($fp); /************* Make the system happy ***********************/ $sql='UPDATE '.TABLE_PREFIX."email SET dept_id=$dept_id_1"; db_query($sql, false); global $cfg; $cfg = new OsticketConfig(); //Create a ticket to make the system warm and happy. $errors = array(); $ticket_vars = $i18n->getTemplate('templates/ticket/installed.yaml') ->getData(); $ticket = Ticket::create($ticket_vars, $errors, 'api', false, false); if ($ticket && ($org = Organization::objects()->order_by('id')->one())) { $user=User::lookup($ticket->getOwnerId()); $user->setOrganization($org); } //TODO: create another personalized ticket and assign to admin?? //Log a message. $msg=__("Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"); $sql='INSERT INTO '.TABLE_PREFIX.'syslog SET created=NOW(), updated=NOW(), log_type="Debug" ' .', title="osTicket installed!"' .', log='.db_input($msg) .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); db_query($sql, false); return true; }
Peter Rotich <*****@*****.**> Copyright (c) 2006-2013 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: **********************************************************************/ # Override staffLoginPage() defined in staff.inc.php to return an # HTTP/Forbidden status rather than the actual login page. # XXX: This should be moved to the AjaxController class function staffLoginPage($msg = 'Unauthorized') { Http::response(403, 'Must login: '******'staff.inc.php'; //Clean house...don't let the world see your crap. ini_set('display_errors', '0'); //Disable error display ini_set('display_startup_errors', '0'); //TODO: disable direct access via the browser? i,e All request must have REFER? if (!defined('INCLUDE_DIR')) { Http::response(500, 'Server configuration error'); } require_once INCLUDE_DIR . '/class.dispatcher.php'; $dispatcher = new Dispatcher(); Signal::send('apps.scp', $dispatcher); # Call the respective function print $dispatcher->resolve($ost->get_path_info());
static function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $ost, $cfg, $thisclient, $_FILES; // Don't enforce form validation for email $field_filter = function ($type) use($origin) { return function ($f) use($origin, $type) { // Ultimately, only offer validation errors for web for // non-internal fields. For email, no validation can be // performed. For other origins, validate as usual switch (strtolower($origin)) { case 'email': return false; case 'staff': // Required 'Contact Information' fields aren't required // when staff open tickets return $type != 'user' || in_array($f->get('name'), array('name', 'email')); case 'web': return !$f->get('private'); default: return true; } }; }; $reject_ticket = function ($message) use(&$errors) { global $ost; $errors = array('errno' => 403, 'err' => __('This help desk is for use by authorized users only')); $ost->logWarning(_S('Ticket Denied'), $message, false); return 0; }; Signal::send('ticket.create.before', null, $vars); // Create and verify the dynamic form entry for the new ticket $form = TicketForm::getNewInstance(); $form->setSource($vars); // If submitting via email or api, ensure we have a subject and such if (!in_array(strtolower($origin), array('web', 'staff'))) { foreach ($form->getFields() as $field) { $fname = $field->get('name'); if ($fname && isset($vars[$fname]) && !$field->value) { $field->value = $field->parse($vars[$fname]); } } } if (!$form->isValid($field_filter('ticket'))) { $errors += $form->errors(); } if ($vars['uid']) { $user = User::lookup($vars['uid']); } $id = 0; $fields = array(); $fields['message'] = array('type' => '*', 'required' => 1, 'error' => __('Message content is required')); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Select a help topic')); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 0, 'error' => __('Department selection is required')); $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Help topic selection is required')); $fields['duedate'] = array('type' => 'date', 'required' => 0, 'error' => __('Invalid date format - must be MM/DD/YY')); case 'api': $fields['source'] = array('type' => 'string', 'required' => 1, 'error' => __('Indicate ticket source')); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => __('Unknown system email')); break; default: # TODO: Return error message $errors['err'] = $errors['origin'] = __('Invalid ticket origin given'); } if (!Validator::process($fields, $vars, $errors) && !$errors['err']) { $errors['err'] = __('Missing or invalid data - check the errors and try again'); } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = __('Select a time from the list'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = __('Invalid due date'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = __('Due date must be in the future'); } } if (!$errors) { # Perform ticket filter actions on the new ticket arguments $__form = null; if ($vars['topicId']) { if (($__topic = Topic::lookup($vars['topicId'])) && ($__form = $__topic->getForm())) { $__form = $__form->instanciate(); $__form->setSource($vars); } } try { $vars = self::filterTicketData($origin, $vars, array($form, $__form), $user); } catch (RejectedException $ex) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) by filter "%s"'), $ex->vars['email'], $ex->getRejectingFilter()->getName())); } //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($_user = TicketUser::lookupByEmail($vars['email'])) && ($openTickets = $_user->getNumOpenTickets()) && $openTickets >= $cfg->getMaxOpenTickets()) { $errors = array('err' => __("You've reached the maximum open tickets allowed.")); $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']), sprintf(_S('Max open tickets (%1$d) reached for %2$s'), $cfg->getMaxOpenTickets(), $vars['email']), false); return 0; } // Allow vars to be changed in ticket filter and applied to the user // account created or detected if (!$user && $vars['email']) { $user = User::lookupByEmail($vars['email']); } if (!$user) { // Reject emails if not from registered clients (if // configured) if (strcasecmp($origin, 'email') === 0 && !$cfg->acceptUnregisteredEmail()) { list($mailbox, $domain) = explode('@', $vars['email'], 2); // Users not yet created but linked to an organization // are still acceptable if (!Organization::forDomain($domain)) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) (unregistered client)'), $vars['email'])); } } $user_form = UserForm::getUserForm()->getForm($vars); if (!$user_form->isValid($field_filter('user')) || !($user = User::fromVars($user_form->getClean()))) { $errors['user'] = __('Incomplete client information'); } } } if ($vars['topicId']) { if ($topic = Topic::lookup($vars['topicId'])) { if ($topic_form = $topic->getForm()) { $TF = $topic_form->getForm($vars); $topic_form = $topic_form->instanciate(); $topic_form->setSource($vars); if (!$TF->isValid($field_filter('topic'))) { $errors = array_merge($errors, $TF->errors()); } } } else { $errors['topicId'] = 'Invalid help topic selected'; } } // Any error above is fatal. if ($errors) { return 0; } Signal::send('ticket.create.validated', null, $vars); # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) { $autorespond = $vars['autorespond']; } # Apply filter-specific priority if ($vars['priorityId']) { $form->setAnswer('priority', null, $vars['priorityId']); } // If the filter specifies a help topic which has a form associated, // and there was previously either no help topic set or the help // topic did not have a form, there's no need to add it now as (1) // validation is closed, (2) there may be a form already associated // and filled out from the original help topic, and (3) staff // members can always add more forms now // OK...just do it. $statusId = $vars['statusId']; $deptId = $vars['deptId']; //pre-selected Dept if any. $source = ucfirst($vars['source']); // Apply email settings for emailed tickets. Email settings should // trump help topic settins if the email has an associated help // topic if ($vars['emailId'] && ($email = Email::lookup($vars['emailId']))) { $deptId = $deptId ?: $email->getDeptId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $email->getPriorityId()); } if ($autorespond) { $autorespond = $email->autoRespond(); } if (!isset($topic) && ($T = $email->getTopic()) && $T->isActive()) { $topic = $T; } $email = null; $source = 'Email'; } if (!isset($topic)) { // This may return NULL, no big deal $topic = $cfg->getDefaultTopic(); } // Intenal mapping magic...see if we need to override anything if (isset($topic)) { $deptId = $deptId ?: $topic->getDeptId(); $statusId = $statusId ?: $topic->getStatusId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $topic->getPriorityId()); } if ($autorespond) { $autorespond = $topic->autoRespond(); } //Auto assignment. if (!isset($vars['staffId']) && $topic->getStaffId()) { $vars['staffId'] = $topic->getStaffId(); } elseif (!isset($vars['teamId']) && $topic->getTeamId()) { $vars['teamId'] = $topic->getTeamId(); } //set default sla. if (isset($vars['slaId'])) { $vars['slaId'] = $vars['slaId'] ?: $cfg->getDefaultSLAId(); } elseif ($topic && $topic->getSLAId()) { $vars['slaId'] = $topic->getSLAId(); } } // Auto assignment to organization account manager if (($org = $user->getOrganization()) && $org->autoAssignAccountManager() && ($code = $org->getAccountManagerId())) { if (!isset($vars['staffId']) && $code[0] == 's') { $vars['staffId'] = substr($code, 1); } elseif (!isset($vars['teamId']) && $code[0] == 't') { $vars['teamId'] = substr($code, 1); } } // Last minute checks $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $cfg->getDefaultPriorityId()); } $deptId = $deptId ?: $cfg->getDefaultDeptId(); $statusId = $statusId ?: $cfg->getDefaultTicketStatusId(); $topicId = isset($topic) ? $topic->getId() : 0; $ipaddress = $vars['ip'] ?: $_SERVER['REMOTE_ADDR']; $source = $source ?: 'Web'; //We are ready son...hold on to the rails. $number = $topic ? $topic->getNewTicketNumber() : $cfg->getNewTicketNumber(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,user_id=' . db_input($user->getId()) . ' ,`number`=' . db_input($number) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); if (isset($vars['emailId']) && $vars['emailId']) { $sql .= ', email_id=' . db_input($vars['emailId']); } //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ // Save the (common) dynamic form $form->setTicketId($id); $form->save(); // Save the form data from the help-topic form, if any if ($topic_form) { $topic_form->setTicketId($id); $topic_form->save(); } $ticket->loadDynamicData(); $dept = $ticket->getDept(); // Add organizational collaborators if ($org && $org->autoAddCollabs()) { $pris = $org->autoAddPrimaryContactsAsCollabs(); $members = $org->autoAddMembersAsCollabs(); $settings = array('isactive' => true); $collabs = array(); foreach ($org->allMembers() as $u) { if ($members || $pris && $u->isPrimaryContact()) { if ($c = $ticket->addCollaborator($u, $settings, $errors)) { $collabs[] = (string) $c; } } } //TODO: Can collaborators add others? if ($collabs) { //TODO: Change EndUser to name of user. $ticket->logNote(sprintf(_S('Collaborators for %s organization added'), $org->getName()), implode("<br>", $collabs), $org->getName(), false); } } //post the message. $vars['title'] = $vars['subject']; //Use the initial subject as title of the post. $vars['userId'] = $ticket->getUserId(); $message = $ticket->postMessage($vars, $origin, false); // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); // Assign ticket to staff or team (new ticket by staff) if ($vars['assignId']) { $ticket->assign($vars['assignId'], $vars['note']); } else { // Auto assign staff or team - auto assignment based on filter // rules. Both team and staff can be assigned if ($vars['staffId']) { $ticket->assignToStaff($vars['staffId'], _S('Auto Assignment')); } if ($vars['teamId']) { // No team alert if also assigned to an individual agent $ticket->assignToTeam($vars['teamId'], _S('Auto Assignment'), !$vars['staffId']); } } // Apply requested status — this should be done AFTER assignment, // because if it is requested to be closed, it should not cause the // ticket to be reopened for assignment. if ($statusId) { $ticket->setStatus($statusId, false, false); } /********** double check auto-response ************/ //Override auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if (isset($vars['flags']) && $vars['flags']['bounce']) { $autorespond = false; } if ($autorespond && $message->isAutoReply()) { $autorespond = false; } //post canned auto-response IF any (disables new ticket auto-response). if ($vars['cannedResponseId'] && $ticket->postCannedReply($vars['cannedResponseId'], $message->getId(), $autorespond)) { $ticket->markUnAnswered(); //Leave the ticket as unanswred. $autorespond = false; } //Check department's auto response settings // XXX: Dept. setting doesn't affect canned responses. if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } //Don't send alerts to staff when the message is a bounce // this is necessary to avoid possible loop (especially on new ticket) if ($alertstaff && $message->isBounce()) { $alertstaff = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($message, $autorespond, $alertstaff); /************ check if the user JUST reached the max. open tickets limit **********/ if ($cfg->getMaxOpenTickets() > 0 && ($user = $ticket->getOwner()) && $user->getNumOpenTickets() == $cfg->getMaxOpenTickets()) { $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff')); } /* Start tracking ticket lifecycle events */ $ticket->logEvent('created'); // Fire post-create signal (for extra email sending, searching) Signal::send('model.created', $ticket); /* Phew! ... time for tea (KETEPA) */ return $ticket; }
<?php /********************************************************************* dispatcher.php Dispatcher for client applications Jared Hancock <*****@*****.**> Peter Rotich <*****@*****.**> Copyright (c) 2006-2013 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: **********************************************************************/ function clientLoginPage($msg = 'Unauthorized') { Http::response(403, 'Must login: '******'client.inc.php'; if (!defined('INCLUDE_DIR')) { Http::response(500, 'Server configuration error'); } require_once INCLUDE_DIR . '/class.dispatcher.php'; $dispatcher = new Dispatcher(); Signal::send('ajax.client', $dispatcher); print $dispatcher->resolve($ost->get_path_info());
function dump($error_stream) { // Allow plugins to change the tables exported Signal::send('export.tables', $this, $this->tables); $header = array(array(OSTICKET_BACKUP_SIGNATURE, OSTICKET_BACKUP_VERSION), array('version' => THIS_VERSION, 'table_prefix' => TABLE_PREFIX, 'salt' => SECRET_SALT, 'dbtype' => DBTYPE, 'streams' => DatabaseMigrater::getUpgradeStreams(UPGRADE_DIR . 'streams/'))); $this->write_block($header); foreach ($this->tables as $t) { if ($error_stream) { $error_stream->write("{$t}\n"); } // Inspect schema $table = $indexes = array(); $res = db_query("show columns from {$t}"); while ($field = db_fetch_array($res)) { $table[] = $field; } $res = db_query("show indexes from {$t}"); while ($col = db_fetch_array($res)) { $indexes[] = $col; } $res = db_query("select * from {$t}"); $types = array(); if (!$table) { if ($error_stream) { $error_stream->write($t . ': Cannot export table with no fields' . "\n"); } die; } $this->write_block(array('table', substr($t, strlen(TABLE_PREFIX)), $table, $indexes)); // Dump row data while ($row = db_fetch_row($res)) { $this->write_block($row); } $this->write_block(array('end-table')); } }