app = $app; if ($intern) return; $this->app->ActionHandlerInit($this); $this->app->ActionHandler("list", "ticket_list"); $this->app->ActionHandler("create", "ticket_create"); // This automatically adds a "New" button $this->app->ActionHandler("edit", "ticket_edit"); $this->app->ActionHandler("minidetail", "ticket_minidetail"); $this->app->ActionHandler("text", "ticket_text"); // Output text for iframe display $this->app->ActionHandler("text_ausgang", "ticket_text_ausgang"); // Output text for iframe display $this->app->ActionHandler("statusfix", "ticket_statusfix"); // Xentral 20 compatibility set all ticket status to latest ticket_nachricht status $this->app->ActionHandler("datefix", "ticket_datefix"); // Xentral 20 compatibility set all ticket dates to latest ticket_nachricht date $this->app->ActionHandler("dateien", "ticket_dateien"); $this->app->DefaultActionHandler("list"); $this->app->ActionHandlerListen($app); } public function Install() { /* Fill out manually later */ } function ticket_status_icon(string $status) { return(''); } public function TableSearch(&$app, $name, $erlaubtevars) { function ticket_iconssql() { return "CONCAT('')"; } switch ($name) { case "ticket_list": $allowed['ticket_list'] = array('list'); $heading = array('','','Ticket #', 'Aktion','Adresse', 'Betreff', 'Tags', 'Verant.', 'Nachr.', 'Status', 'Projekt', 'Menü'); $width = array('1%','1%','5%', '5%', '5%', '30%', '1%', '5%', '1%', '1%', '1%', '1%'); $findcols = array('t.id','t.id','t.schluessel', 't.zeit', 'a.name', 't.betreff', 't.tags', 'w.warteschlange', 'nachrichten_anz', 't.status', 'p.abkuerzung'); $searchsql = array( 't.schluessel', 't.zeit', 'a.name', 't.betreff','t.notiz', 't.tags', 'w.warteschlange', 't.status', 'p.abkuerzung','(SELECT mail FROM ticket_nachricht tn WHERE tn.ticket = t.schluessel AND tn.versendet <> 1 LIMIT 1)'); $defaultorder = 1; $defaultorderdesc = 0; $menu = "
" . "Conf->WFconf['defaulttheme']}/images/edit.svg\" border=\"0\">" . "
"; $timedifference = "if ( TIMESTAMPDIFF(hour, t.zeit, NOW()) < 24, CONCAT(TIMESTAMPDIFF(hour, t.zeit, NOW()),'h'), CONCAT(TIMESTAMPDIFF(day, t.zeit, NOW()), 'd ',MOD(TIMESTAMPDIFF(hour, t.zeit, NOW()),24),'h'))"; $dropnbox = "'' AS `open`, CONCAT('') AS `auswahl`"; $priobetreff = "if(t.prio!=1,REGEXP_REPLACE(t.betreff, '<[^>]*>+', ''),CONCAT('',REGEXP_REPLACE(t.betreff, '<[^>]*>+', ''),''))"; //+ #20230916 XSS $anzahlnachrichten = "(SELECT COUNT(n.id) FROM ticket_nachricht n WHERE n.ticket = t.schluessel)"; $letztemail = $app->erp->FormatDateTimeShort("(SELECT MAX(n.zeit) FROM ticket_nachricht n WHERE n.ticket = t.schluessel AND n.zeit IS NOT NULL)"); $tagstart = "
  • "; $tagend = "
  • "; $sql = "SELECT SQL_CALC_FOUND_ROWS t.id, ".$dropnbox.", CONCAT('',t.schluessel,''),". $app->erp->FormatDateTimeShort('zeit')." as aktion, CONCAT(COALESCE(CONCAT(a.name,'
    '),''),COALESCE((SELECT mail FROM ticket_nachricht tn WHERE tn.ticket = t.schluessel AND tn.versendet <> 1 LIMIT 1),'')) as combiadresse, CONCAT('',".$priobetreff.",'
    ',replace(substring(ifnull(t.notiz,''),1,500),'\n','
    '),'
    '), CONCAT('
    '), w.warteschlange, ".$anzahlnachrichten." as `nachrichten_anz`, ".ticket_iconssql().", p.abkuerzung, t.id FROM ticket t LEFT JOIN adresse a ON t.adresse = a.id LEFT JOIN warteschlangen w ON t.warteschlange = w.label LEFT JOIN projekt p on t.projekt = p.id"; $where = "1"; // Toggle filters $this->app->Tpl->Add('JQUERYREADY', "$('#meinetickets').click( function() { fnFilterColumn1( 0 ); } );"); $this->app->Tpl->Add('JQUERYREADY', "$('#prio').click( function() { fnFilterColumn2( 0 ); } );"); $this->app->Tpl->Add('JQUERYREADY', "$('#geschlossene').click( function() { fnFilterColumn3( 0 ); } );"); $this->app->Tpl->Add('JQUERYREADY', "$('#spam').click( function() { fnFilterColumn4( 0 ); } );"); for ($r = 1;$r <= 4;$r++) { $this->app->Tpl->Add('JAVASCRIPT', ' function fnFilterColumn' . $r . ' ( i ) { if(oMoreData' . $r . $name . '==1) oMoreData' . $r . $name . ' = 0; else oMoreData' . $r . $name . ' = 1; $(\'#' . $name . '\').dataTable().fnFilter( \'\', i, 0,0 ); } '); } $more_data1 = $this->app->Secure->GetGET("more_data1"); if ($more_data1 == 1) { $where .= " AND t.warteschlange IN (SELECT w.label FROM warteschlangen w WHERE adresse=".$this->app->User->GetAdresse().")"; // Queues of user } else { } $more_data2 = $this->app->Secure->GetGET("more_data2"); if ($more_data2 == 1) { $where .= " AND t.prio = '1'"; } else { } $more_data3 = $this->app->Secure->GetGET("more_data3"); if ($more_data3 == 1) { } else { $where .= " AND (t.status <> 'abgeschlossen')"; // Exclude and geschlossen } $more_data4 = $this->app->Secure->GetGET("more_data4"); if ($more_data4 == 1) { } else { $where .= " AND (t.status <> 'spam')"; } // END Toggle filters $moreinfo = true; // Allow drop down details $menucol = 11; // For moredata $count = "SELECT count(DISTINCT id) FROM ticket t WHERE $where"; // echo(htmlentities($sql." ".$where)); // $groupby = ""; break; } $erg = false; foreach ($erlaubtevars as $k => $v) { if (isset($$v)) { $erg[$v] = $$v; } } return $erg; } // Ensure status 'offen' on self-assigned tickets function ticket_set_self_assigned_status(array $ids) { $sql = "UPDATE ticket SET status = 'offen' WHERE status = 'neu' AND id IN (".implode(',',$ids).") AND warteschlange IN (SELECT label FROM warteschlangen WHERE adresse = '".$this->app->User->GetAdresse()."')"; $this->app->DB->Update($sql); } function ticket_list() { // Process multi action $auswahl = $this->app->Secure->GetPOST('auswahl'); $submit = $this->app->Secure->GetPOST('submit'); $selectedIds = []; if(!empty($auswahl)) { foreach($auswahl as $selectedId) { $selectedId = (int)$selectedId; if($selectedId > 0) { $selectedIds[] = $selectedId; } } switch ($submit) { case 'zuordnen': $status = $this->app->Secure->GetPOST('status'); $warteschlange = $this->app->Secure->GetPOST('warteschlange'); $sql = "UPDATE ticket SET status = '".$status."', zeit = NOW()"; if ($warteschlange != '') { $sql .= ", warteschlange = '".explode(" ",$warteschlange)[0]."'"; } $sql .= " WHERE id IN (".implode(",",$selectedIds).")"; $this->app->DB->Update($sql); $this->ticket_set_self_assigned_status($selectedIds); break; case 'spam_filter': if($this->app->erp->RechteVorhanden('ticketregeln','create')) { $sql = "UPDATE ticket SET status = 'spam', zeit = NOW()"; $sql .= " WHERE id IN (".implode(",",$selectedIds).")"; $this->app->DB->Update($sql); foreach ($selectedIds as $selectedId) { // Check existing $sql = "SELECT id FROM ticket_regeln WHERE empfaenger_email = '' AND sender_email = (SELECT mailadresse FROM ticket WHERE id = ".$selectedId." LIMIT 1) AND name = '' AND betreff = '' AND spam = 1 AND aktiv = 1 "; if (!$this->app->DB->Select($sql)) { $sql = "INSERT IGNORE INTO ticket_regeln ( empfaenger_email, sender_email, name, betreff, spam, persoenlich, prio, dsgvo, adresse, warteschlange, aktiv ) VALUES ( '', (SELECT mailadresse FROM ticket WHERE id = ".$selectedId." LIMIT 1), '', '', 1, 0, 0, 0, 0, '', 1 )"; $this->app->DB->Insert($sql); } } } break; } } // List $this->app->YUI->TagEditor('taglist', array('width'=>370)); $this->app->Tpl->Add('SCRIPTJAVASCRIPT',''); $this->app->erp->MenuEintrag("index.php?module=ticket&action=list", "Übersicht"); $this->app->erp->MenuEintrag("index.php?module=ticket&action=create", "Neu anlegen"); $this->app->erp->MenuEintrag("index.php", "Zurück"); $this->app->Tpl->Set('STATUS', $this->app->erp->GetStatusTicketSelect('neu')); $this->app->YUI->AutoComplete("warteschlange","warteschlangename"); if(!$this->app->erp->RechteVorhanden('ticketregeln','create')) { $this->app->Tpl->Set('SPAM_HIDDEN', 'hidden'); } $this->app->YUI->TableSearch('TAB1', 'ticket_list', "show", "", "", basename(__FILE__), __CLASS__); $this->app->Tpl->Parse('PAGE', "ticket_list.tpl"); } function get_messages_of_ticket($ticket_id, $where, $limit) { if ($limit) { $limitsql = " LIMIT ".((int) $limit); } else { $limitsql = ""; } if (empty($ticket_id)) { $ticket_where = ""; } else { $ticket_where = " AND t.id = ".$ticket_id; } if (empty($where)) { $where = "1"; } // $sql = "SELECT n.id, n.betreff, n.verfasser, n.mail, n.mail_cc, n.zeit, n.zeitausgang, n.versendet, n.text, n.verfasser_replyto, mail_replyto, (SELECT GROUP_CONCAT(value SEPARATOR ', ' FROM ticket_header th WHERE th.ticket_nachricht = n.id AND th.type = 'cc') value from) as cc FROM ticket_nachricht n INNER JOIN ticket t ON t.schluessel = n.ticket WHERE (".$where.") AND t.id = ".$ticket_id." ORDER BY n.zeit DESC ".$limitsql; $sql = "SELECT n.id, n.betreff, n.bearbeiter, n.verfasser, n.mail, t.quelle, ".$this->app->erp->FormatDateTimeShort('n.zeit','zeit').", ".$this->app->erp->FormatDateTimeShort('n.zeitausgang','zeitausgang').", n.versendet, n.text, n.textausgang, n.verfasser_replyto, n.mail_replyto, n.mail_cc, (SELECT GROUP_CONCAT(value SEPARATOR ', ') FROM ticket_header th WHERE th.ticket_nachricht = n.id AND th.type = 'cc') as mail_cc_recipients, (SELECT GROUP_CONCAT(value SEPARATOR ', ') FROM ticket_header th WHERE th.ticket_nachricht = n.id AND th.type = 'to') as mail_recipients FROM ticket_nachricht n INNER JOIN ticket t ON t.schluessel = n.ticket WHERE (".$where.") ".$ticket_where." ORDER BY n.zeit DESC ".$limitsql; return $this->app->DB->SelectArr($sql); } function add_attachments_html($ticket_id, $message_id,$templatepos,$showdelete) { $file_attachments = $this->app->erp->GetDateiSubjektObjekt('Anhang','Ticket',$message_id); if (!empty($file_attachments)) { $this->app->Tpl->Add('NACHRICHT_ANHANG',"
    "); foreach ($file_attachments as $file_attachment) { if ($showdelete) { $deletetext = ''. ''; } else { $deletetext = ""; } $attachtext = ""; /* Not implemented -> Attachment of ticket_nachricht to business object is the better option -> implement later $attachtext = ''. ''; */ $this->app->Tpl->Add($templatepos, "". htmlentities($this->app->erp->GetDateiName($file_attachment)). " (". $this->app->erp->GetDateiSize($file_attachment). ")". "". $deletetext. $attachtext. "
    "); } } } function add_attachments_header_html($ticket_id, $templatepos) { $file_attachments = $this->app->erp->GetDateiSubjektObjekt('%','ticket_header',$ticket_id); if (!empty($file_attachments)) { $this->app->Tpl->Add($templatepos,"{|Anhänge|}:
    "); foreach ($file_attachments as $file_attachment) { $this->app->Tpl->Add($templatepos, "". htmlentities($this->app->erp->GetDateiName($file_attachment)). " (". $this->app->erp->GetDateiSize($file_attachment). ")". "". "
    "); } $this->app->Tpl->Add($templatepos,"
    "); } } function add_messages_tpl($messages, $showdrafts) { // Add Messages now foreach ($messages as $message) { $message['betreff'] = strip_tags($message['betreff']); //+ #20230916 XSS // Clear this first $this->app->Tpl->Set('NACHRICHT_ANHANG',""); if (empty($message['betreff'])) { $message['betreff'] = "..."; } // Xentral 20 compatibility if ($message['textausgang'] != '') { // Sent message $this->app->Tpl->Set("NACHRICHT_BETREFF",''.htmlentities($message['betreff']).''); $this->app->Tpl->Set("NACHRICHT_ZEIT",$message['zeitausgang']); $this->app->Tpl->Set("NACHRICHT_FLOAT","right"); $this->app->Tpl->Set("META_FLOAT","left"); $this->app->Tpl->Set("NACHRICHT_TEXT",$message['textausgang']); $this->app->Tpl->Set("NACHRICHT_SENDER",htmlentities($message['bearbeiter'])); $this->app->Tpl->Set("NACHRICHT_RECIPIENTS",htmlentities($message['verfasser']." <".$message['mail'].">")); // $this->app->Tpl->Set("NACHRICHT_TEXT",$message['textausgang']); $this->app->Tpl->Set("NACHRICHT_TEXT",''); $this->app->Tpl->Parse('MESSAGES', "ticket_nachricht.tpl"); } if ($message['versendet'] == '1' && empty($message['textausgang'])) { // textausgang is always empty, except for old Xentral 20 tickets // Sent message if (is_null($message['zeitausgang'])) { if (!$showdrafts) { continue; } $this->app->Tpl->Set("NACHRICHT_BETREFF",htmlentities($message['betreff']." (Entwurf)")); } else { $this->app->Tpl->Set("NACHRICHT_BETREFF",''.htmlentities($message['betreff']).''); } $this->app->Tpl->Set("NACHRICHT_SENDER",htmlentities($message['verfasser']." <".$message['mail_replyto'].">")); $this->app->Tpl->Set("NACHRICHT_RECIPIENTS",htmlentities($message['mail'])); $this->app->Tpl->Set("NACHRICHT_CC_RECIPIENTS",htmlentities($message['mail_cc'])); $this->app->Tpl->Set("NACHRICHT_FLOAT","right"); $this->app->Tpl->Set("META_FLOAT","left"); $this->app->Tpl->Set("NACHRICHT_ZEIT",$message['zeitausgang']); $this->app->Tpl->Set("NACHRICHT_NAME",htmlentities($message['verfasser'])); } else { // Received message $this->app->Tpl->Set("NACHRICHT_SENDER",htmlentities($message['verfasser']." <".$message['mail'].">")); if ($message['mail_recipients'] != '') { $this->app->Tpl->Set("NACHRICHT_RECIPIENTS",htmlentities($message['mail_recipients'])); } else { // Xentral 20 compatibility $this->app->Tpl->Set("NACHRICHT_RECIPIENTS",htmlentities($message['quelle'])); } $this->app->Tpl->Set("NACHRICHT_CC_RECIPIENTS",htmlentities($message['mail_cc_recipients'])); $this->app->Tpl->Set("NACHRICHT_BETREFF",''.htmlentities($message['betreff']).''); $this->app->Tpl->Set("NACHRICHT_FLOAT","left"); $this->app->Tpl->Set("META_FLOAT","right"); $this->app->Tpl->Set("NACHRICHT_ZEIT",$message['zeit']); } // $this->app->Tpl->Set("NACHRICHT_TEXT",$message['text']); $this->app->Tpl->Set("NACHRICHT_TEXT",''); $this->add_attachments_html($id,$message['id'],'NACHRICHT_ANHANG',false); $this->app->Tpl->Parse('MESSAGES', "ticket_nachricht.tpl"); } } function ticket_text() { $secure_html_tags = array( '
    ', '

    ', '', '', '', '', '
    ', ' "; $blink_css = "animation-name:animation_blink;animation-timing-function:linear;animation-duration:2s;animation-iteration-count:5;"; $secure_text = $blink_style_tag."app->Conf->WFconf['defaulttheme']}/images/icon-invisible.svg\" alt=\"Einige Elemente wurden durch OpenXE blockiert.\" title=\"Einige Elemente wurden durch OpenXE blockiert.\" border=\"0\" style=\"all: initial;display:block;float:right;font-size:small;".$blink_css."\">".$secure_text; } $this->app->Tpl->Set("TEXT",$secure_text); } $this->app->Tpl->Output('ticket_text.tpl'); $this->app->ExitXentral(); } function ticket_text_ausgang() { $mid = $this->app->Secure->GetGET('mid'); if (empty($mid)) { return; } $messages = $this->get_messages_of_ticket("", "n.id = ".$mid, NULL); if (empty($messages)) { } $this->app->Tpl->Set("TEXT",$messages[0]['textausgang']); $this->app->Tpl->Output('ticket_text.tpl'); $this->app->ExitXentral(); } /** * @throws NumberGeneratorException * * @return string */ private function generateRandomTicketNumber(): string { $random = rand(300,700); $loopCounter = 0; while(true) { $candidate = sprintf('%s%04d', date('Ymd'), $random++); if (!$this->app->DB->Select('SELECT id FROM ticket WHERE schluessel = '.$candidate)) { return($candidate); } if ($loopCounter > 99) { throw new NumberGeneratorException('ticket number generation failed'); } $loopCounter++; } } function ticket_save_to_db($id, $input) { // Write to database // Add checks here if (empty($id)) { // New item $id = 'NULL'; } if ($input['betreff'] == '') { $input['betreff'] = "..."; } $input['projekt'] = $this->app->erp->ReplaceProjekt(true,$input['projekt'],true); // Parameters: Target db?, value, from form? $input['adresse'] = $this->app->erp->ReplaceAdresse(true,$input['adresse'],true); // Parameters: Target db?, value, from form? $input['warteschlange'] = explode(" ",$input['warteschlange'])[0]; // Just the label $input['zeit'] = date('Y-m-d H:i:s', time()); $tags = explode(',',$input['tags']); // Replace multiple '!' and '?' foreach ($tags as &$tag) { $pos = strpos($tag, '?'); if ($pos !== false) { $tag = substr($tag,0,$pos+1) . str_replace('?','',substr($tag,$pos+1)); } $tag = preg_replace("/([?!])\\1+/", "$1", $tag); } $input['tags'] = implode(',',$tags); $input['tags'] = str_replace(' ?','?',$input['tags']); $input['tags'] = str_replace(' !','!',$input['tags']); $input['tags'] = str_replace('?!','?',$input['tags']); $input['tags'] = str_replace('!?','?',$input['tags']); $columns = "id, "; $values = "$id, "; $update = ""; $fix = ""; foreach ($input as $key => $value) { if ($this->app->DB->ColumnExists('ticket',$key)) { $columns = $columns.$fix.$key; $values = $values.$fix."'".$value."'"; $update = $update.$fix.$key." = '$value'"; $fix = ", "; } } $sql = "INSERT INTO ticket (".$columns.") VALUES (".$values.") ON DUPLICATE KEY UPDATE ".$update; $this->app->DB->Update($sql); $id = $this->app->DB->GetInsertID(); $this->ticket_set_self_assigned_status(array($id)); return($id); } function save_draft($id, $input) { $columns = "id, "; $values = "$id, "; $update = ""; $fix = ""; // Translate form to table $input['betreff'] = $input['email_betreff']; $input['mail'] = $input['email_an']; $input['mail_cc'] = $input['email_cc']; $input['text'] = $input['email_text']; foreach ($input as $key => $value) { if ($this->app->DB->ColumnExists('ticket_nachricht',$key)) { $columns = $columns.$fix.$key; $values = $values.$fix."'".$value."'"; $update = $update.$fix.$key." = '$value'"; $fix = ", "; } } $sql = "INSERT INTO ticket_nachricht (".$columns.") VALUES (".$values.") ON DUPLICATE KEY UPDATE ".$update; $this->app->DB->Update($sql); } function ticket_create() { $submit = $this->app->Secure->GetPOST('submit'); $input = $this->GetInput(); $projekt_id = $this->app->User->DefaultProjekt(); $projekt = $this->app->DB->Select("SELECT abkuerzung FROM projekt WHERE id = ".$projekt_id); if ($submit != '') { $input['schluessel'] = $this->generateRandomTicketNumber(); $input['kunde'] = $this->app->User->GetName(); $id = $this->ticket_save_to_db($id, $input); header("Location: index.php?module=ticket&action=edit&id=$id"); exit(); } $this->app->Tpl->Set('PROJEKT', $projekt); $this->app->Tpl->Set('STATUSICON', $this->ticket_status_icon('neu')." "); $this->app->YUI->AutoComplete("adresse","adresse"); $this->app->YUI->AutoComplete("projekt","projektname",1); $this->app->YUI->AutoComplete("status","ticketstatus",1); $this->app->Tpl->Set('STATUS', $this->app->erp->GetStatusTicketSelect('neu')); $this->app->YUI->AutoComplete("warteschlange","warteschlangename"); $this->app->Tpl->Parse('PAGE', "ticket_create.tpl"); } function ticket_menu($id) { $this->app->erp->MenuEintrag("index.php?module=ticket&action=edit&id=$id", "Details"); $this->app->erp->MenuEintrag("index.php?module=ticket&action=list", "Zurück zur Übersicht"); $anzahldateien = $this->app->erp->AnzahlDateien("ticket_header",$id); if ($anzahldateien > 0) { $anzahldateien = " (".$anzahldateien.")"; } else { $anzahldateien=""; } $this->app->erp->MenuEintrag("index.php?module=ticket&action=dateien&id=$id", "Dateien".$anzahldateien); } function ticket_edit() { $id = $this->app->Secure->GetGET('id'); if (empty($id)) { return; } $this->ticket_menu($id); $this->app->Tpl->Set('ID', $id); $id = $this->app->Secure->GetGET('id'); $cmd = $this->app->Secure->GetGET('cmd'); $input = $this->GetInput(); $submit = $this->app->Secure->GetPOST('submit'); $msg = $this->app->erp->base64_url_decode($this->app->Secure->GetGET('msg')); if ($input['neue_notiz'] != '') { $input['notiz'] = $this->app->User->GetName()." ".date("d.m.Y H:i").": ".$input['neue_notiz']."\r\n".$input['notiz']; } // Always save if ($submit != '') { $this->ticket_save_to_db($id, $input); $msg = "
    Die Einstellungen wurden erfolgreich übernommen.
    "; } // Load values again from database $sql = "SELECT t.id, t.schluessel, ".$this->app->erp->FormatDateTimeShort("zeit",'zeit').", p.abkuerzung as projekt, t.bearbeiter, t.quelle, t.status, t.prio, t.adresse, t.kunde, CONCAT(w.label,' ',w.warteschlange) as warteschlange, t.mailadresse, t.betreff, t.zugewiesen, t.inbearbeitung, t.inbearbeitung_user, t.firma, t.notiz, t.bitteantworten, t.service, t.kommentar, t.privat, t.dsgvo, t.tags, t.nachrichten_anz, t.id FROM ticket t LEFT JOIN adresse a ON t.adresse = a.id LEFT JOIN projekt p on t.projekt = p.id LEFT JOIN warteschlangen w on t.warteschlange = w.label WHERE t.id=$id"; $ticket_from_db = $this->app->DB->SelectArr($sql)[0]; $ticket_from_db['betreff'] = strip_tags($ticket_from_db['betreff']); foreach ($ticket_from_db as $key => $value) { $this->app->Tpl->Set(strtoupper($key), $value); } $this->app->Tpl->Set('PRIO', $ticket_from_db['prio']==1?"checked":""); $this->app->Tpl->Set('STATUSICON', $this->ticket_status_icon($ticket_from_db['status'])." "); $this->app->YUI->AutoComplete("adresse","adresse"); $this->app->Tpl->Set('ADRESSE', $this->app->erp->ReplaceAdresse(false,$ticket_from_db['adresse'],false)); // Convert ID to form display if ($ticket_from_db['mailadresse'] != "") { $this->app->Tpl->Set('MAILADRESSE',"<".$ticket_from_db['mailadresse'].">"); } $this->app->Tpl->Set('ADRESSE_ID',$ticket_from_db['adresse']); $this->app->YUI->AutoComplete("projekt","projektname",1); $this->app->YUI->AutoComplete("status","ticketstatus",1); $this->app->YUI->TagEditor('tags', array('width'=>370)); $this->app->Tpl->Set('STATUS', $this->app->erp->GetStatusTicketSelect($ticket_from_db['status'])); $input['projekt'] = $this->app->erp->ReplaceProjekt(false,$input['projekt'],false); // Parameters: Target db?, value, from form? $this->app->YUI->AutoComplete("warteschlange","warteschlangename"); // END Header // Check for draft $drafted_messages = $this->get_messages_of_ticket($id, "zeitausgang IS NULL AND versendet = '1'",NULL); if (!empty($drafted_messages)) { // Draft from form? if ($submit != '') { $this->save_draft($drafted_messages[0]['id'],$input); // Reload $drafted_messages = $this->get_messages_of_ticket($id, "zeitausgang IS NULL AND versendet = '1'",NULL); } // Load the draft for editing $this->app->Tpl->Set('EMAIL_AN', htmlentities($drafted_messages[0]['mail'])); $this->app->Tpl->Set('EMAIL_CC', htmlentities($drafted_messages[0]['mail_cc'])); $this->app->Tpl->Set('EMAIL_BCC', htmlentities($drafted_messages[0]['mail_bcc'])); $this->app->Tpl->Set('EMAIL_BETREFF', htmlentities($drafted_messages[0]['betreff'])); $this->app->Tpl->Set('EMAIL_TEXT',htmlentities($drafted_messages[0]['text'])); // Show new message dialog $this->app->Tpl->Set('EMAIL_SENDER', $this->app->erp->GetSelectEmailMitName($dokument['von'])); $this->app->YUI->AutoComplete("email_an","emailname"); $this->app->YUI->AutoComplete("email_cc","emailname"); $this->app->YUI->AutoComplete("email_bcc","emailname"); $this->app->YUI->CkEditor("email_text","internal", null, 'JQUERY'); // Delete attachment from draft if ($cmd=='deleteattachment') { $fileid = $this->app->Secure->GetGET('fileid'); // Check if this file is only attached to this draft and nowhere else $check = $this->app->erp->GetDateiStichwoerter($fileid); $save_to_delete = true; foreach ($check as $stichwort) { if ($stichwort['subjekt'] != 'anhang' || $stichwort['objekt'] != 'Ticket' || $stichwort['parameter'] != $drafted_messages[0]['id']) { $save_to_delete = false; break; } } if ($save_to_delete) { $this->app->erp->DeleteDatei($fileid); } else { $msg .= "
    Fehler beim Löschen der Datei: In Verwendung.
    "; } } // Upload of attachments if(isset($_FILES['upload']) && is_array($_FILES['upload'])) { foreach($_FILES['upload']['tmp_name'] as $key => $file) { if($file != "") { $fileid = $this->app->erp->CreateDatei($_FILES['upload']['name'][$key], $_FILES['upload']['name'][$key], "", "", $_FILES['upload']['tmp_name'][$key], $this->app->User->GetName()); // stichwoerter hinzufuegen $this->app->erp->AddDateiStichwort($fileid, "anhang", "Ticket", $drafted_messages[0]['id']); } } } $this->add_attachments_html($id,$drafted_messages[0]['id'],'ANHAENGE',true); $this->app->Tpl->Parse('NEW_MESSAGE', "ticket_new_message.tpl"); } // END Draft // Get all messsages $messages = $this->get_messages_of_ticket($id, 1, NULL); $recv_messages = $this->get_messages_of_ticket($id,"n.versendet != 1",NULL); $an_alle = false; switch ($submit) { case 'neue_email_alle': $an_alle = true; // break omitted case 'neue_email': $senderName = $this->app->User->GetName()." (".$this->app->erp->GetFirmaAbsender().")"; $senderAddress = $this->app->erp->GetFirmaMail(); if (empty($drafted_messages)) { // Create new message and save it for editing $this->app->Tpl->Set('EMAIL_AN', htmlentities($recv_messages[0]['mail'])); $to = ""; $cc = ""; if (!empty($recv_messages)) { if (!str_starts_with(strtoupper($recv_messages[0]['betreff']),"RE:")) { $betreff = "RE: ".strip_tags($recv_messages[0]['betreff']); //+ #20230916 XSS } else { $betreff = strip_tags($recv_messages[0]['betreff']); //+ #20230916 XSS } $to = $recv_messages[0]['mail']; if ($an_alle) { $sql = "SELECT GROUP_CONCAT(DISTINCT `value` ORDER BY `value` SEPARATOR ', ') FROM ticket_header th WHERE th.ticket_nachricht = ".$recv_messages[0]['id']." AND `value` <> '".$senderAddress."' AND type='to'"; $to_additional = $this->app->DB->Select($sql); if (!empty($to_additional)) { $to .= ", ".$to_additional; } $sql = "SELECT GROUP_CONCAT(DISTINCT `value` ORDER BY `value` SEPARATOR ', ') FROM ticket_header th WHERE th.ticket_nachricht = ".$recv_messages[0]['id']." AND `value` <> '".$senderAddress."' AND type='cc'"; $cc = $this->app->DB->Select($sql); } else { $cc = null; } } else { $betreff = $ticket_from_db['betreff']; $sql = "SELECT email FROM adresse WHERE id =".$ticket_from_db['adresse']; $to = $this->app->DB->Select($sql); } $anschreiben = $this->app->DB->Select("SELECT anschreiben FROM adresse WHERE id='".$ticket_from_db['adresse']."' LIMIT 1"); if($anschreiben=="") { $anschreiben = $this->app->erp->Beschriftung("dokument_anschreiben"); } $anschreiben = $anschreiben.",
    ".$this->app->erp->Grussformel($projekt,$sprache); $sql = "INSERT INTO `ticket_nachricht` ( `ticket`, `zeit`, `text`, `betreff`, `medium`, `versendet`, `verfasser`, `mail`,`status`, `verfasser_replyto`, `mail_replyto`,`mail_cc` ) VALUES ('". $ticket_from_db['schluessel']. "',NOW(),'". $this->app->DB->real_escape_string($anschreiben). "','". $this->app->DB->real_escape_string($betreff). "','email','1','". $this->app->DB->real_escape_string($senderName). "','". $this->app->DB->real_escape_string($to). "','neu','". $this->app->DB->real_escape_string($senderName). "','". $this->app->DB->real_escape_string($senderAddress). "','". $this->app->DB->real_escape_string($cc)."');"; $this->app->DB->Insert($sql); // Show new message dialog header("Location: index.php?module=ticket&action=edit&id=$id"); $this->app->ExitXentral(); } break; case 'entwurfloeschen': if (!empty($drafted_messages)) { $sql = "UPDATE ticket_nachricht SET ticket = '' WHERE id=".$drafted_messages[0]['id']; $this->app->DB->Update($sql); $msg = $this->app->erp->base64_url_encode("
    Der Entwurf wurde gelöscht.
    "); header("Location: index.php?module=ticket&action=edit&msg=$msg&id=$id"); $this->app->ExitXentral(); } break; case 'zitat': if (!empty($drafted_messages) && !empty($recv_messages)) { $nl = "
    "; $citation_info =$recv_messages[0]['zeit']." ".$recv_messages[0]['verfasser']." <".$recv_messages[0]['mail'].">"; $text = $drafted_messages[0]['text'].$nl.$nl.$citation_info.":".$nl."
    ".$recv_messages[0]['text']."
    "; $sql = "UPDATE ticket_nachricht SET text='".$this->app->DB->real_escape_string($text)."' WHERE id=".$drafted_messages[0]['id']; $this->app->DB->Update($sql); header("Location: index.php?module=ticket&action=edit&id=$id"); $this->app->ExitXentral(); } break; case 'absenden': if (empty($drafted_messages)) { break; } $msg = ""; // Enforce Ticket # if (!preg_match("/Ticket #[0-9]{12}/i", $drafted_messages[0]['betreff'])) { $drafted_messages[0]['betreff'].= " Ticket #".$ticket_from_db['schluessel']; } // Attachments $files = $this->app->erp->GetDateiSubjektObjektDateiname('Anhang','Ticket',$drafted_messages[0]['id'],""); $pattern = '/[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.([a-z]{2,63})(?:\.[a-z]{2,63})?/i'; preg_match_all($pattern, $drafted_messages[0]['mail'], $matches); $to = $matches[0]; if ($drafted_messages[0]['mail_cc'] != '') { preg_match_all($pattern, $drafted_messages[0]['mail_cc'], $matches); $cc = $matches[0]; } else { $cc = null; } $senderName = $this->app->User->GetName()." (".$this->app->erp->GetFirmaAbsender().")"; $senderAddress = $this->app->erp->GetFirmaMail(); // function MailSend($from,$from_name,$to,$to_name,$betreff,$text,$files="",$projekt="",$signature=true,$cc="",$bcc="", $system = false) if ( $this->app->erp->MailSend( $senderAddress, $senderName, $to, $to, htmlentities($drafted_messages[0]['betreff']), htmlentities($drafted_messages[0]['text']), $files, 0, true, $cc, '', true ) != 0 ) { // Update message in ticket_nachricht $sql = "UPDATE `ticket_nachricht` SET `zeitausgang` = NOW(), `betreff` = '".$this->app->DB->real_escape_string($drafted_messages[0]['betreff'])."', `verfasser` = '$senderName', `verfasser_replyto` = '$senderName', `mail_replyto` = '$senderAddress' WHERE id = ".$drafted_messages[0]['id']; $this->app->DB->Insert($sql); $msg .= '
    Die E-Mail wurde erfolgreich versendet an '.$input['email_an'].'.'; if ($drafted_messages[0]['mail_cc'] != '') { $msg .= ' (CC: '.$drafted_messages[0]['mail_cc'].')
    '; } else { $msg .= ''; } header("Location: index.php?module=ticket&action=edit&id=".$id."&msg=".$this->app->erp->base64_url_encode($msg)); } else { $msg = '
    Fehler beim Versenden der E-Mail: '.$this->app->erp->mail_error.'
    '; } // Get messsages again $messages = $this->get_messages_of_ticket($id,1,NULL); break; } $this->add_messages_tpl($messages, false); $this->add_attachments_header_html($id,'TICKET_ANHANG'); $this->app->Tpl->Set('MESSAGE', $msg); $this->app->Tpl->Parse('PAGE', "ticket_edit.tpl"); } function ticket_dateien() { $id = $this->app->Secure->GetGET("id"); $this->ticket_menu($id); $this->app->Tpl->Add('UEBERSCHRIFT'," (Dateien)"); $this->app->YUI->DateiUpload('PAGE',"ticket_header",$id); } /** * Get all paramters from html form and save into $input */ public function GetInput(): array { $input = array(); //$input['EMAIL'] = $this->app->Secure->GetPOST('email'); $input['projekt'] = $this->app->Secure->GetPOST('projekt'); $input['status'] = $this->app->Secure->GetPOST('status'); $input['adresse'] = $this->app->Secure->GetPOST('adresse'); $input['warteschlange'] = $this->app->Secure->GetPOST('warteschlange'); $input['prio'] = !empty($this->app->Secure->GetPOST('prio'))?"1":"0"; $input['neue_notiz'] = $this->app->Secure->GetPOST('neue_notiz'); $input['notiz'] = $this->app->Secure->GetPOST('notiz'); $input['tags'] = $this->app->Secure->GetPOST('tags'); $input['betreff'] = $this->app->Secure->GetPOST('betreff'); $input['email_sender'] = $this->app->Secure->GetPOST('email_sender'); $input['email_an'] = $this->app->Secure->GetPOST('email_an'); $input['email_cc'] = $this->app->Secure->GetPOST('email_cc'); $input['email_bcc'] = $this->app->Secure->GetPOST('email_bcc'); $input['email_betreff'] = $this->app->Secure->GetPOST('email_betreff'); $input['email_text'] = $this->app->Secure->GetPOST('email_text'); return $input; } public function ticket_minidetail($parsetarget='',$menu=true) { $id = $this->app->Secure->GetGET('id'); // Get last 3 messages $messages = $this->get_messages_of_ticket($id, "1", 3); if(!empty($messages)) { $this->add_messages_tpl($messages, true); // With drafts $render = true; } else { } if($parsetarget=='') { if ($render) { $this->app->Tpl->Output('ticket_minidetail.tpl'); } $this->app->ExitXentral(); } if ($render) { $this->app->Tpl->Parse($parsetarget,'ticket_minidetail.tpl'); } } /* * After import of Xentral 20 ticket system * Set all ticket status to the status of the latest ticket_nachricht */ function ticket_statusfix() { $confirmed = $this->app->Secure->GetGET('confirmed'); if ($confirmed == "yes") { $sql = "UPDATE ticket SET STATUS =ifnull(( SELECT tn.status FROM ticket_nachricht tn INNER JOIN( SELECT ticket, MAX(zeit) AS lastzeit FROM ticket_nachricht GROUP BY ticket ) l ON tn.ticket = l.ticket AND tn.zeit = l.lastzeit WHERE ticket.schluessel = tn.ticket LIMIT 1 ),'abgeschlossen') WHERE ticket.status = 'neu'"; $this->app->DB->Update($sql); $this->app->Tpl->Set('TEXT', "Status fix abgeschlossen."); $this->app->Tpl->Parse('PAGE','ticket_text.tpl'); } else { // $this->app->Tpl->Set('TEXT', "This will replace all ticket status with the status of the latest ticket_nachricht. To confirm, press here: "); $this->app->Tpl->Set('TEXT', "Dieser Assistent ersetzt den Status aller offenen Tickets (Weder abgeschlossen noch Spam) mit dem Status der letzten Nachricht im Ticket. Hier starten: "); $this->app->Tpl->Add('TEXT', ''); $this->app->Tpl->Parse('PAGE','ticket_text.tpl'); } } /* * After import of Xentral 20 ticket system * Set all ticket dates to the date of the latest ticket_nachricht */ function ticket_datefix() { $confirmed = $this->app->Secure->GetGET('confirmed'); if ($confirmed == "yes") { $sql = "UPDATE ticket set zeit = (SELECT MAX(zeit) AS lastzeit FROM ticket_nachricht WHERE ticket.schluessel = ticket_nachricht.ticket AND ticket.schluessel LIMIT 1 ) WHERE ticket.status <> 'abgeschlossen' AND ticket.status <> 'spam'"; $this->app->DB->Update($sql); $this->app->Tpl->Set('TEXT', "Datum fix abgeschlossen."); $this->app->Tpl->Parse('PAGE','ticket_text.tpl'); } else { // $this->app->Tpl->Set('TEXT', "This will replace all open ticket dates with the date of the latest ticket_nachricht. To confirm, press here: "); $this->app->Tpl->Set('TEXT', "Dieser Assistent ersetzt das Datum aller offenen Tickets (Weder abgeschlossen noch Spam) mit dem Datum der letzten Nachricht im Ticket. Hier starten: "); $this->app->Tpl->Add('TEXT', ''); $this->app->Tpl->Parse('PAGE','ticket_text.tpl'); } } }