diff --git a/.gitignore b/.gitignore
index 3c8db864..aff7c4f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -183,7 +183,6 @@ inc/mail/sasl/ntlm_sasl_client.php
inc/mail/sasl/plain_sasl_client.php
inc/mail/sasl/sasl.php
inc/mail/smtp.php
-inc/pipe_functions.inc.php
inc/posting_functions.inc.php
inc/prepare_ticket_export.inc.php
inc/print_group.inc.php
diff --git a/inc/pipe_functions.inc.php b/inc/pipe_functions.inc.php
new file mode 100755
index 00000000..cf4e7016
--- /dev/null
+++ b/inc/pipe_functions.inc.php
@@ -0,0 +1,505 @@
+num_rows > 0) {
+ return hesk_cleanExit();
+ }
+
+ // Process "From:" name, convert to UTF-8, set to "[Customer]" if not set
+ $tmpvar['name'] = isset($results['from'][0]['name']) ? $results['from'][0]['name'] : $hesklang['pde'];
+ if ( ! empty($results['from'][0]['encoding']) )
+ {
+ $tmpvar['name'] = hesk_encodeUTF8($tmpvar['name'], $results['from'][0]['encoding']);
+ }
+ $tmpvar['name'] = hesk_input($tmpvar['name'],'','',1,50) or $tmpvar['name'] = $hesklang['pde'];
+
+ // Process "To:" email (not yet implemented, for future use)
+ // $tmpvar['to_email'] = hesk_validateEmail($results['to'][0]['address'],'ERR',0);
+
+ // Process email subject, convert to UTF-8, set to "[Piped email]" if none set
+ $tmpvar['subject'] = isset($results['subject']) ? $results['subject'] : $hesklang['pem'];
+ if ( ! empty($results['subject_encoding']) )
+ {
+ $tmpvar['subject'] = hesk_encodeUTF8($tmpvar['subject'], $results['subject_encoding']);
+ }
+ $tmpvar['subject'] = hesk_input($tmpvar['subject'],'','',1,70) or $tmpvar['subject'] = $hesklang['pem'];
+
+ // Process email message, convert to UTF-8
+ $tmpvar['message'] = isset($results['message']) ? $results['message'] : '';
+ if ( ! empty($results['encoding']) )
+ {
+ $tmpvar['message'] = hesk_encodeUTF8($tmpvar['message'], $results['encoding']);
+ }
+ $tmpvar['message'] = hesk_input($tmpvar['message'],'','',1);
+
+ // Message missing? We require it!
+ if ( ! $tmpvar['message'])
+ {
+ return hesk_cleanExit();
+ }
+
+ // Strip quoted reply from email
+ $tmpvar['message'] = hesk_stripQuotedText($tmpvar['message']);
+
+ // Convert URLs to links, change newlines to
+ $tmpvar['message'] = hesk_makeURL($tmpvar['message']);
+ $tmpvar['message'] = nl2br($tmpvar['message']);
+
+ # For debugging purposes
+ # die( bin2hex($tmpvar['message']) );
+ # die($tmpvar['message']);
+
+ // Try to detect "delivery failed" and "noreply" emails - ignore if detected
+ if ( hesk_isReturnedEmail($tmpvar) )
+ {
+ return hesk_cleanExit();
+ }
+
+ // Check for email loops
+ if ( hesk_isEmailLoop($tmpvar['email'], md5($tmpvar['message']) ) )
+ {
+ return hesk_cleanExit();
+ }
+
+ // OK, everything seems OK. Now determine if this is a reply to a ticket or a new ticket
+ if ( preg_match('/\[#([A-Z0-9]{3}\-[A-Z0-9]{3}\-[A-Z0-9]{4})\]/', str_replace(' ', '', $tmpvar['subject']), $matches) )
+ {
+ // We found a possible tracking ID
+ $tmpvar['trackid'] = $matches[1];
+
+ // Does it match one in the database?
+ $res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($tmpvar['trackid'])."' LIMIT 1");
+ if (hesk_dbNumRows($res))
+ {
+ $ticket = hesk_dbFetchAssoc($res);
+
+ // Do email addresses match?
+ if ( strpos( strtolower($ticket['email']), strtolower($tmpvar['email']) ) === false )
+ {
+ $tmpvar['trackid'] = '';
+ }
+
+ // Is this ticket locked? Force create a new one if it is
+ if ($ticket['locked'])
+ {
+ $tmpvar['trackid'] = '';
+ }
+ }
+ else
+ {
+ $tmpvar['trackid'] = '';
+ }
+ }
+
+ // If tracking ID is empty, generate a new one
+ if ( empty($tmpvar['trackid']) )
+ {
+ $tmpvar['trackid'] = hesk_createID();
+ $is_reply = 0;
+ }
+ else
+ {
+ $is_reply = 1;
+ }
+
+ // Process attachments
+ $tmpvar['attachmment_notices'] = '';
+ $tmpvar['attachments'] = '';
+ $num = 0;
+ if ($hesk_settings['attachments']['use'] && isset($results['attachments'][0]))
+ {
+ #print_r($results['attachments']);
+
+ foreach ($results['attachments'] as $k => $v)
+ {
+
+ // Clean attachment names
+ $myatt['real_name'] = hesk_cleanFileName($v['orig_name']);
+
+ // Check number of attachments, delete any over max number
+ if ($num >= $hesk_settings['attachments']['max_number'])
+ {
+ $tmpvar['attachmment_notices'] .= sprintf($hesklang['attnum'], $myatt['real_name']) . "\n";
+ continue;
+ }
+
+ // Check file extension
+ $ext = strtolower(strrchr($myatt['real_name'], "."));
+ if (!in_array($ext,$hesk_settings['attachments']['allowed_types']))
+ {
+ $tmpvar['attachmment_notices'] .= sprintf($hesklang['atttyp'], $myatt['real_name']) . "\n";
+ continue;
+ }
+
+ // Check file size
+ $myatt['size'] = $v['size'];
+ if ($myatt['size'] > ($hesk_settings['attachments']['max_size']))
+ {
+ $tmpvar['attachmment_notices'] .= sprintf($hesklang['attsiz'], $myatt['real_name']) . "\n";
+ continue;
+ }
+
+ // Generate a random file name
+ $useChars='AEUYBDGHJLMNPQRSTVWXZ123456789';
+ $tmp = $useChars{mt_rand(0,29)};
+ for($j=1;$j<10;$j++)
+ {
+ $tmp .= $useChars{mt_rand(0,29)};
+ }
+ $myatt['saved_name'] = substr($tmpvar['trackid'] . '_' . md5($tmp . $myatt['real_name']), 0, 200) . $ext;
+
+ // Rename the temporary file
+ rename($v['stored_name'],HESK_PATH.$hesk_settings['attach_dir'].'/'.$myatt['saved_name']);
+
+ // Insert into database
+ hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` (`ticket_id`,`saved_name`,`real_name`,`size`) VALUES ('".hesk_dbEscape($tmpvar['trackid'])."','".hesk_dbEscape($myatt['saved_name'])."','".hesk_dbEscape($myatt['real_name'])."','".intval($myatt['size'])."')");
+ $tmpvar['attachments'] .= hesk_dbInsertID() . '#' . $myatt['real_name'] .',';
+
+ $num++;
+ }
+
+ if (strlen($tmpvar['attachmment_notices']))
+ {
+ $tmpvar['message'] .= "
" . hesk_input($hesklang['attrem'],'','',1) . "
" . nl2br(hesk_input($tmpvar['attachmment_notices'],'','',1));
+ }
+ }
+
+ // Delete the temporary files
+ deleteAll($results['tempdir']);
+
+ // If this is a reply add a new reply
+ if ($is_reply)
+ {
+ // Set last replier name to customer name
+ $ticket['lastreplier'] = ($tmpvar['name'] == $hesklang['pde']) ? $tmpvar['email'] : $tmpvar['name'];;
+
+ // If staff hasn't replied yet, keep ticket status "New", otherwise set it to "Waiting reply from staff"
+ $ticket['status'] = $ticket['status'] ? 1 : 0;
+
+ // Update ticket as necessary
+ hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `lastchange`=NOW(),`status`='{$ticket['status']}',`lastreplier`='0' WHERE `id`='".intval($ticket['id'])."' LIMIT 1");
+
+ // Insert reply into database
+ hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."replies` (`replyto`,`name`,`message`,`dt`,`attachments`) VALUES ('".intval($ticket['id'])."','".hesk_dbEscape($ticket['lastreplier'])."','".hesk_dbEscape($tmpvar['message'])."',NOW(),'".hesk_dbEscape($tmpvar['attachments'])."')");
+
+ // --> Prepare reply message
+
+ // 1. Generate the array with ticket info that can be used in emails
+ $info = array(
+ 'email' => $ticket['email'],
+ 'category' => $ticket['category'],
+ 'priority' => $ticket['priority'],
+ 'owner' => $ticket['owner'],
+ 'trackid' => $ticket['trackid'],
+ 'status' => $ticket['status'],
+ 'name' => $ticket['name'],
+ 'lastreplier' => $ticket['lastreplier'],
+ 'subject' => $ticket['subject'],
+ 'message' => stripslashes($tmpvar['message']),
+ 'attachments' => $tmpvar['attachments'],
+ 'dt' => hesk_date($ticket['dt'], true),
+ 'lastchange' => hesk_date($ticket['lastchange'], true),
+ );
+
+ // 2. Add custom fields to the array
+ foreach ($hesk_settings['custom_fields'] as $k => $v)
+ {
+ $info[$k] = $v['use'] ? $ticket[$k] : '';
+ }
+
+ // 3. Make sure all values are properly formatted for email
+ $ticket = hesk_ticketToPlain($info, 1, 0);
+
+ // --> Process custom fields before sending
+ foreach ($hesk_settings['custom_fields'] as $k => $v)
+ {
+ $ticket[$k] = $v['use'] ? hesk_msgToPlain($ticket[$k], 1) : '';
+ }
+
+ // --> If ticket is assigned just notify the owner
+ if ($ticket['owner'])
+ {
+ hesk_notifyAssignedStaff(false, 'new_reply_by_customer', 'notify_reply_my');
+ }
+ // --> No owner assigned, find and notify appropriate staff
+ else
+ {
+ hesk_notifyStaff('new_reply_by_customer',"`notify_reply_unassigned`='1'");
+ }
+
+ return $ticket['trackid'];
+
+ } // END REPLY
+
+ // Not a reply, but a new ticket. Add it to the database
+ $tmpvar['category'] = 1;
+ $tmpvar['priority'] = 3;
+ $_SERVER['REMOTE_ADDR'] = $hesklang['unknown'];
+
+ // Auto assign tickets if aplicable
+ $tmpvar['owner'] = 0;
+ $tmpvar['history'] = $pop3 ? sprintf($hesklang['thist16'], hesk_date()) : sprintf($hesklang['thist11'], hesk_date());
+
+ $autoassign_owner = hesk_autoAssignTicket($tmpvar['category']);
+
+ #print_r($autoassign_owner);
+
+ if ($autoassign_owner)
+ {
+ $tmpvar['owner'] = $autoassign_owner['id'];
+ $tmpvar['history'] .= sprintf($hesklang['thist10'],hesk_date(),$autoassign_owner['name'].' ('.$autoassign_owner['user'].')');
+ }
+
+ // Custom fields will be empty as there is no reliable way of detecting them
+ foreach ($hesk_settings['custom_fields'] as $k=>$v)
+ {
+ $tmpvar[$k] = '';
+ }
+
+ // Insert ticket to database
+ $ticket = hesk_newTicket($tmpvar);
+
+ // Notify the customer
+ hesk_notifyCustomer();
+
+ // Need to notify staff?
+ // --> From autoassign?
+ if ($tmpvar['owner'] && $autoassign_owner['notify_assigned'])
+ {
+ hesk_notifyAssignedStaff($autoassign_owner, 'ticket_assigned_to_you');
+ }
+ // --> No autoassign, find and notify appropriate staff
+ elseif ( ! $tmpvar['owner'] )
+ {
+ hesk_notifyStaff('new_ticket_staff', " `notify_new_unassigned` = '1' ");
+ }
+
+ return $ticket['trackid'];
+} // END hesk_email2ticket()
+
+
+function hesk_encodeUTF8($in, $encoding)
+{
+ $encoding = strtoupper($encoding);
+
+ switch($encoding)
+ {
+ case 'UTF-8':
+ return $in;
+ break;
+ case 'ISO-8859-1':
+ return utf8_encode($in);
+ break;
+ default:
+ return iconv($encoding, 'UTF-8', $in);
+ break;
+ }
+} // END hesk_encodeUTF8()
+
+
+function hesk_stripQuotedText($message)
+{
+ global $hesk_settings, $hesklang;
+
+ // Stripping quoted text disabled?
+ if ( ! $hesk_settings['strip_quoted'])
+ {
+ return $message;
+ }
+
+ // Loop through available languages and ty to find the tag
+ foreach ($hesk_settings['languages'] as $language => $settings)
+ {
+ if ( ($found = strpos($message, $settings['hr']) ) !== false )
+ {
+ // "Reply above this line" tag found, strip quoted reply
+ $message = substr($message, 0, $found);
+ $message .= "\n" . $hesklang['qrr'];
+
+ // Set language to the detected language
+ hesk_setLanguage($language);
+ break;
+ }
+ }
+
+ return $message;
+} // END hesk_stripQuotedText()
+
+
+function hesk_isReturnedEmail($tmpvar)
+{
+ // Check noreply email addresses
+ if ( preg_match('/not?[\-_]reply@/i', $tmpvar['email']) )
+ {
+ return true;
+ }
+
+ // Check mailer daemon email addresses
+ if ( preg_match('/mail(er)?[\-_]daemon@/i', $tmpvar['email']) )
+ {
+ return true;
+ }
+
+ // Check autoreply subjects
+ if ( preg_match('/^[\[\(]?Auto(mat(ic|ed))?[ \-]?reply/i', $tmpvar['subject']) )
+ {
+ return true;
+ }
+
+ // Check out of office subjects
+ if ( preg_match('/^Out of Office/i', $tmpvar['subject']) )
+ {
+ return true;
+ }
+
+ // Check delivery failed email subjects
+ if (
+ preg_match('/DELIVERY FAILURE/i', $tmpvar['subject']) ||
+ preg_match('/Undelivered Mail Returned to Sender/i', $tmpvar['subject']) ||
+ preg_match('/Delivery Status Notification \(Failure\)/i', $tmpvar['subject']) ||
+ preg_match('/Returned mail\: see transcript for details/i', $tmpvar['subject'])
+ )
+ {
+ return true;
+ }
+
+ // Check Mail Delivery sender name
+ if ( preg_match('/Mail[ \-_]?Delivery/i', $tmpvar['name']) )
+ {
+ return true;
+ }
+
+ // Check Delivery failed message
+ if ( preg_match('/postmaster@/i', $tmpvar['email']) && preg_match('/Delivery has failed to these recipients/i', $tmpvar['message']) )
+ {
+ return true;
+ }
+
+ // No pattern detected, seems like this is not a returned email
+ return false;
+
+} // END hesk_isReturnedEmail()
+
+
+function hesk_isEmailLoop($email, $message_hash)
+{
+ global $hesk_settings, $hesklang, $hesk_db_link;
+
+ // If $hesk_settings['loop_hits'] is set to 0 this function is disabled
+ if ( ! $hesk_settings['loop_hits'])
+ {
+ return false;
+ }
+
+ // Escape wildcards in email
+ $email_like = hesk_dbEscape(hesk_dbLike($email));
+
+ // Delete expired DB entries
+ hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."pipe_loops` WHERE `dt` < (NOW() - INTERVAL ".intval($hesk_settings['loop_time'])." SECOND) ");
+
+ // Check current entry
+ $res = hesk_dbQuery("SELECT `hits`, `message_hash` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."pipe_loops` WHERE `email` LIKE '{$email_like}' LIMIT 1");
+
+ // Any active entry*
+ if (hesk_dbNumRows($res))
+ {
+ list($num, $md5) = hesk_dbFetchRow($res);
+
+ $num++;
+
+ // Number of emails in a time period reached?
+ if ($num >= $hesk_settings['loop_hits'])
+ {
+ return true;
+ }
+
+ // Message exactly the same as in previous email?
+ if ($message_hash == $md5)
+ {
+ return true;
+ }
+
+ // Update DB entry
+ hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."pipe_loops` SET `hits` = `hits` + 1, `message_hash` = '".hesk_dbEscape($message_hash)."' WHERE `email` LIKE '{$email_like}' LIMIT 1");
+ }
+ else
+ {
+ // First instance, insert a new database row
+ hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."pipe_loops` (`email`, `message_hash`) VALUES ('".hesk_dbEscape($email)."', '".hesk_dbEscape($message_hash)."')");
+ }
+
+ // No loop rule trigered
+ return false;
+
+} // END hesk_isEmailLoop()
+
+
+function hesk_cleanExit()
+{
+ global $results;
+
+ // Delete the temporary files
+ deleteAll($results['tempdir']);
+
+ // Return NULL
+ return NULL;
+} // END hesk_cleanExit()