function _uploadInlineImage($draft) { if (!isset($_POST['data']) && !isset($_FILES['file'])) { Http::response(422, "File not included properly"); } # Fixup for expected multiple attachments if (isset($_FILES['file'])) { foreach ($_FILES['file'] as $k => $v) { $_FILES['image'][$k] = array($v); } unset($_FILES['file']); $file = AttachmentFile::format($_FILES['image'], true); # TODO: Detect unacceptable attachment extension # TODO: Verify content-type and check file-content to ensure image if (!($ids = $draft->attachments->upload($file))) { if ($file[0]['error']) { return Http::response(403, JsonDataEncoder::encode(array('error' => $file[0]['error']))); } else { return Http::response(500, 'Unable to attach image'); } } $id = $ids[0]; } else { $type = explode('/', $_POST['contentType']); $info = array('data' => base64_decode($_POST['data']), 'name' => Misc::randCode(10) . '.' . $type[1], 'type' => $_POST['contentType']); // TODO: Detect unacceptable filetype // TODO: Verify content-type and check file-content to ensure image $id = $draft->attachments->save($info); } if (!($f = AttachmentFile::lookup($id))) { return Http::response(500, 'Unable to attach image'); } echo JsonDataEncoder::encode(array('content_id' => 'cid:' . $f->getKey(), 'filelink' => sprintf('image.php?h=%s', $f->getDownloadHash()))); }
function save($id, $vars, &$errors) { if (!$id && (!$vars['ipaddr'] || !Validator::is_ip($vars['ipaddr']))) { $errors['ipaddr'] = 'Valid IP required'; } if ($errors) { return false; } $sql = ' updated=NOW() ' . ',isactive=' . db_input($vars['isactive']) . ',can_create_tickets=' . db_input($vars['can_create_tickets']) . ',can_exec_cron=' . db_input($vars['can_exec_cron']) . ',notes=' . db_input($vars['notes']); if ($id) { $sql = 'UPDATE ' . API_KEY_TABLE . ' SET ' . $sql . ' WHERE id=' . db_input($id); if (db_query($sql)) { return true; } $errors['err'] = 'Unable to update API key. Internal error occurred'; } else { $sql = 'INSERT INTO ' . API_KEY_TABLE . ' SET ' . $sql . ',created=NOW() ' . ',ipaddr=' . db_input($vars['ipaddr']) . ',apikey=' . db_input(strtoupper(md5(time() . $vars['ipaddr'] . md5(Misc::randCode(16))))); if (db_query($sql) && ($id = db_insert_id())) { return $id; } $errors['err'] = 'Unable to add API key. Try again!'; } return false; }
function send($to, $subject, $message, $options = null) { global $ost; //Get the goodies require_once PEAR_DIR . 'Mail.php'; // PEAR Mail package require_once PEAR_DIR . 'Mail/mime.php'; // PEAR Mail_Mime packge //do some cleanup $to = preg_replace("/(\r\n|\r|\n)/s", '', trim($to)); $subject = preg_replace("/(\r\n|\r|\n)/s", '', trim($subject)); //We're decoding html entities here becasuse we only support plain text for now - html support comming. $body = Format::htmldecode(preg_replace("/(\r\n|\r)/s", "\n", trim($message))); /* Message ID - generated for each outgoing email */ $messageId = sprintf('<%s%d-%s>', Misc::randCode(6), time(), $this->getEmail() ? $this->getEmail()->getEmail() : '@osTicketMailer'); $headers = array('From' => $this->getFromAddress(), 'To' => $to, 'Subject' => $subject, 'Date' => date('D, d M Y H:i:s O'), 'Message-ID' => $messageId, 'X-Mailer' => 'osTicket Mailer'); //Set bulk/auto-response headers. if ($options && ($options['autoreply'] or $options['bulk'])) { $headers += array('X-Autoreply' => 'yes', 'X-Auto-Response-Suppress' => 'ALL, AutoReply', 'Auto-Submitted' => 'auto-replied'); if ($options['bulk']) { $headers += array('Precedence' => 'bulk'); } else { $headers += array('Precedence' => 'auto_reply'); } } if ($options) { if (isset($options['inreplyto']) && $options['inreplyto']) { $headers += array('In-Reply-To' => $options['inreplyto']); } if (isset($options['references']) && $options['references']) { if (is_array($options['references'])) { $headers += array('References' => implode(' ', $options['references'])); } else { $headers += array('References' => $options['references']); } } } $mime = new Mail_mime(); $mime->setTXTBody($body); //XXX: Attachments if ($attachments = $this->getAttachments()) { foreach ($attachments as $attachment) { if ($attachment['file_id'] && ($file = AttachmentFile::lookup($attachment['file_id']))) { $mime->addAttachment($file->getData(), $file->getType(), $file->getName(), false); } elseif ($attachment['file'] && file_exists($attachment['file']) && is_readable($attachment['file'])) { $mime->addAttachment($attachment['file'], $attachment['type'], $attachment['name']); } } } //Desired encodings... $encodings = array('head_encoding' => 'quoted-printable', 'text_encoding' => 'base64', 'html_encoding' => 'base64', 'html_charset' => 'utf-8', 'text_charset' => 'utf-8', 'head_charset' => 'utf-8'); //encode the body $body = $mime->get($encodings); //encode the headers. $headers = $mime->headers($headers, true); if ($smtp = $this->getSMTPInfo()) { //Send via SMTP $mail = mail::factory('smtp', array('host' => $smtp['host'], 'port' => $smtp['port'], 'auth' => $smtp['auth'], 'username' => $smtp['username'], 'password' => $smtp['password'], 'timeout' => 20, 'debug' => false)); $result = $mail->send($to, $headers, $body); if (!PEAR::isError($result)) { return $messageId; } $alert = sprintf("Unable to email via SMTP:%s:%d [%s]\n\n%s\n", $smtp['host'], $smtp['port'], $smtp['username'], $result->getMessage()); $this->logError($alert); } //No SMTP or it failed....use php's native mail function. $mail = mail::factory('mail'); return PEAR::isError($mail->send($to, $headers, $body)) ? false : $messageId; }
function getAttachments($part = null) { $files = array(); /* Consider this part as an attachment if * * It has a Content-Disposition header * * AND it is specified as either 'attachment' or 'inline' * * The Content-Type header specifies * * type is image/* or application/* * * has a name parameter */ if ($part && ($part->disposition && (!strcasecmp($part->disposition, 'attachment') || !strcasecmp($part->disposition, 'inline')) || (!strcasecmp($part->ctype_primary, 'image') || !strcasecmp($part->ctype_primary, 'application')))) { if (isset($part->d_parameters['filename'])) { $filename = Format::mimedecode($part->d_parameters['filename'], $this->charset); } elseif (isset($part->d_parameters['filename*'])) { // Support RFC 6266, section 4.3 and RFC, and RFC 5987 $filename = Format::decodeRfc5987($part->d_parameters['filename*']); } elseif (isset($part->ctype_parameters['name'])) { $filename = Format::mimedecode($part->ctype_parameters['name'], $this->charset); } elseif (isset($part->ctype_parameters['name*'])) { $filename = Format::decodeRfc5987($part->ctype_parameters['name*']); } elseif (isset($part->headers['content-id']) && $part->headers['content-id'] && 0 === strcasecmp($part->ctype_primary, 'image')) { $filename = 'image-' . Misc::randCode(4) . '.' . strtolower($part->ctype_secondary); } else { // Not an attachment? return false; } $file = array('name' => $filename, 'type' => strtolower($part->ctype_primary . '/' . $part->ctype_secondary)); if ($part->ctype_parameters['charset'] && 0 === strcasecmp($part->ctype_primary, 'text')) { $file['data'] = $this->mime_encode($part->body, $part->ctype_parameters['charset']); } else { $file['data'] = $part->body; } // Capture filesize in order to support de-duplication if (extension_loaded('mbstring')) { $file['size'] = mb_strlen($file['data'], '8bit'); } else { $file['size'] = strlen($file['data']); } if (!$this->decode_bodies && $part->headers['content-transfer-encoding']) { $file['encoding'] = $part->headers['content-transfer-encoding']; } // Include Content-Id (for inline-images), stripping the <> $file['cid'] = isset($part->headers['content-id']) ? rtrim(ltrim($part->headers['content-id'], '<'), '>') : false; return array($file); } elseif ($this->tnef) { foreach ($this->tnef->attachments as $at) { $files[] = array('cid' => @$at->AttachContentId ?: false, 'data' => $at->getData(), 'size' => @$at->DataSize ?: null, 'type' => @$at->AttachMimeTag ?: false, 'name' => $at->getName()); } return $files; } if ($part == null) { $part = $this->getStruct(); } if ($part->parts) { foreach ($part->parts as $k => $p) { if ($p && ($result = $this->getAttachments($p))) { $files = array_merge($files, $result); } } } return $files; }
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; }
function send($to, $subject, $message, $options = null) { global $ost; //Get the goodies require_once PEAR_DIR . 'Mail.php'; // PEAR Mail package require_once PEAR_DIR . 'Mail/mime.php'; // PEAR Mail_Mime packge //do some cleanup $to = preg_replace("/(\r\n|\r|\n)/s", '', trim($to)); $subject = stripslashes(preg_replace("/(\r\n|\r|\n)/s", '', trim($subject))); $body = stripslashes(preg_replace("/(\r\n|\r)/s", "\n", trim($message))); /* Message ID - generated for each outgoing email */ $messageId = sprintf('<%s%d-%s>', Misc::randCode(6), time(), $this->getEmail() ? $this->getEmail()->getEmail() : '@osTicketMailer'); $headers = array('From' => $this->getFromAddress(), 'To' => $to, 'Subject' => $subject, 'Date' => date('D, d M Y H:i:s O'), 'Message-ID' => $messageId, 'X-Mailer' => 'osTicket Mailer', 'Content-Type' => 'text/html; charset="UTF-8"'); $mime = new Mail_mime(); $mime->setTXTBody($body); //XXX: Attachments if ($attachments = $this->getAttachments()) { foreach ($attachments as $attachment) { if ($attachment['file_id'] && ($file = AttachmentFile::lookup($attachment['file_id']))) { $mime->addAttachment($file->getData(), $file->getType(), $file->getName(), false); } elseif ($attachment['file'] && file_exists($attachment['file']) && is_readable($attachment['file'])) { $mime->addAttachment($attachment['file'], $attachment['type'], $attachment['name']); } } } //Desired encodings... $encodings = array('head_encoding' => 'quoted-printable', 'text_encoding' => 'quoted-printable', 'html_encoding' => 'base64', 'html_charset' => 'utf-8', 'text_charset' => 'utf-8', 'head_charset' => 'utf-8'); //encode the body $body = $mime->get($encodings); //encode the headers. $headers = $mime->headers($headers); if ($smtp = $this->getSMTPInfo()) { //Send via SMTP $mail = mail::factory('smtp', array('host' => $smtp['host'], 'port' => $smtp['port'], 'auth' => $smtp['auth'], 'username' => $smtp['username'], 'password' => $smtp['password'], 'timeout' => 20, 'debug' => false)); $result = $mail->send($to, $headers, $body); if (!PEAR::isError($result)) { return $messageId; } $alert = sprintf("Unable to email via SMTP:%s:%d [%s]\n\n%s\n", $smtp['host'], $smtp['port'], $smtp['username'], $result->getMessage()); $this->logError($alert); } //No SMTP or it failed....use php's native mail function. $mail = mail::factory('mail'); return PEAR::isError($mail->send($to, $headers, $body)) ? false : $messageId; }
/** * getMessageId * * Generates a unique message ID for an outbound message. Optionally, * the recipient can be used to create a tag for the message ID where * the user-id and thread-entry-id are encoded in the message-id so * the message can be threaded if it is replied to without any other * indicator of the thread to which it belongs. This tag is signed with * the secret-salt of the installation to guard against false positives. * * Parameters: * $recipient - (EmailContact|null) recipient of the message. The ID of * the recipient is placed in the message id TAG section so it can * be recovered if the email replied to directly by the end user. * $options - (array) - options passed to ::send(). If it includes a * 'thread' element, the threadId will be recorded in the TAG * * Returns: * (string) - email message id, with leading and trailing <> chars. See * the format below for the structure. * * Format: * VA-B-C-D, with dash separators and A-D explained below: * * V: Version code of the generated Message-Id * A: Predictable random code — used for loop detection * B: Random data for unique identifier * Version Code: A (at char position 10) * C: TAG: Base64(Pack(userid, entryId, type)), = chars discarded * D: Signature: * '@' + Signed Tag value, last 10 chars from * HMAC(sha1, tag+rand, SECRET_SALT) * -or- Original From email address */ function getMessageId($recipient, $options = array(), $version = 'A') { $rand = Misc::randCode(9, 'abcdefghiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_='); // Create a tag for the outbound email $tag = pack('VVa', $recipient instanceof EmailContact ? $recipient->getUserId() : 0, isset($options['thread']) && $options['thread'] instanceof ThreadEntry ? $options['thread']->getId() : 0, $recipient instanceof Staff ? 'S' : ($recipient instanceof TicketOwner ? 'U' : ($recipient instanceof Collaborator ? 'C' : '?'))); $tag = str_replace('=', '', base64_encode($tag)); // Sign the tag with the system secret salt $sig = '@' . substr(hash_hmac('sha1', $tag . $rand, SECRET_SALT), -10); return sprintf('<A%s-%s-%s-%s>', static::getSystemMessageIdCode(), $rand, $tag, $sig); }
function getAttachments($part, $index = 0) { if ($part && !$part->parts) { //Check if the part is an attachment. $filename = false; if ($part->ifdisposition && $part->ifdparameters && in_array(strtolower($part->disposition), array('attachment', 'inline'))) { $filename = $this->findFilename($part->dparameters); } // Inline attachments without disposition. NOTE that elseif is // not utilized here b/c ::findFilename may return null if (!$filename && $part->ifparameters && $part->parameters && $part->type > 0) { $filename = $this->findFilename($part->parameters); } $content_id = $part->ifid ? rtrim(ltrim($part->id, '<'), '>') : false; // Some mail clients / servers (like Lotus Notes / Domino) will // send images without a filename. For such a case, generate a // random filename for the image if (!$filename && $content_id && $part->type == 5) { $filename = _S('image') . '-' . Misc::randCode(4) . '.' . strtolower($part->subtype); } if ($filename) { return array(array('name' => $this->mime_decode($filename), 'type' => $this->getMimeType($part), 'size' => $part->bytes ?: null, 'encoding' => $part->encoding, 'index' => $index ? $index : 1, 'cid' => $content_id)); } } //Recursive attachment search! $attachments = array(); if ($part && $part->parts) { foreach ($part->parts as $k => $struct) { if ($index) { $prefix = $index . '.'; } $attachments = array_merge($attachments, $this->getAttachments($struct, $prefix . ($k + 1))); } } return $attachments; }
function save($id, $vars, &$errors) { if (!$id && (!$vars['ipaddr'] || !Validator::is_ip($vars['ipaddr']))) { $errors['ipaddr'] = __('Valid IP is required'); } if ($errors) { return false; } $sql = ' updated=NOW() ' . ',isactive=' . db_input($vars['isactive']) . ',can_create_tickets=' . db_input($vars['can_create_tickets']) . ',can_exec_cron=' . db_input($vars['can_exec_cron']) . ',notes=' . db_input(Format::sanitize($vars['notes'])); if ($id) { $sql = 'UPDATE ' . API_KEY_TABLE . ' SET ' . $sql . ' WHERE id=' . db_input($id); if (db_query($sql)) { return true; } $errors['err'] = sprintf(__('Unable to update %s.'), __('this API key')) . ' ' . __('Internal error occurred'); } else { $sql = 'INSERT INTO ' . API_KEY_TABLE . ' SET ' . $sql . ',created=NOW() ' . ',ipaddr=' . db_input($vars['ipaddr']) . ',apikey=' . db_input(strtoupper(md5(time() . $vars['ipaddr'] . md5(Misc::randCode(16))))); if (db_query($sql) && ($id = db_insert_id())) { return $id; } $errors['err'] = sprintf(__('Unable to add %s. Correct error(s) below and try again.'), __('this API key')); } return false; }
function send($to, $subject, $message, $options = null) { global $ost, $cfg; //Get the goodies require_once PEAR_DIR . 'Mail.php'; // PEAR Mail package require_once PEAR_DIR . 'Mail/mime.php'; // PEAR Mail_Mime packge //do some cleanup $to = preg_replace("/(\r\n|\r|\n)/s", '', trim($to)); $subject = preg_replace("/(\r\n|\r|\n)/s", '', trim($subject)); /* Message ID - generated for each outgoing email */ $messageId = sprintf('<%s-%s-%s>', substr(md5('mail' . SECRET_SALT), -9), Misc::randCode(9), $this->getEmail() ? $this->getEmail()->getEmail() : '@osTicketMailer'); $headers = array('From' => $this->getFromAddress(), 'To' => $to, 'Subject' => $subject, 'Date' => date('D, d M Y H:i:s O'), 'Message-ID' => $messageId, 'X-Mailer' => 'osTicket Mailer'); // 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. if (isset($options['bulk']) && $options['bulk']) { $headers += array('Precedence' => 'bulk'); } //Auto-reply - mark as autoreply and supress all auto-replies if (isset($options['autoreply']) && $options['autoreply']) { $headers += array('Precedence' => 'auto_reply', 'X-Autoreply' => 'yes', 'X-Auto-Response-Suppress' => 'DR, RN, OOF, AutoReply', 'Auto-Submitted' => 'auto-replied'); } //Notice (sort of automated - but we don't want auto-replies back if (isset($options['notice']) && $options['notice']) { $headers += array('X-Auto-Response-Suppress' => 'OOF, AutoReply', 'Auto-Submitted' => 'auto-generated'); } if ($options) { if (isset($options['inreplyto']) && $options['inreplyto']) { $headers += array('In-Reply-To' => $options['inreplyto']); } if (isset($options['references']) && $options['references']) { if (is_array($options['references'])) { $headers += array('References' => implode(' ', $options['references'])); } else { $headers += array('References' => $options['references']); } } } // The Suhosin patch will muck up the line endings in some // cases // // References: // 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(); } // If the message is not explicitly declared to be a text message, // then assume that it needs html processing to create a valid text // body $isHtml = true; $mid_token = isset($options['thread']) ? $options['thread']->asMessageId($to) : ''; if (!(isset($options['text']) && $options['text'])) { if ($cfg && $cfg->stripQuotedReply() && ($tag = $cfg->getReplySeparator()) && (!isset($options['reply-tag']) || $options['reply-tag'])) { $message = "<div style=\"display:none\"\n data-mid=\"{$mid_token}\">{$tag}<br/><br/></div>{$message}"; } $txtbody = rtrim(Format::html2text($message, 90, false)) . ($mid_token ? "\nRef-Mid: {$mid_token}\n" : ''); $mime->setTXTBody($txtbody); } else { $mime->setTXTBody($message); $isHtml = false; } if ($isHtml && $cfg && $cfg->isHtmlThreadEnabled()) { // Pick a domain compatible with pear Mail_Mime $matches = array(); if (preg_match('#(@[0-9a-zA-Z\\-\\.]+)#', $this->getFromAddress(), $matches)) { $domain = $matches[1]; } else { $domain = '@localhost'; } // Format content-ids with the domain, and add the inline images // to the email attachment list $self = $this; $message = preg_replace_callback('/cid:([\\w.-]{32})/', function ($match) use($domain, $mime, $self) { if (!($file = AttachmentFile::lookup($match[1]))) { return $match[0]; } $mime->addHTMLImage($file->getData(), $file->getType(), $file->getName(), false, $match[1] . $domain); // Don't re-attach the image below unset($self->attachments[$file->getId()]); return $match[0] . $domain; }, $message); // Add an HTML body $mime->setHTMLBody($message); } //XXX: Attachments if ($attachments = $this->getAttachments()) { foreach ($attachments as $attachment) { if ($attachment['file_id'] && ($file = AttachmentFile::lookup($attachment['file_id']))) { $mime->addAttachment($file->getData(), $file->getType(), $file->getName(), false); } } } //Desired encodings... $encodings = array('head_encoding' => 'quoted-printable', 'text_encoding' => 'base64', 'html_encoding' => 'base64', 'html_charset' => 'utf-8', 'text_charset' => 'utf-8', 'head_charset' => 'utf-8'); //encode the body $body = $mime->get($encodings); //encode the headers. $headers = $mime->headers($headers, true); // Cache smtp connections made during this request static $smtp_connections = array(); if ($smtp = $this->getSMTPInfo()) { //Send via SMTP $key = sprintf("%s:%s:%s", $smtp['host'], $smtp['port'], $smtp['username']); if (!isset($smtp_connections[$key])) { $mail = mail::factory('smtp', array('host' => $smtp['host'], 'port' => $smtp['port'], 'auth' => $smtp['auth'], 'username' => $smtp['username'], 'password' => $smtp['password'], 'timeout' => 20, 'debug' => false, 'persist' => true)); if ($mail->connect()) { $smtp_connections[$key] = $mail; } } else { // Use persistent connection $mail = $smtp_connections[$key]; } $result = $mail->send($to, $headers, $body); if (!PEAR::isError($result)) { return $messageId; } // Force reconnect on next ->send() unset($smtp_connections[$key]); $alert = sprintf("Unable to email via SMTP:%s:%d [%s]\n\n%s\n", $smtp['host'], $smtp['port'], $smtp['username'], $result->getMessage()); $this->logError($alert); } //No SMTP or it failed....use php's native mail function. $mail = mail::factory('mail'); return PEAR::isError($mail->send($to, $headers, $body)) ? false : $messageId; }
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' => 'string', 'required' => 1, 'error' => 'Confirm password'); $f['prefix'] = array('type' => 'string', 'required' => 1, 'error' => 'Table prefix required'); $f['dbhost'] = array('type' => 'string', 'required' => 1, 'error' => 'Hostname 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'); 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'] = 'passwords to 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'] = '******'; } // 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'] = 'Unable to connect to MySQL server. ' . db_connect_error(); } elseif (explode('.', db_version()) < explode('.', $this->getMySQLVersion())) { $this->errors['db'] = sprintf('osTicket requires MySQL %s or better!', $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('PREFIX', $vars['prefix']); //Table prefix $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'] = $stream . ': Internal Error - please make sure your download is the latest (#1)'; } elseif (!($hash = md5(fread($fp2, filesize($schemaFile)))) || strcasecmp($signature, $hash)) { $this->errors['err'] = $stream . ': Unknown or invalid schema signature (' . $signature . ' .. ' . $hash . ')'; } elseif (!$this->load_sql_file($schemaFile, $vars['prefix'], true, $debug)) { $this->errors['err'] = $stream . ': Error parsing SQL schema! Get help from developers (#4)'; } } } $sql = 'SELECT `id` FROM ' . PREFIX . 'sla ORDER BY `id` LIMIT 1'; $sla_id_1 = db_result(db_query($sql, false), 0); $sql = 'SELECT `dept_id` FROM ' . PREFIX . 'department ORDER BY `dept_id` LIMIT 1'; $dept_id_1 = db_result(db_query($sql, false), 0); $sql = 'SELECT `tpl_id` FROM ' . PREFIX . 'email_template_group ORDER BY `tpl_id` LIMIT 1'; $template_id_1 = db_result(db_query($sql, false), 0); $sql = 'SELECT `group_id` FROM ' . PREFIX . 'groups ORDER BY `group_id` LIMIT 1'; $group_id_1 = db_result(db_query($sql, false), 0); $sql = 'SELECT `id` FROM ' . PREFIX . 'timezone WHERE offset=-5.0 LIMIT 1'; $eastern_timezone = db_result(db_query($sql, false), 0); if (!$this->errors) { //Create admin user. $sql = 'INSERT INTO ' . PREFIX . 'staff SET created=NOW() ' . ", isactive=1, isadmin=1, group_id={$group_id_1}, dept_id={$dept_id_1}" . ", timezone_id={$eastern_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 ' . 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 ' . PREFIX . "email WHERE `email`='alerts@{$domain}' LIMIT 1"; $alert_email_id = db_result(db_query($sql, false), 0); //Create config settings---default settings! //XXX: rename ostversion helpdesk_* ?? // XXX: Some of this can go to the core install file $defaults = array('isonline' => '0', '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_timezone_id' => $eastern_timezone, 'default_template_id' => $template_id_1, 'admin_email' => db_input($vars['admin_email']), 'schema_signature' => db_input($streams['core']), 'helpdesk_url' => db_input(URL), 'helpdesk_title' => db_input($vars['name'])); foreach ($defaults as $key => $value) { $sql = 'UPDATE ' . PREFIX . 'config SET updated=NOW(), value=' . $value . ' WHERE namespace="core" AND `key`=' . db_input($key); if (!db_query($sql, false)) { $this->errors['err'] = 'Unable to create config settings (#7)'; } } foreach ($streams as $stream => $signature) { if ($stream != 'core') { $sql = 'INSERT INTO ' . PREFIX . 'config (`namespace`, `key`, `value`, `updated`) ' . 'VALUES (' . db_input($stream) . ', ' . db_input('schema_signature') . ', ' . db_input($signature) . ', NOW())'; if (!db_query($sql, false)) { $this->errors['err'] = 'Unable to create config settings (#7)'; } } } } 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 ' . PREFIX . "email SET dept_id={$dept_id_1}"; db_query($sql, false); $sql = 'UPDATE ' . PREFIX . "department SET email_id={$support_email_id}" . ", autoresp_email_id={$support_email_id}"; db_query($sql, false); //Create a ticket to make the system warm and happy. $sql = 'INSERT INTO ' . PREFIX . 'ticket SET created=NOW(), status="open", source="Web" ' . " ,priority_id=0, dept_id={$dept_id_1}, topic_id=0 " . ' ,ticketID=' . db_input(Misc::randNumber(6)) . ' ,email="*****@*****.**" ' . ' ,name="osTicket Support" ' . ' ,subject="osTicket Installed!"'; if (db_query($sql, false) && ($tid = db_insert_id())) { if (!($msg = file_get_contents(INC_DIR . 'msg/installed.txt'))) { $msg = 'Congratulations and Thank you for choosing osTicket!'; } $sql = 'INSERT INTO ' . PREFIX . 'ticket_thread SET created=NOW()' . ', source="Web" ' . ', thread_type="M" ' . ', ticket_id=' . db_input($tid) . ', title=' . db_input('osTicket Installed') . ', body=' . db_input($msg); db_query($sql, false); } //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 ' . 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; }
function extractEmbeddedHtmlImages($body) { $self = $this; return preg_replace_callback('/src="(data:[^"]+)"/', function ($m) use($self) { $info = Format::parseRfc2397($m[1], false, false); $info['cid'] = 'img' . Misc::randCode(12); list(, $type) = explode('/', $info['type'], 2); $info['name'] = 'image' . Misc::randCode(4) . '.' . $type; $self->embedded_images[] = $info; return 'src="cid:' . $info['cid'] . '"'; }, $body); }
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; } $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)) . ' ,body=' . db_input(Format::sanitize($vars['body'], true)) . ' ,staff_id=' . db_input($vars['staffId']) . ' ,poster=' . db_input($vars['poster']) . ' ,source=' . db_input($vars['source']); 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']); } //Emailed or API attachments if ($vars['attachments']) { $entry->importAttachments($vars['attachments']); } //Canned attachments... if ($vars['cannedattachments'] && is_array($vars['cannedattachments'])) { $entry->saveAttachments($vars['cannedattachments']); } // 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); return $entry; }
function saveAttachment($name, $data, $refid, $type) { global $cfg; if (!$refid || !$name || !$data) { return 0; } $dir = $cfg->getUploadDir(); $rand = Misc::randCode(16); $name = Format::file_name($name); $filename = rtrim($dir, '/') . '/' . $rand . '_' . $name; if ($fp = fopen($filename, 'w')) { fwrite($fp, $data); fclose($fp); $size = @filesize($filename); $sql = 'INSERT INTO ' . TICKET_ATTACHMENT_TABLE . ' SET created=NOW() ' . ',ticket_id=' . db_input($this->getId()) . ',ref_id=' . db_input($refid) . ',ref_type=' . db_input($type) . ',file_size=' . db_input($size) . ',file_name=' . db_input($name) . ',file_key=' . db_input($rand); if (db_query($sql)) { return db_insert_id(); } @unlink($filename); //insert failed...remove the link. } return 0; }
function saveAttachment($name, $data, $refid, $type) { global $cfg; if (!$refid || !$name || !$data) { return 0; } $dir = $cfg->getUploadDir(); $rand = Misc::randCode(16); $name = Format::file_name($name); $month = date('my', strtotime($this->getCreateDate())); //try creating the directory if it doesn't exists. if (!file_exists(rtrim($dir, '/') . '/' . $month) && @mkdir(rtrim($dir, '/') . '/' . $month, 0777)) { chmod(rtrim($dir, '/') . '/' . $month, 0777); } if (file_exists(rtrim($dir, '/') . '/' . $month) && is_writable(rtrim($dir, '/') . '/' . $month)) { $filename = sprintf("%s/%s/%s_%s", rtrim($dir, '/'), $month, $rand, $name); } else { $filename = rtrim($dir, '/') . '/' . $rand . '_' . $name; } if ($fp = fopen($filename, 'w')) { fwrite($fp, $data); fclose($fp); $size = @filesize($filename); $sql = 'INSERT INTO ' . TICKET_ATTACHMENT_TABLE . ' SET created=NOW() ' . ',ticket_id=' . db_input($this->getId()) . ',ref_id=' . db_input($refid) . ',ref_type=' . db_input($type) . ',file_size=' . db_input($size) . ',file_name=' . db_input($name) . ',file_key=' . db_input($rand); if (db_query($sql) && ($id = db_insert_id())) { return $id; } @unlink($filename); //insert failed...remove the link. } return 0; }
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 _uploadInlineImage($draft) { global $cfg; if (!isset($_POST['data']) && !isset($_FILES['file'])) { Http::response(422, "File not included properly"); } # Fixup for expected multiple attachments if (isset($_FILES['file'])) { foreach ($_FILES['file'] as $k => $v) { $_FILES['image'][$k] = array($v); } unset($_FILES['file']); $file = AttachmentFile::format($_FILES['image']); # TODO: Detect unacceptable attachment extension # TODO: Verify content-type and check file-content to ensure image $type = $file[0]['type']; if (strpos($file[0]['type'], 'image/') !== 0) { return Http::response(403, JsonDataEncoder::encode(array('error' => 'File type is not allowed'))); } # TODO: Verify file size is acceptable if ($file[0]['size'] > $cfg->getMaxFileSize()) { return Http::response(403, JsonDataEncoder::encode(array('error' => 'File is too large'))); } if (!($ids = $draft->attachments->upload($file))) { if ($file[0]['error']) { return Http::response(403, JsonDataEncoder::encode(array('error' => $file[0]['error']))); } else { return Http::response(500, 'Unable to attach image'); } } $id = $ids[0]; } else { $type = explode('/', $_POST['contentType']); $info = array('data' => base64_decode($_POST['data']), 'name' => Misc::randCode(10) . '.' . $type[1], 'type' => $_POST['contentType']); // TODO: Detect unacceptable filetype // TODO: Verify content-type and check file-content to ensure image $id = $draft->attachments->save($info); } if (!($f = AttachmentFile::lookup($id))) { return Http::response(500, 'Unable to attach image'); } echo JsonDataEncoder::encode(array('content_id' => 'cid:' . $f->getKey(), 'filelink' => $f->getDownloadUrl(false, 'inline'))); }
function sendmail($to, $subject, $message, $from) { require_once 'Mail.php'; // PEAR Mail package require_once 'Mail/mime.php'; // PEAR Mail_Mime packge $eol = "\n"; $to = preg_replace("/(\r\n|\r|\n)/s", '', trim($to)); $subject = stripslashes(preg_replace("/(\r\n|\r|\n)/s", '', trim($subject))); $body = stripslashes(preg_replace("/(\r\n|\r)/s", "\n", trim($message))); $headers = array('From' => $from, 'To' => $to, 'Subject' => $subject, 'Message-ID' => '<' . Misc::randCode(10) . '' . time() . '@osTicket>', 'X-Mailer' => 'osTicket v 1.6', 'Content-Type' => 'text/html; charset="UTF-8"'); $mime = new Mail_mime(); $mime->setTXTBody($body); $options = array('head_encoding' => 'quoted-printable', 'text_encoding' => 'quoted-printable', 'html_encoding' => 'base64', 'html_charset' => 'utf-8', 'text_charset' => 'utf-8'); //encode the body $body = $mime->get($options); //headers $headers = $mime->headers($headers); $mail = mail::factory('mail'); return PEAR::isError($mail->send($to, $headers, $body)) ? false : true; }
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']); }