Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

osTicket v1.10 (stable) and Maintenance Release v1.9.15 are now available! Go get it now

[MOD] Allow Staff to reply to emails

This works for me, yes it is very hackish. Could somebody verify it works for them?

This will allow staff to reply to any email from osTicket and expect it to be added to the ticket as a response. It only works if the first part of the email address is the same as the staff usernames.

In pipe.php
Use the first and last line for reference.
be sure to read the comments, you have to change one part for your setup.

//Allow mismatched emails?? For now hell NO.
//if(!is_object($ticket) || strcasecmp($ticket->getEmail(),$var['email']))
// $ticket=null;
}
$errors=array();
$msgid=0;
if(!$ticket){ //New tickets...
$ticket=Ticket::create($var,$errors,'email');
if(!is_object($ticket) || $errors){
api_exit(EX_DATAERR,'Create Failed '.implode(\"\n\",$errors).\"\n\n\");
}
$msgid=$ticket->getLastMsgId();
}else{
$message=$var['message'];
//Strip quoted reply...TODO: figure out how mail clients do it without special tag..
if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
list($message)=split($tag,$var['message']);
//post message....postMessage does the cleanup.

$senderName=$var['email'];
$senderName = substr($senderName, 0, -20); //Change this to remove the @youyrdomain.com from the email address
$sql1=\"SELECT staff_id FROM ost_staff WHERE username='$senderName'\";
$almostsenderid=db_query($sql1);
while($row = mysql_fetch_array($almostsenderid)) {
$senderid = $row['staff_id'];
}

$sql=\"SELECT firstname,lastname FROM ost_staff WHERE staff_id='$senderid'\";
$almostsendername=db_query($sql);
while($row = mysql_fetch_array($almostsendername)) {
$senderName = $row['firstname'].' '.$row['lastname'];
}
if ($senderid){
if(!($respId=$ticket->postEmailResponse($msgid,$senderid,$senderName,$message,$var['header'],'Email'))) {
api_exit(EX_DATAERR,\"post message failed \n\n $message\n\");
}
}else{
if(!($msgid=$ticket->postMessage($message,$var['header'],'Email'))) {
api_exit(EX_DATAERR,\"post message failed \n\n $message\n\");
}
}

}
//Ticket created...save attachments if enabled.


Add this to class.ticket.php:
You can add it anywhere within the current functions

function postEmailResponse($mymsgid,$senderid,$senderName,$msg,$signature='none',$attachment=false,$ticket_status,$canalert=true){
global $cfg;
if(!$this->getId())
return 0;

//We don't really care much about the source at message level
$source=$source?$source:$_SERVER['REMOTE_ADDR'];
$mytid=db_input($this->getId());
$sql5=\"SELECT msg_id FROM ost_ticket_message WHERE ticket_id='$mytid' order by msg_id desc limit 1\";
$result5=db_query($sql5);
while($row = mysql_fetch_array($result5)) {
$mymsgid = $row['msg_id'];
}

$sql= 'INSERT INTO '.TICKET_RESPONSE_TABLE.' SET created=NOW() '.
',msg_id='.db_input($mymsgid).
',ticket_id='.db_input($this->getId()).
',response='.db_input(Format::striptags($msg)). //Tags/code stripped...meaning client can not send in code..etc
',staff_id='.db_input($senderid).
',staff_name='.db_input($senderName).
',ip_address='.db_input('10.2.1.22');
$resp_id=0;
//echo $sql;
$sql1= 'UPDATE '.TICKET_TABLE.' SET updated=NOW() WHERE ticket_id='.db_input($this->getId());
db_query($sql1);
if(db_query($sql) && ($resp_id=db_insert_id())):

if(!$canalert) //No alert/response
return $resp_id;


$dept=$this->getDept();
//Send Response to client...based on the template...
//TODO: check department level templates...if set.
$sql='SELECT ticket_reply_subj,ticket_reply_body FROM '.EMAIL_TEMPLATE_TABLE.
' WHERE cfg_id='.db_input($cfg->getId()).' AND tpl_id='.db_input($cfg->getDefaultTemplateId());
$resp=db_query($sql);
if(db_num_rows($resp) && list($subj,$body)=db_fetch_row($resp)){
if(strtolower($ticket_status)==\"close\"||strtolower($ticket_status)==\"closed\") $subj = \"[#%ticket] - Closed - Re: %subject\";

$subj = str_replace(\"%ticket\", $this->getExtId(),$subj);
$subj = str_replace(\"%subject\", $this->getSubject(),$subj);

$body = str_replace(\"%ticket\", $this->getExtId(),$body);
$body = str_replace(\"%name\", $this->getName(),$body);
$body = str_replace(\"%email\", $this->getEmail(),$body);
$body = str_replace(\"%url\", $cfg->getBaseUrl(),$body);
$body = str_replace(\"%message\",$msg,$body);

//Figure out the signature to use...if any.
switch(strtolower($signature)):
case 'mine';
$signature=$thisuser->getSignature();
break;
case 'dept':
$signature=$dept->isPublic()?$dept->getSignature():''; //make sure it is public
break;
case 'none';
default:
$signature='';
break;
endswitch;
$body = str_replace(\"%signature\",$signature,$body);

//Email attachment when attached AND if emailed.
if(($attachment && is_file($attachment['tmp_name'])) && $cfg->emailAttachments()) {
$semi_rand = md5(time());
$mime_boundary = \"==Multipart_Boundary_x{$semi_rand}x\";
$headers=\"MIME-Version: 1.0\n\" .

\"Content-Type: multipart/mixed;\n\" .
\" boundary=\\"{$mime_boundary}\\"\";

$body = \"This is a multi-part message in MIME format.\n\n\" .
\"--{$mime_boundary}\n\" .
\"Content-Type: text/plain; charset=\\"iso-8859-1\\"\n\" .
\"Content-Transfer-Encoding: 7bit\n\n\".
$body . \"\n\n\";

$body.= \"--{$mime_boundary}\n\" .
\"Content-Type: \" . $attachment['type'] . \";\n\" .
\" name=\\"\" . $attachment['name'] . \"\\"\n\" .
\"Content-Disposition: attachment;\n\" .
\" filename=\\"\" . $attachment['name'] . \"\\"\n\" .
\"Content-Transfer-Encoding: base64\n\n\" .
chunk_split(base64_encode(file_get_contents($attachment['tmp_name']))). \"\n\n\" .
\"--{$mime_boundary}--\n\";
}
$email=$from=$fromNamenull;
if(($email=$dept->getEmail())) { //Dept email if set!
$from=$email->getEmail();
$fromName=$email->getName();
//Reply separator tag.
if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
$body =\"\n$tag\n\n\".$body;
}else{//No emails means it is a noreply...
$from=$cfg->getNoReplyEmail();
}
Misc::sendmail($this->getEmail(),$subj,$body,$from,$fromName,$headers);
}else{
//We have a big problem...alert admin...
$msg='Problems fetching response template for ticket#'.$this->getId().' Possible config error';
Misc::alertAdmin('System Error',$msg);
}
return $resp_id;

endif;

return 0;
}

«1

Comments

  • Does it replaces the patch for email to v 1.6RC4? or...
    This script its worth with v 1.6RC5 ??
    How To implement the patch in the new version?

    Does This work in the v1.6RC5?
  • slm4996;8011 said:


    It only works if the first part of the email address is the same as the staff usernames.
    Can someone explain what this means? What email address is it referring to?
  • I think he means that:

    Example:

    'testname@example.com' is your e-mail adress.

    The staff username in osticket has to be the same:

    'testname'

    Ok?

    Greetings,
    Torben
  • trbn;8943 said:
    I think he means that:

    Example:

    'testname@example.com' is your e-mail adress.

    The staff username in osticket has to be the same:

    'testname'

    Ok?

    Greetings,
    Torben
    I still don't get it.
    What address is "testname@example.com" Client? admin? staff?

    Maybe if you tell me what line in the mod checks for the match, I can tell from there, assuming its part of the mod.
  • rodeored;8944 said:
    I still don't get it.
    What address is "testname@example.com" Client? admin? staff?

    Maybe if you tell me what line in the mod checks for the match, I can tell from there, assuming its part of the mod.
    well, this is a mod for STAFF to be able to reply to clients via email. Clients do not have usernames to the Staff Control Panel, so the email addresses in question must be for the staff users.

    if you staff members email address is [email]joe@company.com[/email], his username needs to be joe.
  • Yes, thats right
    Skeyelab;9622 said:
    well, this is a mod for STAFF to be able to reply to clients via email. Clients do not have usernames to the Staff Control Panel, so the email addresses in question must be for the staff users.

    if you staff members email address is [email]joe@company.com[/email], his username needs to be joe.
    Sorry for my late response, yes Skeyelab got it right.

    BTW, this works on rc5 but it gives continual email cannot be delivered errors!? Anybody know why?

    Basically the responses get input, they show up, everything works just fine. The only problem is the staff member then gets a bounce back from the mail server saying that the message could not be delivered.
  • slm4996;9953 said:
    Sorry for my late response, yes Skeyelab got it right.

    BTW, this works on rc5 but it gives continual email cannot be delivered errors!? Anybody know why?

    Basically the responses get input, they show up, everything works just fine. The only problem is the staff member then gets a bounce back from the mail server saying that the message could not be delivered.
    I'm no osticket expert (just installed it for the first time today), but as I was reading forum threads here about email setup, I ran across this post about email bounce messages getting sent even though the message is delivered.

    http://osticket.com/forums/showpost.php?p=2282&postcount=45

    Maybe by adding the code in that post it might silence the bounce emails?
  • mail issue:: from staff or admin replied mail not comeing to osticket panel

    Hi


    i am getting one problem after installation::from staff or admin replied mail not comeing to osticket panel only client reply mails are comeing ,is there any body ,who can help me out
  • This is how I made this work:

    find this code in api/pipe.php


    $ticket=null;
    if(ereg (\"[[][#][0-9]{1,10}[]]\",$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    if(!is_object($ticket) || strcasecmp($ticket->getEmail(),$var['email'])) {
    $ticket=null;
    }
    }


    From what I can see, this part of the code checks for a ticket number in the format [#0] to [#9999999999], and creates a ticket object using that number as the extID. The code then attempts to get the email address associated with that ticket, and checks that it matches with the email address which sent the email.

    So, if we comment out the $ticket=null line, so it becomes
    //$ticket=null;
    then it will allow anyone to post a message to a ticket.

    Anyone being able to post a message to a ticket is probably not a good thing. It means if someone knows your ticket number, they can send messages into the system. So what we need to do is make sure that only staff can reply in this way.

    So, after commenting out the $ticket=null line, add this code below the closing brackets:

    // mod by PRedmond to allow staff to reply via email
    // check that email address is in the staff list.
    $sql=\"SELECT username FROM \" . STAFF_TABLE . \" WHERE email='\" . $var['email'] . \"' \";
    $query=db_query($sql);
    while($row = mysql_fetch_array($query)) {
    $senderUsername = $row['username'];
    }

    // if username is in the staff list, then it can be a reply
    // if username is not in the staff list, then it must be a new ticket
    if (!$senderUsername){
    $ticket=null;
    }

    // end mod


    This checks that the incoming email address is in the staff list. If it is, then the message will be added to the original ticket as a response. If the email address is NOT in the staff list, then the email will become a new ticket.

    Hope this helps!!
  • I made a few changes and incorporated your ideas...

    A little differently - it works without changing the ticket class.

    I look up the staff id from the sender's email, and then create a staff session object from which I have the ability to call the postResponse method directly.

    This method also shows some rough code I added at the bottom that allows embedding image attachments in outlook like email messages that post embedded images without specifying a disposition.

    It's ugly but it works.


    @@ -93,9 +96,29 @@
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    - if(!is_object($ticket) || strcasecmp($ticket->getEmail(),$var['email']))
    - $ticket=null;
    -}
    +//TO ALLOW MOD BELOW TO WORK
    +// if(!is_object($ticket) || strcasecmp($ticket->getEmail(),$var['email']))
    +// $ticket=null;
    +}
    +// mod to allow staff to reply via email
    + // check that email address is in the staff list.
    + $sql=\"SELECT username,staff_id FROM \" . STAFF_TABLE . \" WHERE email='\" . $var['email'] . \"' \";
    + $query=db_query($sql);
    + while($row = mysql_fetch_array($query)) {
    + $senderUsername = $row['username'];
    + $senderStaffID = $row['staff_id'];
    + }
    +//thisuser is a global required by postResponse
    + $thisuser = new StaffSession($senderStaffID);
    +
    + // if username is in the staff list (or original client), then it can be a reply
    + // if username is not in the staff list, then it must be a new ticket
    + if ((!$senderUsername)
    + && (!is_object($ticket) || strcasecmp($ticket->getEmail(),$var['email']))
    + $ticket=null;
    + }
    +// end mod
    +
    $errors=array();
    $msgid=0;
    if(!$ticket){ //New tickets...
    @@ -110,9 +133,24 @@
    if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
    list($message)=split($tag,$var['message']);
    //post message....postMessage does the cleanup.
    +// mod to make a response from STAFF a response not a message
    +if (!$senderUsername){
    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
    api_exit(EX_DATAERR,\"Unable to post message \n\n $message\n\");
    }
    +} else {
    +// function postResponse($msgid,$response,$signature='none',$attachment=false,$canalert=true){
    +// function postMessage($msg,$source='',$msgid=NULL,$headers='',$newticket=false){
    +$sql='SELECT MAX(msg_id) FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id ='.$ticket->getId();
    +$query=db_query($sql);
    +while($row = mysql_fetch_array($query)) {
    + $Last_msg_id = $row[0];
    +}
    + if(!($msgid=$ticket->postResponse($Last_msg_id,$message))){
    + api_exit(EX_DATAERR,\"Unable to post response \n\n $message\n\");
    + }
    +}
    +// end mod
    }
    //Ticket created...save attachments if enabled.
    $struct=$parser->getStruct();
    @@ -122,6 +160,13 @@
    if($part->disposition
    && (!strcasecmp($part->disposition,'attachment') || !strcasecmp($part->disposition,'inline') || !strcasecmp($part->ctype_primary,'image'))){
    $filename=$part->d_parameters['filename'];
    + if($filename && $cfg->canUploadFileType($filename)) {
    + $ticket->saveAttachment($filename,$part->body,$msgid,'M');
    + }
    +//THIS PATCH ADDS THE ABILITY TO SAVE EMBEDDED IMAGES IN AN HTML EMAIL FROM OUTLOOK 2007
    + } elseif (!($part->disposition)
    + && (!strcasecmp($part->ctype_primary,'image')) ) {
    + $filename=$part->ctype_parameters['name'];
    if($filename && $cfg->canUploadFileType($filename)) {
    $ticket->saveAttachment($filename,$part->body,$msgid,'M');
    }
  • I personally don't agree with allowing staff responses via email, on the current code-base, without some safeguards and restrictions.

    Email headers can be spoofed - combine that with sequential ticket IDs or known user's ticket ID and you have problem. In addition you have to worry about; more than one staff members responding, lack of ticket history and internal notes when responding, disabled staff (fired?) can still respond...etc.

    The point is there are too many moving parts. Of course anyone is welcome to implement the mod - I was just pointing out why the functionality is not supported.
  • How To Impliment

    Hi guys im new to all this. How would i impliment this mod to allow staff to reply via email.

    Thankx
  • Allow threaded reply to emails.

    This is a slightly different approach and would allow any one to reply to a ticket. What's needed is to track message-id(s) and match them up with in-reply-to headers.

    This would involve a little more then just scrapping the subject for a ticket number. The main goal is to allow migration from an inbox style ticket system. We are currently using Mailman and are attempting to migrate to OSTicket.

    I could use a few pointers.
    1. Where to inject message IDs into mysql.
    a. For messages sent by osticket, introduction of message ID generation.
    b. The easy part of when creating a ticket from an email message... Where is this done.
    2. What schema, each email message has an ID that would need to be added to a list. Another table?

    From there authentication can be provided by having a message ID that's related to a ticket and optionally knowing the ticket id.

    Any pointers would be helpful. I'm able to do most of the coding, I just have no idea how to safely extend the MySQL schema.

    EDIT:
    Ohh my, I see the message IDs in the DB already. I'll see what I can cook-up. Perhaps just a small change to perpend 'osticketid...' to the current message id on any message sent.
  • Untested patch for threaded messages.

    [root@internalsupport api]# rcsdiff -u pipe.php
    ===================================================================
    RCS file: pipe.php,v
    retrieving revision 1.2
    diff -u -r1.2 pipe.php
    --- pipe.php 2010/10/19 21:42:58 1.2
    +++ pipe.php 2010/10/21 19:09:21
    @@ -91,8 +91,49 @@
    $var['header']=$parser->getHeader();
    $var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;

    +$var['struct']=$parser->getStruct();
    +$var['inreplyto']=$var['struct']->headers['in-reply-to'];
    +$var['references']=$var['struct']->headers['references'];
    +$var['references']=trim($var['references']);
    +$var['referenceslen']=strlen($var['references']);
    +$var['references']=trim($var['references'],'<>');
    +if ($var['referenceslen']===strlen($var['references'])+2) {
    + $var['references']=explode('> <', $var['references']);
    +} else {
    + $var['references']=array();
    +}
    +$var['inreplyto']=trim($var['inreplyto']);
    +$var['inreplytolen']=strlen($var['inreplyto']);
    +$var['inreplyto']=trim($var['inreplyto'],'<>');
    +if ($var['inreplytolen']===strlen($var['inreplyto'])+2) {
    + $var['inreplyto']=explode('> <', $var['inreplyto']);
    +} else {
    + $var['inreplyto']=array();
    +}
    +$var['references']=array_unique(
    + array_merge($var['references'], $var['inreplyto']));
    +unset($var['inreplyto'], $var['inreplytolen'], $var['referenceslen'],
    + $var['struct']);
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + $var['references'][$k_mmestnik]='<'.$v_mmestnik.'>';
    +}
    +unset($k_mmestnik,$v_mmestnik);
    +
    $ticket=null;
    -if(preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + $tickrow_mmestnik=db_query(
    + \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    + while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    + $tickid_mmestnik = $row_mmestnik['ticket_id'];
    + $ticket= new Ticket(Ticket::getIdByExtId($extid));
    + if($ticket) break 2;
    + }
    +}
    +# TODO: Look for more then one and handle what else is found.
    +unset($var['references'], $k_mmestnik, $v_mmestnik, $tickrow_mmestnik,
    + $row_mmestnik, $tickid_mmestnik);
    +# TODO: Clean up mysql objects properly, how?
    +if(!$ticket && preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    @@ -129,4 +170,5 @@
    }
    }
    api_exit(EX_SUCCESS);
    +return NULL;
    ?>
  • I tried all mods, listed here - not working :(
    Someone, who have working method, please, paste it here.

    And I have one idea. If it's possible, to add reply mail (example: [email]reply@org.com[/email]).
    When Staff (staff@org.com) get's alert, he could answer via mail to [email]reply@org.com[/email]. And we need a script, adding mails, got by [email]reply@org.com[/email] as a comments, added to ticket. Get ticket number from mail title, using parser.
  • I need a little help coding this.

    Something is not right. Looks like emails that match are just dropped.

    Any advice on debugging this? Where/how should I log debugging messages?
  • Guys, I really want to make this work, but I don't know how to. I did manage to get it working, but it would fail when sending the message to the user. It did add correctly to the ticket as a staff message, but the user didn't get an email, and I got a bounce-back error:

    pipe to |/.......api/pipe.php
    generated by ****@*****
    local delivery failed
  • So when a client replies to the email it is added to the thread. I would love this. Does this mod do that.
  • That's the intent. To have messages that are replied to be interpreted as a response instead of a new ticket.

    I believe that this line:
    if(preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    has a syntax error, it's missing two '/'s. Corrected in this patch. Other changes are the inclusion of logging, logs to maillog on my machine.

    TODO: This may not function on messages sent by OST, only intended to work against the original mail messages... That is this should work to have OST follow an email list for example.

    Assistance from an OST developer would be appreciated, specifically in regards to the ticket API. It seams as thought the call to postMessage below is failing in some situations... Actually I don't think it's ever worked for me.

    Another patch that would complement this patch is to add VERP features the the code that OST calls to send messages. As well as inserting a referential MessageID to the email headers. A pointer to this section of the code would be better then having me hunt around for it.

    [root@internalsupport api]# rcsdiff -ur1.1 pipe.php
    ===================================================================
    RCS file: pipe.php,v
    retrieving revision 1.1
    diff -u -r1.1 pipe.php
    --- pipe.php 2010/10/19 21:42:21 1.1
    +++ pipe.php 2010/11/08 19:10:14
    @@ -13,7 +13,7 @@
    See LICENSE.TXT for details.

    vim: expandtab sw=4 ts=4 sts=4:
    - $Id: pipe.php,v 1.1 2010/10/19 21:42:21 root Exp $
    + $Id: pipe.php,v 1.4 2010/11/08 19:09:10 root Exp root $
    **********************************************************************/
    @chdir(realpath(dirname(__FILE__)).'/'); //Change dir.
    ini_set('memory_limit', '256M'); //The concern here is having enough mem for emails with attachments.
    @@ -78,6 +78,7 @@
    if($from->comment && $from->comment[0])
    $name.=' ('.$from->comment[0].')';
    $subj=utf8_encode($parser->getSubject());
    +$subj=preg_replace('/^[\[][[:alnum:] ]+[\]][\s]/', '', $subj);
    if(!($body=Format::stripEmptyLines($parser->getBody())) && $subj)
    $body=$subj;

    @@ -90,8 +91,54 @@
    $var['header']=$parser->getHeader();
    $var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;

    +$var['struct']=$parser->getStruct();
    +$var['inreplyto']=$var['struct']->headers['in-reply-to'];
    +$var['references']=$var['struct']->headers['references'];
    +$var['references']=trim($var['references']);
    +$var['referenceslen']=strlen($var['references']);
    +$var['references']=trim($var['references'],'<>');
    +if ($var['referenceslen']===strlen($var['references'])+2) {
    + $var['references']=preg_split('/>[\s]+</', $var['references'], PREG_SPLIT_NO_EMPTY);
    +} else {
    + $var['references']=array();
    +}
    +$var['inreplyto']=trim($var['inreplyto']);
    +$var['inreplytolen']=strlen($var['inreplyto']);
    +$var['inreplyto']=trim($var['inreplyto'],'<>');
    +if ($var['inreplytolen']===strlen($var['inreplyto'])+2) {
    + $var['inreplyto']=preg_split('/>[\s]+</', $var['inreplyto'], PREG_SPLIT_NO_EMPTY);
    +} else {
    + $var['inreplyto']=array();
    +}
    +$var['references']=array_unique(
    + array_merge($var['references'], $var['inreplyto']));
    +unset($var['inreplyto'], $var['inreplytolen'], $var['referenceslen'],
    + $var['struct']);
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + $var['references'][$k_mmestnik]='<'.$v_mmestnik.'>';
    +}
    +unset($k_mmestnik,$v_mmestnik);
    +
    +openlog(\"OSTicket: Pipe\", LOG_PID, LOG_MAIL);
    +syslog(LOG_DEBUG, 'Starting run for msg-id: '.$var['mid']);
    $ticket=null;
    -if(preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    + $tickrow_mmestnik=db_query(
    + \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    + while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    + $tickid_mmestnik = $row_mmestnik['ticket_id'];
    + syslog(LOG_NOTICE, 'Open ticket: '.$extid);
    + $ticket= new Ticket(Ticket::getIdByExtId($extid));
    + if($ticket) break 2;
    + syslog(LOG_ERR, 'Open ticket '.$extid.' failed.');
    + }
    +}
    +# TODO: Look for more then one and handle what else is found.
    +unset($var['references'], $k_mmestnik, $v_mmestnik, $tickrow_mmestnik,
    + $row_mmestnik, $tickid_mmestnik);
    +# TODO: Clean up mysql objects properly, how?
    +if(!$ticket && preg_match ('/[[#][0-9]{1,10}]/',$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    @@ -113,9 +160,11 @@
    list($message)=split($tag,$var['message']);
    //post message....postMessage does the cleanup.
    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
    + syslog(LOG_CRIT,'Ticket postMessage failed.');
    api_exit(EX_DATAERR,\"Unable to post message \n\n $message\n\");
    }
    }
    +closelog();
    //Ticket created...save attachments if enabled.
    if($cfg->allowEmailAttachments()) {
    if($attachments=$parser->getAttachments()){
    @@ -128,4 +177,5 @@
    }
    }
    api_exit(EX_SUCCESS);
    +return NULL;
    ?>
  • mmestnik;17686 said:


    RCS file: pipe.php,v
    retrieving revision 1.1
    diff -u -r1.1 pipe.php
    --- pipe.php 2010/10/19 21:42:21 1.1
    +++ pipe.php 2010/11/08 19:10:14
    @@ -13,7 +13,7 @@
    See LICENSE.TXT for details.

    vim: expandtab sw=4 ts=4 sts=4:
    - $Id: pipe.php,v 1.1 2010/10/19 21:42:21 root Exp $
    + $Id: pipe.php,v 1.4 2010/11/08 19:09:10 root Exp root $
    **********************************************************************/
    Hi, can you post here your pipe.txt or send it to my mail please? I can't understand something posted here with rcsdiff.

    my pipe.php:
    #!/usr/bin/php -q
    <?php
    /*********************************************************************
    pipe.php

    Converts piped emails to ticket. Both local and remote!

    Peter Rotich <peter@osticket.com>
    Copyright (c) 2006-2010 osTicket
    http://www.osticket.com

    Released under the GNU General Public License WITHOUT ANY WARRANTY.
    See LICENSE.TXT for details.

    vim: expandtab sw=4 ts=4 sts=4:
    $Id: $
    **********************************************************************/
    @chdir(realpath(dirname(__FILE__)).'/'); //Change dir.
    ini_set('memory_limit', '256M'); //The concern here is having enough mem for emails with attachments.
    require('api.inc.php');
    require_once(INCLUDE_DIR.'class.mailparse.php');
    require_once(INCLUDE_DIR.'class.email.php');

    //Make sure piping is enabled!
    if(!$cfg->enableEmailPiping())
    api_exit(EX_UNAVAILABLE,'Email piping not enabled - check MTA settings.');
    //Get the input
    $data=isset($_SERVER['HTTP_HOST'])?file_get_contents('php://input'):file_get_contents('php://stdin');
    if(empty($data)){
    api_exit(EX_NOINPUT,'No data');
    }

    //Parse the email.
    $parser= new Mail_Parse($data);
    if(!$parser->decode()){ //Decode...returns false on decoding errors
    api_exit(EX_DATAERR,'Email parse failed ['.$parser->getError().\"]\n\n\".$data);
    }



    //Check from address. make sure it is not a banned address.
    $fromlist = $parser->getFromAddressList();
    //Check for parsing errors on FROM address.
    if(!$fromlist || PEAR::isError($fromlist)){
    api_exit(EX_DATAERR,'Invalid FROM address ['.$fromlist?$fromlist->getMessage():''.\"]\n\n\".$data);
    }

    $from=$fromlist[0]; //Default.
    foreach($fromlist as $fromobj){
    if(!Validator::is_email($fromobj->mailbox.'@'.$fromobj->host))
    continue;
    $from=$fromobj;
    break;
    }

    //TO Address:Try to figure out the email associated with the message.
    $tolist = $parser->getToAddressList();
    foreach ($tolist as $toaddr){
    if(($emailId=Email::getIdByEmail($toaddr->mailbox.'@'.$toaddr->host))){
    //We've found target email.
    break;
    }
    }
    if(!$emailId && ($cclist=$parser->getCcAddressList())) {
    foreach ($cclist as $ccaddr){
    if(($emailId=Email::getIdByEmail($ccaddr->mailbox.'@'.$ccaddr->host))){
    break;
    }
    }
    }
    //TODO: Options to reject emails without a matching To address in db? May be it was Bcc? Current Policy: If you pipe, we accept policy

    require_once(INCLUDE_DIR.'class.ticket.php'); //We now need this bad boy!

    $var=array();
    $deptId=0;
    $name=trim($from->personal,'\"');
    if($from->comment && $from->comment[0])
    $name.=' ('.$from->comment[0].')';
    $subj=utf8_encode($parser->getSubject());
    //1
    $subj=preg_replace('/^[\[][[:alnum:] ]+[\]][\s]/', '', $subj);
    if(!($body=Format::stripEmptyLines($parser->getBody())) && $subj)
    $body=$subj;

    $var['mid']=$parser->getMessageId();
    $var['email']=$from->mailbox.'@'.$from->host;
    $var['name']=$name?utf8_encode($name):$var['email'];
    $var['emailId']=$emailId?$emailId:$cfg->getDefaultEmailId();
    $var['subject']=$subj?$subj:'[No Subject]';
    $var['message']=utf8_encode(Format::stripEmptyLines($body));
    $var['header']=$parser->getHeader();
    $var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;
    //2
    $var['struct']=$parser->getStruct();
    $var['inreplyto']=$var['struct']->headers['in-reply-to'];
    $var['references']=$var['struct']->headers['references'];
    $var['references']=trim($var['references']);
    $var['referenceslen']=strlen($var['references']);
    $var['references']=trim($var['references'],'<>');
    if ($var['referenceslen']===strlen($var['references'])+2) {
    $var['references']=preg_split('/>[\s]+</', $var['references'], PREG_SPLIT_NO_EMPTY);
    } else {
    $var['references']=array();
    }
    $var['inreplyto']=trim($var['inreplyto']);
    $var['inreplytolen']=strlen($var['inreplyto']);
    $var['inreplyto']=trim($var['inreplyto'],'<>');
    if ($var['inreplytolen']===strlen($var['inreplyto'])+2) {
    $var['inreplyto']=preg_split('/>[\s]+</', $var['inreplyto'], PREG_SPLIT_NO_EMPTY);
    } else {
    $var['inreplyto']=array();
    }
    $var['references']=array_unique(
    array_merge($var['references'], $var['inreplyto']));
    unset($var['inreplyto'], $var['inreplytolen'], $var['referenceslen'],
    $var['struct']);
    foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    $var['references'][$k_mmestnik]='<'.$v_mmestnik.'>';
    }
    unset($k_mmestnik,$v_mmestnik);

    openlog(\"OSTicket: Pipe\", LOG_PID, LOG_MAIL);
    syslog(LOG_DEBUG, 'Starting run for msg-id: '.$var['mid']);
    $ticket=null;

    foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    $tickrow_mmestnik=db_query(
    \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    $tickid_mmestnik = $row_mmestnik['ticket_id'];
    syslog(LOG_NOTICE, 'Open ticket: '.$extid);
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    if($ticket) break 2;
    syslog(LOG_ERR, 'Open ticket '.$extid.' failed.');
    }
    }
    # TODO: Look for more then one and handle what else is found.
    unset($var['references'], $k_mmestnik, $v_mmestnik, $tickrow_mmestnik,
    $row_mmestnik, $tickid_mmestnik);
    # TODO: Clean up mysql objects properly, how?
    if(!$ticket && preg_match ('/[[#][0-9]{1,10}]/',$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    list($message)=split($tag,$var['message']);
    //post message....postMessage does the cleanup.
    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
    syslog(LOG_CRIT,'Ticket postMessage failed.');
    api_exit(EX_DATAERR,\"Unable to post message \n\n $message\n\");
    }
    }
    closelog();
    //Ticket created...save attachments if enabled.
    if($cfg->allowEmailAttachments()) {
    if($attachments=$parser->getAttachments()){
    }
    }
    api_exit(EX_SUCCESS);
    return NULL;
    ?>

    No results.
    Maybe it's because I have mail title like "New ticket created [#123456]". I tried answering with different titles - new tickets only.
    Maybe it's because "@chdir(realpath(dirname(__FILE__)).'/'); //Change dir."? I tried using "/var/www/ost/api/pipe.php" and "/var/www/ost/api/", where it's located.
  • Is this mod fully functional yet?
  • You would run any PHP code I supplied without reading it first? It's to your benefit to learn enough English to use our software and that's why we have not learned how to write applications using locals as this information is useless to us in other areas of our lives. Though if you plan on making use of computers learning how to use diff and patch should be of interest to you any time you are working with text files that change.

    The "patch" program is what you are looking for. It's also possible that your pipe may differ from the one I'm using, in that case I'm supposed to be able to do something with an orig and rej files that patch produces. I'm eager to learn this process as this aspect of diff and patch are a mystery to me.

    As this is a WIP it should only be available to developers currently.

    This version uses tested preg options. The previous options were created following the documentation, it lied. There was also a bug where some variable names didn't match up. Causing the patch to not work at all.

    I can only hope that this patch is closer to working.

    [root@internalsupport api]# rcsdiff -ur1.1 pipe.php
    ===================================================================
    RCS file: pipe.php,v
    retrieving revision 1.1
    diff -u -r1.1 pipe.php
    --- pipe.php 2010/10/19 21:42:21 1.1
    +++ pipe.php 2010/11/09 16:44:42
    @@ -13,7 +13,7 @@
    See LICENSE.TXT for details.

    vim: expandtab sw=4 ts=4 sts=4:
    - $Id: pipe.php,v 1.1 2010/10/19 21:42:21 root Exp $
    + $Id: pipe.php,v 1.5 2010/11/09 16:44:06 root Exp root $
    **********************************************************************/
    @chdir(realpath(dirname(__FILE__)).'/'); //Change dir.
    ini_set('memory_limit', '256M'); //The concern here is having enough mem for emails with attachments.
    @@ -78,6 +78,7 @@
    if($from->comment && $from->comment[0])
    $name.=' ('.$from->comment[0].')';
    $subj=utf8_encode($parser->getSubject());
    +$subj=preg_replace('/^[\[][[:alnum:] ]+[\]][[:space:]]/', '', $subj);
    if(!($body=Format::stripEmptyLines($parser->getBody())) && $subj)
    $body=$subj;

    @@ -90,8 +91,55 @@
    $var['header']=$parser->getHeader();
    $var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;

    +$var['struct']=$parser->getStruct();
    +$var['inreplyto']=$var['struct']->headers['in-reply-to'];
    +$var['references']=$var['struct']->headers['references'];
    +$var['references']=trim($var['references']);
    +$var['referenceslen']=strlen($var['references']);
    +$var['references']=trim($var['references'],'<>');
    +if ($var['referenceslen']===strlen($var['references'])+2) {
    + $var['references']=preg_split('/>[[:space:]]+</', $var['references']);
    +} else {
    + $var['references']=array();
    +}
    +$var['inreplyto']=trim($var['inreplyto']);
    +$var['inreplytolen']=strlen($var['inreplyto']);
    +$var['inreplyto']=trim($var['inreplyto'],'<>');
    +if ($var['inreplytolen']===strlen($var['inreplyto'])+2) {
    + $var['inreplyto']=preg_split('/>[[:space:]]+</', $var['inreplyto']);
    +} else {
    + $var['inreplyto']=array();
    +}
    +$var['references']=array_unique(
    + array_merge($var['references'], $var['inreplyto']));
    +unset($var['inreplyto'], $var['inreplytolen'], $var['referenceslen'],
    + $var['struct']);
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + $var['references'][$k_mmestnik]='<'.$v_mmestnik.'>';
    +}
    +unset($k_mmestnik,$v_mmestnik);
    +
    +openlog(\"OSTicket: Pipe\", LOG_PID, LOG_MAIL);
    +syslog(LOG_DEBUG, 'Starting run for msg-id: '.$var['mid']);
    $ticket=null;
    -if(preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + if (!$v_mmestnik) continue;
    + syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    + $tickrow_mmestnik=db_query(
    + \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    + while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    + $tickid_mmestnik = $row_mmestnik['ticket_id'];
    + syslog(LOG_NOTICE, 'Open ticket: '.$tickid_mmestnik);
    + $ticket= new Ticket(Ticket::getIdByExtId($tickid_mmestnik));
    + if($ticket) break 2;
    + syslog(LOG_ERR, 'Open ticket '.$tickid_mmestnik.' failed.');
    + }
    +}
    +# TODO: Look for more then one and handle what else is found.
    +unset($var['references'], $k_mmestnik, $v_mmestnik, $tickrow_mmestnik,
    + $row_mmestnik, $tickid_mmestnik);
    +# TODO: Clean up mysql objects properly, how?
    +if(!$ticket && preg_match ('/[[#][0-9]{1,10}]/',$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    @@ -113,9 +161,11 @@
    list($message)=split($tag,$var['message']);
    //post message....postMessage does the cleanup.
    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
    + syslog(LOG_CRIT,'Ticket postMessage failed.');
    api_exit(EX_DATAERR,\"Unable to post message \n\n $message\n\");
    }
    }
    +closelog();
    //Ticket created...save attachments if enabled.
    if($cfg->allowEmailAttachments()) {
    if($attachments=$parser->getAttachments()){
    @@ -128,4 +178,5 @@
    }
    }
    api_exit(EX_SUCCESS);
    +return NULL;
    ?>


    Here is the same file encoded to avoid being altered by the forum software, it's valid shell code.
    <<'EOF' tr -d '\n' | base64 -d | bzcat
    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
    kvYNv7h3mhQ2z8D/xdyRThQkP+qtQoA=
    EOF
  • This is the next edit I'm trying. This corrects a vulnerable SQL injection as well as tries harder to pass the correct parameter to the OST API.
    [root@internalsupport api]# rcsdiff -kk -qur1.5 -r1.6 pipe.php
    --- pipe.php 2010/11/09 16:44:06 1.5
    +++ pipe.php 2010/11/09 20:03:27 1.6
    @@ -126,9 +126,11 @@
    if (!$v_mmestnik) continue;
    syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    $tickrow_mmestnik=db_query(
    - \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    + 'SELECT ticketID FROM ost_ticket_message '.
    + 'STRAIGHT_JOIN ost_ticket ON ost_ticket_message.ticket_id = ost_ticket.ticket_id '.
    + 'WHERE messageId=\''. mysql_real_escape_string($v_mmestnik). '\'');
    while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    - $tickid_mmestnik = $row_mmestnik['ticket_id'];
    + $tickid_mmestnik = $row_mmestnik['ticketID'];
    syslog(LOG_NOTICE, 'Open ticket: '.$tickid_mmestnik);
    $ticket= new Ticket(Ticket::getIdByExtId($tickid_mmestnik));
    if($ticket) break 2;
  • mmestnik, just I see rcsdiff first time, so I thought I could to make a mistake, modding my pipe.php.

    As I understood, problem is wrong getting subject from mail title (encoding / parsing / preg rules).
  • That's one way of looking at it, if I understand you correctly.

    Getting the ticket ID from the subject of an email would allow anyone who knows the ticket ID to be able to reply to a ticket(As described previously on this thread or other related threads).
    IMHO Depending on ticket ID(s) at all is going to have issues, let's say the ID from the subject is accentually changed or altered by the user. This might cause a registered/authenticated user to post to the wrong ticket, bad+bad+bad=3*bad.

    Using md5 or sha hashes is a great idea, although E-Mail has a usable concept called MessageID. MessageID(s) are randomly generated, typically by an email server, and should be uniq across the planet earth.

    My patch uses MessageID(s) and *will* not use subject contents. I've just loaded a large mailman archive into my OST and the results look great, about %80 success. One issue worth noting is that Outlook and Exchange do not play nice. Microsoft has patches to correct this, look for In-Reply-To header issues.

    The next round of patches that I'm going to look at are to get the MessageID to be placed in "outgoing" messages. VERP and ReplyTo headers will contain the MessageID so that replies to messages sent by OST will be threaded also.

    That is the address used will look like this:
    xisupport+DB5DFE73-A937-4B27-BD06-19CFEC512FDB=bluegecko.net@internalsupport.nagios.com
    Where [email]DB5DFE73-A937-4B27-BD06-19CFEC512FDB@bluegecko.net[/email] is the original MesageID. I was also thinking about submitting a self generated MessageID with the email, but as using VERP is better I'm not. It's something only useful in cases were VERP is not an option, in those cases changing Email servers is recommended solution.
  • Need assistance from OSTicket Developer.

    I'm still looking for some assistance with this patch. I feel that there is a short-cut way to open a ticket by MessageID. Here is the current code that seams to do that:
      syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    $tickrow_mmestnik=db_query(
    'SELECT ticketID FROM ost_ticket_message '.
    'STRAIGHT_JOIN ost_ticket ON ost_ticket_message.ticket_id = ost_ticket.ticket_id '.
    'WHERE messageId=\''. mysql_real_escape_string($v_mmestnik). '\'');
    while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    $tickid_mmestnik = $row_mmestnik['ticketID'];
    syslog(LOG_NOTICE, 'Open ticket: '.$tickid_mmestnik);
    $ticket= new Ticket(Ticket::getIdByExtId($tickid_mmestnik));
    if($ticket) break 2;
    syslog(LOG_ERR, 'Open ticket '.$tickid_mmestnik.' failed.');
    }


    This code is working as intended, however I feel that the STRAIGHT_JOIN and the getIdByExtId are reciprocals, that is they can be factored out... If I only knew what I was doing.

    As indicated the next step is to alter the way EMails are sent by OST to include a "cookie" that can be used later to map any reply or DSN(bounce message) back to the event and ticket that created it.
  • If user answered by mail, his message became an comment to his ticket (ok).
    If staff answered by mail, his message became a new ticket (fail).
  • Dang,
    I came across that as well. Make all your templates start with:
    [#%ticket] 
    The real fix for this is to place credentials in *other* email headers that are not editable by the user. However this worked for now.
  • Alpha release of this patch.

    All,
    Now that I have something that I've tested and worked for me, this can be considered alpha. It's still missing VERP for messages sent by OST, however for our site this is not a version 1.0 requirement. Although as Dang reports this is a failure on some deployments as messages sent to OST are not typically sent to staff. On our deployment Mailman sends a copy of every message to staff and OST.

    rcsdiff -kk -qur1.5 -r1.6 pipe.php
    --- pipe.php 2010/11/09 16:44:06 1.5
    +++ pipe.php 2010/11/09 20:03:27 1.6
    @@ -126,9 +126,11 @@
    if (!$v_mmestnik) continue;
    syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    $tickrow_mmestnik=db_query(
    - \"SELECT ticket_id FROM ost_ticket_message WHERE messageId='$v_mmestnik'\");
    + 'SELECT ticketID FROM ost_ticket_message '.
    + 'STRAIGHT_JOIN ost_ticket ON ost_ticket_message.ticket_id = ost_ticket.ticket_id '.
    + 'WHERE messageId=\''. mysql_real_escape_string($v_mmestnik). '\'');
    while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    - $tickid_mmestnik = $row_mmestnik['ticket_id'];
    + $tickid_mmestnik = $row_mmestnik['ticketID'];
    syslog(LOG_NOTICE, 'Open ticket: '.$tickid_mmestnik);
    $ticket= new Ticket(Ticket::getIdByExtId($tickid_mmestnik));
    if($ticket) break 2;
    [root@internalsupport api]# rcsdiff -kk -qur1.1 -r1. pipe.php
    --- pipe.php 2010/10/19 21:42:21 1.1
    +++ pipe.php 2010/11/09 20:03:27 1.6
    @@ -78,6 +78,7 @@
    if($from->comment && $from->comment[0])
    $name.=' ('.$from->comment[0].')';
    $subj=utf8_encode($parser->getSubject());
    +$subj=preg_replace('/^[\[][[:alnum:] ]+[\]][[:space:]]/', '', $subj);
    if(!($body=Format::stripEmptyLines($parser->getBody())) && $subj)
    $body=$subj;

    @@ -90,8 +91,57 @@
    $var['header']=$parser->getHeader();
    $var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;

    +$var['struct']=$parser->getStruct();
    +$var['inreplyto']=$var['struct']->headers['in-reply-to'];
    +$var['references']=$var['struct']->headers['references'];
    +$var['references']=trim($var['references']);
    +$var['referenceslen']=strlen($var['references']);
    +$var['references']=trim($var['references'],'<>');
    +if ($var['referenceslen']===strlen($var['references'])+2) {
    + $var['references']=preg_split('/>[[:space:]]+</', $var['references']);
    +} else {
    + $var['references']=array();
    +}
    +$var['inreplyto']=trim($var['inreplyto']);
    +$var['inreplytolen']=strlen($var['inreplyto']);
    +$var['inreplyto']=trim($var['inreplyto'],'<>');
    +if ($var['inreplytolen']===strlen($var['inreplyto'])+2) {
    + $var['inreplyto']=preg_split('/>[[:space:]]+</', $var['inreplyto']);
    +} else {
    + $var['inreplyto']=array();
    +}
    +$var['references']=array_unique(
    + array_merge($var['references'], $var['inreplyto']));
    +unset($var['inreplyto'], $var['inreplytolen'], $var['referenceslen'],
    + $var['struct']);
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + $var['references'][$k_mmestnik]='<'.$v_mmestnik.'>';
    +}
    +unset($k_mmestnik,$v_mmestnik);
    +
    +openlog(\"OSTicket: Pipe\", LOG_PID, LOG_MAIL);
    +syslog(LOG_DEBUG, 'Starting run for msg-id: '.$var['mid']);
    $ticket=null;
    -if(preg_match (\"[[#][0-9]{1,10}]\",$var['subject'],$regs)) {
    +foreach($var['references'] as $k_mmestnik => $v_mmestnik){
    + if (!$v_mmestnik) continue;
    + syslog(LOG_INFO, 'Search msg-id: '.$v_mmestnik);
    + $tickrow_mmestnik=db_query(
    + 'SELECT ticketID FROM ost_ticket_message '.
    + 'STRAIGHT_JOIN ost_ticket ON ost_ticket_message.ticket_id = ost_ticket.ticket_id '.
    + 'WHERE messageId=\''. mysql_real_escape_string($v_mmestnik). '\'');
    + while($row_mmestnik = mysql_fetch_array($tickrow_mmestnik)) {
    + $tickid_mmestnik = $row_mmestnik['ticketID'];
    + syslog(LOG_NOTICE, 'Open ticket: '.$tickid_mmestnik);
    + $ticket= new Ticket(Ticket::getIdByExtId($tickid_mmestnik));
    + if($ticket) break 2;
    + syslog(LOG_ERR, 'Open ticket '.$tickid_mmestnik.' failed.');
    + }
    +}
    +# TODO: Look for more then one and handle what else is found.
    +unset($var['references'], $k_mmestnik, $v_mmestnik, $tickrow_mmestnik,
    + $row_mmestnik, $tickid_mmestnik);
    +# TODO: Clean up mysql objects properly, how?
    +if(!$ticket && preg_match ('/[[#][0-9]{1,10}]/',$var['subject'],$regs)) {
    $extid=trim(preg_replace(\"/[^0-9]/\", \"\", $regs[0]));
    $ticket= new Ticket(Ticket::getIdByExtId($extid));
    //Allow mismatched emails?? For now hell NO.
    @@ -113,9 +163,11 @@
    list($message)=split($tag,$var['message']);
    //post message....postMessage does the cleanup.
    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
    + syslog(LOG_CRIT,'Ticket postMessage failed.');
    api_exit(EX_DATAERR,\"Unable to post message \n\n $message\n\");
    }
    }
    +closelog();
    //Ticket created...save attachments if enabled.
    if($cfg->allowEmailAttachments()) {
    if($attachments=$parser->getAttachments()){
    @@ -128,4 +180,5 @@
    }
    }
    api_exit(EX_SUCCESS);
    +return NULL;
    ?>


    <<'EOF' tr -d '\n' | base64 -d | bzcat
    QlpoOTFBWSZTWSJamtcAAb/fgGIw/e/////33s+////qUAX4iB6zuttbrNA7XcOgShEJqntNU/Uz
    QTyQ9JlHlPKek9GptIGj1PUB6m0mmTQAygmRk0p6Go0zRNNA0AAAaNMgAAABKZEjSNIU8FPyTQRp
    tJoPQZARoZHqaaPUAeoyHDQyaaGmRoaZGQZGRoZAYmjJoAyZGIYSKCCMQymGoYUyh6np6mpiBpoD
    0nqND1AekBpgG6iI3A4Ot+xJ2jf9ycX2uSRISj3qpk1kmu+AmwZCCyEoSjVqmaR3c2Ur4uDuqcfj
    sEHBinEQFyGEWZBnxf2P+F3qeIi+ocokTThf5vptu3M9R4b323KYmz5rme+E0B2JKo7k4MBNp4rI
    78U23ZT+F7asrDUKsTLxlmh9E9iqGSbgfKkch0RfrhXJhwKOu+HW/W3Nj75clntna1IfRmV99GVV
    S4OzgsGrniqhKVmOobSpcVrTsUOyGqs13E7ln43FZOvIqv47KtMpsweVVCbJhIuxCbmlVQJRTSQh
    vLIdjhjCKx6ZTO4uYe9HZWBObj60w146MzQsDc22S3xHxdgevkkk7LfGhuSpqT6Jn+r2qsRNJMY4
    44AjL3/Pmie3M9dbS0mFZMmrXvpOrBaO8UTWTsSKdF6b2sqmEOBGm/V29lvpcfaI7CzVPrmJu1Mp
    DdieTF0aMChzHCU0SP175zJl8KSXWkjqaE3pIjKVEQTeaWmYlpJfr4en29q+zC5ktmgwk3OXzHR6
    eiWOeY3d4KSThSoSQ4npFgtZdVU4u/S5EuyQDRFxzWxyNK0PIKaZ1inSuaBaFbf6e3MVkyHsiZno
    8dvNsK2gdYI+VFqH4xzkhoqwQhmJWJT3sQJkLdhVCVK8IZtLcprUGm0LgSy4+9XNdXBY3jTr82RG
    1rysLPFCtpQGImz0wvGYlwhm2gXqEiyg8IYIolm9HOoQjShBDF31jREMwUgnAx002wBgzho5demS
    9PzrOdnX1d0Mr0cYyxDJg9f3i3Q9JTRi9OE9eg8XJhgl4fZs52eF5RhsmZ2Rya8bdIZ273lqrVcX
    KT9a1kVBAn2nbzNsBy4ZTQ6rTMkW3JRUekODamQyAkt3JFiWofhfhRmPOce46mCTYB2RMJOYVXT/
    Ifb5++dvvVnxxW9UJu6GVQSwQMCO2PgeBaUROsrwRpLWHy5u5UxKH7fZ8vSLiPzOVnPz757nLEkh
    iklyT1XuHFcMqSA1JAQAqC8YJ70+QrzDRG6qdv33vtCIg/mxG5ZhZ6TJcFUf70eNGP/Aez/Sgppi
    jAESLCuRAYbUkqeNOtRMto026BzgfKOMWoKLY0X3ZEUVRXOTw70nwbnWGcFbex8GDlRw4DmMMZKu
    ZHOhmRzP2BUlskhKNegIVlAiMwRzSuSiIMyqFuBEpyM2GhAYZIKk9Q2xJdCMqYLkTGhhZbWVm0xB
    YaDmBE7iJtHSqs7YuWwzGQURWsW1cBqc1YLL05vgKSc5TiEdhlZNe+DBpoC81EPWa4a0V6ht+wZ/
    VOsBaVuazIw7bIxSUILuvKsufgHtKTigs3huYI3oxSSq9soMoiWlXTPtqlE4ZRt2BqyG7n88woXG
    RLOJVl7gAFESl98sZdDpcc0gLFezXDlOwEUTnFgIelGCjyadWqM6ZBtPom6ggtgntkCBaABiYtZJ
    UVGJACtetHGCY6MFgUtJe0zlprLxYX5TZeYmHV6UPAEF99KxiMWyO+l0Rkt7C0bhxaYlSYBD09UO
    zug9q6I661d0XKxBaJIwQ4rdPnygjEXIqwRM68Ulzyo3C6x2DCUOXaqMvEbedFI0qkaYxMJEUgZ5
    B79JHUC20TV2akV62KhehFnmXNsJKYKsoaUAFKigMQwQz0Y79TuyBq5CHGQntsRIhwFIDlEWhRgI
    GGsNXPiWRw2E3fAcIJ59hIkBYa7bQFVqS3MDSiQjNRe1m8g9GBtqSqtR5a2yHLfsWievp0aRIWfO
    ZBFRA7Blk/HkgPeROJGRejgqElkS7xt/WP4TBQbZ6j/xdyRThQkCJamtcA==
    EOF
  • This is a copy of the whole /var/www/html/osticket/api/pipe.php file:
    <<'EOF' tr -d '\n' | base64 -d | bzcat
    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
    iY5IavgPHIEhRx8F/xdyRThQkG6NtZM=
    EOF
Sign In or Register to comment.