1<?php
2/**
3*  IssueTracker Plugin: allows to create simple issue tracker
4*
5* initial code from DokuMicroBugTracker Plugin: allows to create simple bugtracker
6*
7* @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
8* @author     Taggic <taggic@t-online.de>
9*
10*
11*
12*/
13//session_start();
14if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
15if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
16require_once(DOKU_PLUGIN.'syntax.php');
17require_once(DOKU_PLUGIN.'issuetracker/assilist.php');
18/******************************************************************************
19* All DokuWiki plugins to extend the parser/rendering mechanism
20* need to inherit from this class
21*/
22class syntax_plugin_issuetracker extends DokuWiki_Syntax_Plugin
23{
24/******************************************************************************/
25/* return some info
26*/
27    function getInfo(){
28        return confToHash(dirname(__FILE__).'/plugin.info.txt');
29    }
30
31    function getType(){ return 'substition';}
32    function getPType(){ return 'block';}
33    function getSort(){ return 167;}
34
35/******************************************************************************/
36/* Connect pattern to lexer
37*/
38    function connectTo($mode){
39        $this->Lexer->addSpecialPattern('\{\{issuetracker>[^}]*\}\}',$mode,'plugin_issuetracker');
40    }
41
42/******************************************************************************/
43/* Handle the match
44*/
45    function handle($match, $state, $pos,Doku_Handler &$handler){
46        $match = substr($match,15,-2); //strip markup from start and end
47        //handle params
48        $data = array();
49        $params = explode('|',$match);
50
51        foreach($params as $param) {
52            $splitparam = explode('=',$param);
53            if ($splitparam[1] != '')
54            {
55                if ($splitparam[0]=='project')    { $data['project']   = trim(strtolower($splitparam[1])) ;}
56                if ($splitparam[0]=='product')    { $data['product']    = trim(strtoupper($splitparam[1])) ;}
57                if ($splitparam[0]=='status')     { $data['status']     = trim(strtoupper($splitparam[1])) ;}
58                if ($splitparam[0]=='severity')   { $data['severity']   = trim(strtoupper($splitparam[1])) ;}
59                if ($splitparam[0]=='display')    { $data['display']    = trim(strtoupper($splitparam[1])) ;}
60                if ($splitparam[0]=='view')       { $data['view']       = trim(strtoupper($splitparam[1])) ;}
61                if ($splitparam[0]=='controls')   { $data['controls']   = trim(strtoupper($splitparam[1])) ;}
62                if ($splitparam[0]=='prod_limit') { $data['prod_limit'] = trim(strtoupper($splitparam[1])) ;}
63                if ($splitparam[0]=='id')         { $data['id']         = trim(strtoupper($splitparam[1])) ;}
64                if ($splitparam[0]=='version')    { $data['version']    = trim(strtoupper($splitparam[1])) ;}
65                if ($splitparam[0]=='component')  { $data['component']  = trim(strtoupper($splitparam[1])) ;}
66                if ($splitparam[0]=='tblock')     { $data['tblock']     = trim(strtoupper($splitparam[1])) ;}
67                if ($splitparam[0]=='assignee')   { $data['assignee']   = trim(strtoupper($splitparam[1])) ;}
68                if ($splitparam[0]=='reporter')   { $data['reporter']   = trim(strtoupper($splitparam[1])) ;}
69                if ($splitparam[0]=='myissues')   { $data['myissues']   = trim(strtoupper($splitparam[1])) ;}
70                if ($splitparam[0]=='config')     { $data['config']     = trim(strtoupper($splitparam[1])) ;}
71                if ($splitparam[0]=='sort')       { $data['sort']       = trim(strtoupper($splitparam[1])) ;}
72                if ($splitparam[0]=='columns')    { $data['columns']    = trim(strtoupper($splitparam[1])) ;}
73                if ($splitparam[0]=='asympupl')   { $data['asympupl']    = trim(strtoupper($splitparam[1])) ;}
74                if ($splitparam[0]=='email_address') {$data['email_address'] = trim(strtolower($splitparam[1])) ;}
75                   /*continue;*/
76            }
77        }
78
79        return $data;
80    }
81
82/******************************************************************************/
83/* Captcha OK
84*/
85		function _captcha_ok()
86		{
87			$helper = null;
88
89			if(@is_dir(DOKU_PLUGIN.'captcha'))
90      { $helper = plugin_load('helper','captcha'); }
91
92			if(!is_null($helper) && $helper->isEnabled())
93			{	return $helper->check(); }
94
95			return ($this->getConf('use_captcha'));
96		}
97
98/******************************************************************************/
99/* Create output
100*/
101    function render($mode,Doku_Renderer &$renderer, $data) {
102        global $ID;
103        $project = htmlspecialchars(stripslashes($_REQUEST['project']));
104        if(strlen($project) <1) $project = $data['project'];
105        else $data['project'] = $project;
106
107        if ($mode == 'xhtml'){
108
109              $renderer->info['cache'] = false;
110
111              $Generated_Header  = '';
112              $Generated_Table   = '';
113              $Generated_Scripts = '';
114              $Generated_Report  = '';
115
116              if ($data['display']    == '') {$data['display']    = 'ISSUES';}
117              if ($data['view']       == '') {$data['view']       = '10';}
118              if ($data['controls']   == '') {$data['controls']   = 'ON';}
119              if ($data['prod_limit'] == '') {$data['prod_limit'] = 'OFF';}
120              if ($data['id']         == '') {$data['id'] = '0';}
121              if ($data['severity']   == '') {$data['severity']   = 'ALL';}
122              if ($data['status']     == '') {$data['status']     = 'ALL';}
123              if ($data['product']    == '') {$data['product']    = 'ALL';}
124              if ($data['version']    == '') {$data['version']    = 'ALL';}
125              if ($data['component']  == '') {$data['component']  = 'ALL';}
126              if ($data['tblock']     == '') {$data['tblock']     = false;}
127              else { $data['tblock']  = true; }
128              if ($data['assignee']   == '') {$data['assignee']   = 'ALL';}
129              if ($data['reporter']   == '') {$data['reporter']   = 'ALL';}
130          	  if ($data['myissues']   == '') {$data['myissues']   = false;}
131              else { $data['myissues']= true; }
132              if ($data['config']     == '') {$data['config']     = false;}
133              else { $data['config']  = true; }
134              if($data['asympupl']    == '') {$data['asympupl']=false;}
135              else{$data['asympupl']=true;}
136
137              if ($this->validEmail($data['email_address'])===false ) {
138                  if($data['email_address']!='') { msg("invalid mail given by syntax",-1);}
139                  $data['email_address'] = $this->getConf('email_address');
140              }
141
142            if (stristr($data['display'],'FORM')!= false)
143            {
144                //If it is a user report add it to the db-file
145                if (isset($_REQUEST['severity']))
146                {
147                    if ($_REQUEST['severity'])
148                      {
149                          // check if captcha is to be used by issue tracker in general
150                          if ($this->getConf('use_captcha') === 0) { $captcha_ok = 1;}
151                          else { $captcha_ok = ($this->_captcha_ok());}
152
153                          if ($captcha_ok)
154                            {
155                                if (checkSecurityToken())
156                                {   // get issues file contents
157                                    $all = false;
158                                    $issues = $this->_get_issues($data, $all);
159
160                                    //Add it to the issue file
161                                    $issue_id=count($issues);
162                                    foreach ($issues as $value)
163                                        {if ($value['id'] >= $issue_id) {$issue_id=$value['id'] + 1;}}
164
165                                    $issues[$issue_id]['id'] = $issue_id;
166                                    $issues[$issue_id]['product'] = htmlspecialchars(stripslashes($_REQUEST['product']));
167                                    $issues[$issue_id]['version'] = htmlspecialchars(stripslashes($_REQUEST['version']));
168                                    $issues[$issue_id]['component'] = htmlspecialchars(stripslashes($_REQUEST['component']));
169                                    $issues[$issue_id]['tblock'] = htmlspecialchars(stripslashes($_REQUEST['tblock']));
170                                    $issues[$issue_id]['severity'] = htmlspecialchars(stripslashes($_REQUEST['severity']));
171                                    $issues[$issue_id]['created'] = htmlspecialchars(stripslashes($_REQUEST['created']));
172                                    $status = explode(',', $this->getConf('status')) ;
173                                    $issues[$issue_id]['status'] = $status[0];
174                                    $issues[$issue_id]['user_name'] = htmlspecialchars(stripslashes($_REQUEST['user_name']));
175                                    $issues[$issue_id]['user_mail'] = trim(htmlspecialchars(stripslashes($_REQUEST['user_mail'])));
176                                    $issues[$issue_id]['user_phone'] = htmlspecialchars(stripslashes($_REQUEST['user_phone']));
177                                    $issues[$issue_id]['add_user_mail'] = htmlspecialchars(stripslashes($_REQUEST['add_user_mail']));
178//                                    $issues[$issue_id]['title'] = htmlspecialchars(stripslashes($_REQUEST['title']));
179                                    $issues[$issue_id]['title'] = htmlspecialchars($_REQUEST['title']);
180//                                    $issues[$issue_id]['description'] = htmlspecialchars(stripslashes($_REQUEST['description']));
181                                    $issues[$issue_id]['description'] = htmlspecialchars($_REQUEST['description']);
182                                    $issues[$issue_id]['attachment1'] = htmlspecialchars(stripslashes($_REQUEST['attachment1']));
183                                    $issues[$issue_id]['attachment2'] = htmlspecialchars(stripslashes($_REQUEST['attachment2']));
184                                    $issues[$issue_id]['attachment3'] = htmlspecialchars(stripslashes($_REQUEST['attachment3']));
185                                    $issues[$issue_id]['assigned'] = '';
186                                    $issues[$issue_id]['resolution'] = '';
187                                    $issues[$issue_id]['comments'] = '';
188                                    $issues[$issue_id]['modified'] = htmlspecialchars(stripslashes($_REQUEST['modified']));
189
190                                    $xuser = $issues[$issue_id]['user_mail'];
191                                    $xdescription = $issues[$issue_id]['description'];
192
193//echo "Beschreibung: ".$xdescription."<br />";
194
195// *****************************************************************************
196// upload a symptom file
197// *****************************************************************************
198                                    // check if current user is admin/assignee
199                                    // check if syntax parameter asympupl is switched on
200                                    $user_grp    = pageinfo();
201                                    if(array_key_exists('userinfo', $user_grp))
202                                    {   foreach ($user_grp['userinfo']['grps'] as $ugrp)
203                                        {  $user_grps = $user_grps . $ugrp;  }
204                                    }
205                                    else
206                                    {   $user_grps = 'all';  }
207                                    $allowed_users = explode('|', $this->getConf('assign'));
208                                    $cFlag = false;
209                                    foreach ($allowed_users as $w)
210                                    {   // check if one of the assigned user roles does match with current user roles
211                                        if (strpos($user_grps,$w)!== false)
212                                        {   $cFlag = true;
213                                            break;  }
214                                    }
215
216                                    $mime_type1 = $_FILES['attachment1']['type'];
217                                    if((($this->getConf('upload')> 0) ||(($cFlag === true) && ($data['asympupl']=true)) || ($this->getConf('registered_users')== 0)) && (strlen($mime_type1)>1)) {
218                                      $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment1');
219                                    }
220                                    $mime_type2 = $_FILES['attachment2']['type'];
221                                    if(($this->getConf('upload')> 0) && (strlen($mime_type2)>1)) {
222                                      $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment2');
223                                    }
224                                    $mime_type3 = $_FILES['attachment3']['type'];
225                                    if(($this->getConf('upload')> 0) && (strlen($mime_type3)>1)) {
226                                      $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment3');
227                                    }
228
229                                    //check user mail address, necessary for further clarification of the issue
230                                    $valid_umail = $this->validEmail($xuser);
231                                    if ( ($valid_umail == true) && ((stripos($xdescription, " ") > 0) || (strlen($xdescription)>5)) && (strlen($issues[$issue_id]['version']) >0))
232                                    {
233                                          // assemble the path to IssueTracker data store & file
234                                          if($this->getConf('it_data')==false) $pfile = DOKU_CONF."../data/meta/".$data['project'].'.issues';
235                                          else $pfile = DOKU_CONF."../". $this->getConf('it_data').$data['project'].'.issues';
236
237                                          //save issue-file
238                                          $xvalue = io_saveFile($pfile,serialize($issues));
239                                          $this->_log_mods($data['project'], $issues[$issue_id], $issues[$issue_id]['user_name'], 'status', '', $issues[$issue_id]['status']);
240
241                                          $pstring = sprintf("showid=%s&project=%s", urlencode($issues[$issue_id]['id']), urlencode($project));
242                                          $tmp_link = '<a href="'.DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" >'.$issue_id.'</a>';
243
244                                          $Generated_Header .= '<div class="it__positive_feedback">'.$this->getLang('msg_reporttrue').$tmp_link.'</div>';
245                                          $this->_emailForNewIssue($data['project'],$issues[$issue_id],$data['email_address']);
246                                          $_REQUEST['description'] = '';
247                                    }
248
249                                    else
250                                    {
251                                        $wmsg ='';
252                                        if ($valid_umail == false)
253                                            { $wmsg = $this->getLang('wmsg1'); }
254                                        elseif (strlen($issues[$issue_id]['version']) <1)
255                                            { $wmsg = $this->getLang('wmsg2'); }
256                                        else
257                                            { $wmsg = $this->getLang('wmsg3').' ('.stripos($xdescription, " ").', '.strlen($xdescription).')'; }
258
259                                        $Generated_Header .= '<div class="it__negative_feedback">'.$wmsg.'</div>';
260                                    }
261                                }
262                          else
263                                {
264                                $Generated_Header .= ':<div class="it__negative_feedback">'.$this->getLang('msg_captchawrong').'</div>';
265                                }
266                          }
267                    }
268                }
269                else
270                {$Generated_Report = $this->_report_render($data);}
271            }
272
273            // Create issue list
274            elseif (stristr($data['display'],'ISSUES')!= false)
275            {   // get issues file contents
276                $all = true;
277                $issues = $this->_get_issues($data, $all);
278
279                // global sort of issues array
280                if($data['sort']='') $data['sort']='id';
281                $sort_key = $data['sort'];
282                $issues = $this->_issues_globalsort($issues, $sort_key);
283                $step = $data['view'];
284                $Generated_Table = $this->_table_render($data['project'],$issues,$data,$step,$start);
285                if (strtolower($data['controls'])==='on') {
286                    $Generated_Scripts = $this->_scripts_render($project);
287                }
288            }
289            // Count only ...
290            elseif (stristr($data['display'],'COUNT')!= false)
291            {   // get issues file contents
292                $all = true;
293                $issues = $this->_get_issues($data, $all);
294                $a_result = $this->_count_render($issues,$start,$step,$next_start,$data,$project);
295                $Generated_Table =$a_result[1];
296                $count = $a_result[0];
297            }
298            // syntax to display a single issue inside wiki text
299            elseif (stristr($data['display'],'single_issue')!= false)
300            {   // retrieve issue details
301                $all      = false;
302                $issues   = $this->_get_issues($data, $all);
303                $issue_id = $data['id'];
304                if($issues[$issue_id]['status'] == $this->getLang('issue_resolved_status')) { $a_style="<del>"; $e_style="</del>";}
305                // define output
306                $Generated_Table  = $a_style."<a href='".DOKU_URL.'doku.php?id='.$ID."&do=showcaselink&showid=".$issue_id."&project=".$data['project']."' title='".$issues[$issue_id]['status']."'>".NL;
307                $Generated_Table .= "<span>#".$issue_id.":</span>&nbsp;";
308                $Generated_Table .= "<span>".$issues[$issue_id]['title']."</span>&nbsp;";
309                $Generated_Table .= "<span>(".$issues[$issue_id]['status'].")</span>";
310                $Generated_Table .= "</a>".$e_style;
311
312                $Generated_Header  = "";
313                $Generated_Scripts = "";
314                $Generated_Report  = "";
315            }
316// *****************************************************************************
317// Show configuration
318// *****************************************************************************
319            elseif (stristr($data['display'],'config')!= false)
320            {   /* 1. load the defined elements per type
321                   - the related config file (it_matrix.cfg) is stored to the plugin folder
322                   - the matrix structure is as follows
323                     elmnt_type | elmnt_name | rel_childs
324                   - type project has childs of type product
325                   - type product has at least one relative parent or is just newly created
326                */
327/*                $cfg_file = DOKU_PLUGIN."issuetracker/conf/it_matrix.cfg";
328                $it_cfg = array();
329                if (@file_exists($cfg_file)) { $it_cfg  = unserialize(@file_get_contents($cfg_file)); }
330                echo "<pre style='font:italic 11px/15px Arial, serif;'>".print_r($it_cfg, true)."</pre>";
331
332                // 2. replace the placeholder with config values
333                  // a) loop through the matrix and collect all defined projects
334                  //    initially we start with projects
335                  //    string to be built according: <option value="strtolower($name)" >$name</option>
336                  $itm_counter = 0;
337                  $itm_counter2 = 0;
338                  foreach($it_cfg as $item) {
339                    if ($item['elmnt_type']=="project") {
340                      $itm_counter++;
341                      if($itm_counter===1){
342                        $name2  .= '<option value="'.$item['elmnt_name'].'" selected="selected">'.$item['elmnt_name'].'</option>'.NL;
343                        $sel_prod = $item['elmnt_name'];
344                      }
345                      else {
346                        $name2  .= '<option value="'.$item['elmnt_name'].'" >'.$item['elmnt_name'].'</option>'.NL;
347                      }
348                    }
349
350                    // list all potential childs and check the already related items
351                    elseif ($item['elmnt_type']=="product") {
352                      $itm_counter2++;
353                      if (stripos($item['rel_childs'],$sel_prod)!== false) {
354                        $cfgelements .= '<input id="childs_'.$itm_counter2.'" name="childs_'.$itm_counter2.'" class="element checkbox" type="checkbox" checked />
355                                       <label class="choice" for="childs_'.$itm_counter2.'">'.$item['elmnt_name'].'</label> <br />'.NL;
356                      }
357                      else {
358                        $cfgelements .= '<input id="childs_'.$itm_counter2.'" name="childs_'.$itm_counter2.'" class="element checkbox" type="checkbox" />
359                                       <label class="choice" for="childs_'.$itm_counter2.'">'.$item['elmnt_name'].'</label> <br />'.NL;
360                      }
361                    }
362                  }
363
364                  $type1 = '<option value="project" selected="selected">Project</option>
365                            <option value="product" >Product</option>
366                            <option value="component" >Component</option>'.NL;
367*/
368/*                  $name2  = ' <option value="" selected="selected"></option>
369                              <option value="1" >First element</option>
370                              <option value="2" >Second element</option>
371                              <option value="3" >Third element</option>'.NL;
372
373                  $cfgelements = '<input id="element_6_1" name="element_6_1" class="element checkbox" type="checkbox" value="1" />
374                                 <label class="choice" for="element_6_1">First option</label> <br />
375                                  <input id="element_6_2" name="element_6_2" class="element checkbox" type="checkbox" value="1" />
376                                  <label class="choice" for="element_6_2">Second option</label> <br />
377                                  <input id="element_6_3" name="element_6_3" class="element checkbox" type="checkbox" value="1" />
378                                  <label class="choice" for="element_6_3">Third option</label>  <br />'.NL;
379*/
380/*                // 3. load html-skeleton
381                  $html_skeleton = DOKU_PLUGIN."issuetracker/cfg_skeleton.html";
382                  if (@file_exists($html_skeleton)) { $Generated_config  = @file_get_contents($html_skeleton); }
383                  else { msg("The file 'cfg_skeleton.html' was not found at plugin directory.",-1); return;}
384
385                // 4. replace placeholders at html-skeleton
386                  $Generated_config = str_ireplace("%%ID%%",$ID,$Generated_config);
387                  $Generated_config = str_ireplace("%%type1%%",$type1,$Generated_config);
388                  $Generated_config = str_ireplace("%%name2%%",$name2,$Generated_config);
389                  $Generated_config = str_ireplace("%%cfgelements%%",$cfgelements,$Generated_config);
390
391                // 5. load the script to assemble the element childs for submit to action.php
392                  $it_script = DOKU_PLUGIN."issuetracker/it_matrix.script";
393                  if (@file_exists($it_script)) { $it_cfg_script  = @file_get_contents($it_script); }
394                  else { msg("The file 'it_matrix.script' was not found at plugin directory.",-1); }
395                  $Generated_config = $it_cfg_script .NL. $Generated_config;
396
397*/            }
398
399            // Render
400            $renderer->doc .= $Generated_Header.$Generated_Table.$Generated_Scripts.$Generated_Report.$Generated_config;
401
402        }
403    }
404
405/******************************************************************************/
406/* Create count output
407*/
408    function _count_render($issues,$start,$step,$next_start,$data, $project)
409    {   global $ID;
410        $count = array();
411        $productfilter=$data['product'];
412
413        foreach ($issues as $issue)
414        {
415            if(($issue['project'] !== $project) && ($this->getConf('multi_projects')==0)) {
416              continue;
417            }
418            elseif((strcasecmp($productfilter,'ALL')===0) || (stristr($productfilter,$this->_get_one_value($issue,'product'))!= false))
419            {   $status = trim($this->_get_one_value($issue,'status'));
420                $a_count = $a_count + 1;
421                if (($status != '') && (stripos($this->getConf('status_special'),$status)===false))
422                {    if ($this->_get_one_value($count,strtoupper($status))=='')
423                        {$count[strtoupper($status)] = array(1,$status);}
424                    else
425                        {$count[strtoupper($status)][0] += 1;}
426                }
427            }
428        }
429        $rendered_count = '<div class="itl__count_div">'.'<table class="itl__count_tbl">';
430        foreach ($count as $value)
431        {
432            //http://www.fristercons.de/fcon/doku.php?id=issuetracker:issuelist&do=showcaselink&showid=19&project=fcon_project
433            // $ID.'&do=issuelist_filter&itl_sev_filter='.$value[1]
434            $rendered_count .= '<tr><td><a href="'.DOKU_URL.'doku.php?id='.$ID.'&do=issuelist_filterlink'.'&itl_start='.$start.'&itl_step='.$step.'&itl_next='.$next_start.'&itl_stat_filter='.$value[1].'&itl_sev_filter='.$data['severity'].'&itl__prod_filter='.$data['product'].'&itl_project='.$data['project'].'" >'.$value[1].'</a>&nbsp;</td><td>&nbsp;'.$value[0].'</td></tr>';
435        }
436        $rendered_count .= '</table></div>';
437        $ret_array = array($a_count,$rendered_count);
438        return $ret_array;
439    }
440
441/******************************************************************************/
442/* Create table scripts
443*/
444    function _scripts_render($project)
445    {
446        // load status values from config into select control
447        $s_counter = 0;
448        $status = explode(',', $this->getConf('status')) ;
449        foreach ($status as $x_status)
450        {
451            $s_counter = $s_counter + 1;
452            $x_status = trim($x_status);
453            $STR_STATUS = $STR_STATUS . "case '".$x_status."':  val = ".$s_counter."; break;";
454            $pattern = $pattern . "|" .  $x_status;
455            $x_status_select = $x_status_select . "['".$x_status."','".$x_status."'],";
456        }
457
458        // Build string to load products select
459        $products = explode(',', $this->getConf('products')) ;
460        foreach ($products as $x_products)
461        {
462            $x_products = trim($x_products);
463            $x_products_select = $x_products_select . "['".$x_products."','".$x_products."'],";
464        }
465
466        // Build string to load severity select
467        $severity = explode(',', $this->getConf('severity')) ;
468        foreach ($severity as $x_severity)
469        {
470            $x_severity = trim($x_severity);
471            $x_severity_select = $x_severity_select . "['".$x_severity."','".$x_severity."'],";
472        }
473
474        // see issue 37: AUTH:AD switch to provide text input instead
475        // select with retriveing all_users from AD
476        // search also action.php for 'auth_ad_overflow'
477        if($this->getConf('auth_ad_overflow') == false) {
478            global $auth;
479            global $conf;
480            $filter['grps']  = $this->getConf('assign');
481            $target          = $auth->retrieveUsers(0,0,$filter);
482            $shw_assignee_as = trim($this->getConf('shw_assignee_as'));
483            if(stripos("login, mail, name",$shw_assignee_as) === false) $shw_assignee_as = "login";
484//--------------------------------------------------------------------------------------------
485// Build 'assign to' list from a simple textfile
486        	  // 1. check if file exist else use configuration
487        	  if($this->getConf('assgnee_list')==="") {
488                foreach ($target as $key => $x_umail)
489                {       // show assignee by login, name, mail
490                        if($shw_assignee_as=='login') $x_umail_select = $x_umail_select . "['".$key."','".$x_umail['mail']."'],";
491                        else $x_umail_select = $x_umail_select . "['".$x_umail[$shw_assignee_as]."','".$x_umail['mail']."'],";
492                }
493            }
494            else{
495                $fileextension = $this->getConf('assgnee_list');
496                $x_umail_select = __get_assignees_from_files($fileextension);
497              }
498//--------------------------------------------------------------------------------------------
499
500            $x_umail_select .= "['',''],";
501            $authAD_selector = "TableKit.Editable.selectInput('assigned',{}, [".$x_umail_select."]);";
502        }
503        //hack if DOKU_BASE is not properly set
504        if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $BASE = DOKU_URL."lib/plugins/issuetracker/";
505        else $BASE = DOKU_BASE."lib/plugins/issuetracker/";
506
507        return    "<script type=\"text/javascript\" src=\"".$BASE."prototype.js\"></script><script type=\"text/javascript\" src=\"".$BASE."fabtabulous.js\"></script>
508        <script type=\"text/javascript\" src=\"".$BASE."tablekit.js\"></script>
509        <script type=\"text/javascript\">
510            TableKit.options.editAjaxURI = '".$BASE."edit.php';
511            TableKit.Editable.selectInput('status',{}, [".$x_status_select."]);
512            TableKit.Editable.selectInput('product',{}, [".$x_products_select."]);
513            TableKit.Editable.selectInput('severity',{}, [".$x_severity_select."]);
514            ".$authAD_selector."
515            TableKit.Editable.multiLineInput('description');
516            TableKit.Editable.multiLineInput('resolution');
517            var _tabs = new Fabtabs('tabs');
518            $$('a.next-tab').each(function(a) {
519                Event.observe(a, 'click', function(e){
520                    Event.stop(e);
521                    var t = $(this.href.match(/#(\w.+)/)[1]+'-tab');
522                    _tabs.show(t);
523                    _tabs.menu.without(t).each(_tabs.hide.bind(_tabs));
524                }.bindAsEventListener(a));
525            });
526        </script>";
527    }
528
529/******************************************************************************/
530/* Create list of Issues
531*/
532    function _table_render($project,$issues,$data,$step,$start)
533    {
534        global $ID;
535        global $lang;
536        if ($step==0) $step=10;
537        if ($start==0) $start=count($issues)-$step+1;
538        $next_start  = $start + $step + 1;
539        if ($next_start>count($issues)) $next_start=count($issues);
540
541        $imgBASE     = DOKU_BASE."lib/plugins/issuetracker/images/";
542        $style       =' style="text-align:center; white-space:pre-wrap;">';
543//        $date_style =' style="text-align:center; white-space:pre;">';
544        $user_grp    = pageinfo();
545        $noStatIMG   = $this->getConf('noStatIMG');
546        $noSevIMG    = $this->getConf('noSevIMG');
547        $a_project     = $data['project'];
548
549        if(array_key_exists('userinfo', $user_grp))
550        {   foreach ($user_grp['userinfo']['grps'] as $ugrp)
551            {  $user_grps = $user_grps . $ugrp;  }
552        }
553        else
554        {   $user_grps = 'all';  }
555
556        if (strtolower($data['controls'])==='on') {
557        $ret = '<br /><br /><form class="issuetracker__form2" method="post" action="'.$_SERVER['REQUEST_URI'].'" accept-charset="'.$lang['encoding'].'"><p>';
558        $ret .= formSecurityToken(false).'<input type="hidden" name="do" value="show" />';
559        }
560        // the user maybe member of different user groups
561        // check if one of its assigned groups match with configuration
562        $allowed_users = explode('|', $this->getConf('assign'));
563        $cFlag = false;
564        foreach ($allowed_users as $w)
565        {   // check if one of the assigned user roles does match with current user roles
566            if (strpos($user_grps,$w)!== false)
567            {   $cFlag = true;
568                break;  }
569        }
570
571        // members of defined groups $user_grps allowed to change issue contents
572        if (($cFlag === true) || ($this->getConf('registered_users')== 0))
573        {   $dynatable_id = "t_".uniqid((double)microtime()*1000000,1);
574            if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0))
575                { $th_project = "<th id='project'>".$this->getLang('th_project')."</th>"; }
576
577            $head = "<div class='itl__table'><table id='".$dynatable_id."' class='sortable editable resizable inline' width='100%'>".NL.
578                    "<thead><tr>".NL.
579                     $th_project.NL.
580                    "<th class='".$this->getConf('listview_sort')."' id='id'>".$this->getLang('th_id')."</th>".NL.
581                    "<th id='created'>"   .$this->getLang('th_created')   ."</th>".NL.
582                    "<th id='product'>"   .$this->getLang('th_product')   ."</th>".NL.
583                    "<th id='version'>"   .$this->getLang('th_version')   ."</th>".NL.
584                    "<th id='severity'>"  .$this->getLang('th_severity')  ."</th>".NL.
585                    "<th id='status'>"    .$this->getLang('th_status')    ."</th>".NL.
586                    "<th id='user_name'>" .$this->getLang('th_user_name')  ."</th>".NL.
587                    "<th id='title'>"     .$this->getLang('th_title')     ."</th>".NL.
588                    "<th id='assigned'>"  .$this->getLang('th_assigned')  ."</th>".NL.
589                    "<th id='resolution'>".$this->getLang('th_resolution')."</th>".NL.
590                    "<th id='modified'>"  .$this->getLang('th_modified')  ."</th>".NL.
591                    "</tr></thead>".NL;
592            $body = '<tbody>'.NL;
593
594            // Note: The checked attribute is a boolean attribute.
595            if($data['myissues'] == '') { $data['myissues']= false; }
596            else { $data['myissues']= true; }
597
598            for ($i=$next_start-1;$i>=0;$i=$i-1)
599            {   // check start and end of rows to be displayed
600                if($i>count($issues)) break;  // prevent the php-warning
601                $issue = $issues[$i];
602
603                $a_status     = strtolower($this->_get_one_value($issue,'status'));
604                $a_severity   = strtolower($this->_get_one_value($issue,'severity'));
605                $a_product    = strtoupper($this->_get_one_value($issue,'product'));
606                $a_version    = strtoupper($this->_get_one_value($issue,'version'));
607                $a_component  = strtoupper($this->_get_one_value($issue,'component'));
608                $a_tblock     = strtoupper($this->_get_one_value($issue,'tblock'));
609                $a_assignee   = strtoupper($this->_get_one_value($issue,'assignee'));
610                $a_reporter   = strtoupper($this->_get_one_value($issue,'user_name'));
611
612                if ((($data['status']    =='ALL') || (stristr($data['status'],$a_status)          != false)) &&
613                    (($data['severity']  =='ALL') || (stristr($data['severity'],$a_severity)      != false)) &&
614                    (($data['product']   =='ALL') || (stristr($data['product'],$a_product)        != false)) &&
615                    (($data['version']   =='ALL') || (stristr($data['version'],$a_version)        != false)) &&
616                    (($data['component'] =='ALL') || (stristr($data['component'],$a_component)    != false)) &&
617                    (($data['assignee']  =='ALL') || (stristr($data['assignee'],$a_assignee)      != false)) &&
618                    (($data['reporter']  =='ALL') || (stristr($data['reporter'],$a_reporter)      != false)) &&
619                    (($data['myissues']  == false  ) || ($this->_find_myissues($issue, $user_grp) == true)))
620                {
621                    if ($y>=$step) break;
622                    if (stripos($this->getConf('status_special'),$a_status) !== false) continue;
623                    $y=$y+1;
624                    // check if status image or text to be displayed
625                    if ($noStatIMG == false) {
626                        $status_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($a_status))).'.gif';
627//                                if(!file_exists(str_replace("//", "/", DOKU_INC.$status_img)))  { $status_img = $imgBASE . 'status.gif' ;}
628                        $status_img ='  class="it_center"><span style="display : none;">'.$a_status.'</span><img border="0" alt="'.$a_status.'" title="'.$a_status.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$status_img.'" width="16" height="16"/>'.NL;
629                    }
630                    else { $status_img = $style.$a_status; }
631                    // check if severity image or text to be displayed
632                    if ($noSevIMG == false) {
633                        $severity_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($a_severity))).'.gif';
634//                                if(!file_exists(str_replace("//", "/", DOKU_INC.$severity_img)))  { $severity_img = $imgBASE . 'status.gif' ;}
635                        $severity_img ='  class="it_center"><span style="display : none;">'.$a_severity.'</span><img border="0" alt="'.$a_severity.'" title="'.$a_severity.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$severity_img.'" width="16" height="16"/>'.NL;
636                    }
637                    else { $severity_img = $style.$a_severity; }
638
639
640                    $it_issue_username = $this->_get_one_value($issue,'user_name');
641                    $a_project = $this->_get_one_value($issue,'project');
642                    if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0))
643                    {   $td_project = '<td class="itl__td_standard">'.$a_project.'</td>';
644                    }
645
646                    // build parameter for $_GET method
647                        $pstring = sprintf("showid=%s&amp;project=%s", urlencode($this->_get_one_value($issue,'id')), urlencode($a_project));
648                        $itl_item_title = '<a href="doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" title="'.$this->_get_one_value($issue,'title').'">'.$this->_get_one_value($issue,'title').'</a>'.NL;
649
650
651                    if((($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) || $project == $a_project  )
652                    { if($rowEven==="it_roweven") $rowEven="it_rowodd";
653                      else $rowEven="it_roweven";
654                      $body .= '<tr id = "'.$a_project.' '.$this->_get_one_value($issue,'id').'" class="'.$rowEven.'" >'.NL.
655                              $td_project.NL.
656                             '<td class="itl__td_standard">'.$this->_get_one_value($issue,'id').'</td>'.NL.
657                             '<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'created'))).'</td>'.NL.
658                             '<td class="itl__td_standard">'.$this->_get_one_value($issue,'product').'</td>'.NL.
659                             '<td class="itl__td_standard">'.$this->_get_one_value($issue,'version').'</td>'.NL.
660                             '<td'.$severity_img.'</td>'.NL.
661                             '<td'.$status_img.'</td>'.NL.
662                             '<td class="canbreak itl__td_standard"><a href="mailto:'.$this->_get_one_value($issue,'user_mail').'">'.$it_issue_username.'</a></td>'.NL.
663                             '<td class="canbreak itl__td_standard">'.$itl_item_title.'</td>'.NL;
664
665                    // check how the assignee to be displayed: login, name or mail
666                    $a_display = $this->_get_assignee($issue,'assigned');
667                    $body .= '<td class="canbreak itl__td_standard"><a href="mailto:'.$this->_get_one_value($issue,'assigned').'">'.$a_display.'</a></td>'.NL.
668                             '<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'resolution')).'</td>'.NL.
669                             '<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'modified'))).'</td>'.NL.
670                             '</tr>'.NL;
671                    }
672                }
673            }
674            $body .= '</tbody></table></div>'.NL;
675        }
676
677        else
678        {   //$head = "<div class='issuetracker_div' ".$hdr_style."><table id='".$project."' class=\"sortable resizable inline\"><thead><thead><tr><th class=\"sortfirstdesc\" id='id'>Id</th><th id='Status'>Status</th><th id='Severity'>Severity</th><th id='Created'>Created</th><th id='Version'>Version</th><th id='User'>User</th><th id='Description'>Description</th><th id='assigned'>assigned</th><th id='Resolution'>Resolution</th><th id='Modified'>Modified</th></tr></thead>";
679            $dynatable_id = "t_".uniqid((double)microtime()*1000000,1);
680            //Build table header according settings or syntax
681            if(strlen($data['columns'])>0) {
682              $configs = explode(',', strtolower($data['columns']));
683            }
684            else {
685              $configs = explode(',', $this->getConf('shwtbl_usr')) ;
686            }
687
688
689            if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0))
690            { $th_project = "<th id='project'>".$this->getLang('th_project')."</th>"; }
691
692            $reduced_header ='';
693            $reduced_header = "<div class='itl__table'><table id='".$dynatable_id."' class='sortable resizable inline' width='100%'>".NL.
694                    "<thead><tr>".NL.$th_project.NL."<th class='".$this->getConf('listview_sort')."' id='id'>".$this->getLang('th_id')."</th>".NL;
695
696            foreach ($configs as $config)
697            {
698                $reduced_header .= "<th id='".$config."'>".$this->getLang('th_'.$config)."</th>".NL;
699            }
700
701            $reduced_header .= "</tr></thead>".NL;
702
703            //Build rows according settings
704            $reduced_issues='';
705            for ($i=$next_start-1;$i>=0;$i=$i-1)
706            {   // check start and end of rows to be displayed
707                if($i>count($issues)) break;  // prevent the php-warning
708                $issue = $issues[$i];
709                $a_project      = strtolower($this->_get_one_value($issue,'project'));
710                $a_status     = strtolower($this->_get_one_value($issue,'status'));
711                $a_severity   = strtolower($this->_get_one_value($issue,'severity'));
712                $a_product    = strtoupper($this->_get_one_value($issue,'product'));
713                $a_version    = strtoupper($this->_get_one_value($issue,'version'));
714                $a_component  = strtoupper($this->_get_one_value($issue,'component'));
715                $a_tblock     = strtoupper($this->_get_one_value($issue,'tblock'));
716                $a_assignee   = strtoupper($this->_get_one_value($issue,'assignee'));
717                $a_reporter   = strtoupper($this->_get_one_value($issue,'user_name'));
718
719                if ((($data['status']    =='ALL') || (stristr($data['status'],$a_status)          != false)) &&
720                    (($data['severity']  =='ALL') || (stristr($data['severity'],$a_severity)      != false)) &&
721                    (($data['product']   =='ALL') || (stristr($data['product'],$a_product)        != false)) &&
722                    (($data['version']   =='ALL') || (stristr($data['version'],$a_version)        != false)) &&
723                    (($data['component'] =='ALL') || (stristr($data['component'],$a_component)    != false)) &&
724                    (($data['assignee']  =='ALL') || (stristr($data['assignee'],$a_assignee)      != false)) &&
725                    (($data['reporter']  =='ALL') || (stristr($data['reporter'],$a_reporter)      != false)) &&
726                    (($data['myissues']  == false  ) || ($this->_find_myissues($issue, $user_grp) == true)))
727               {
728
729                    if (stripos($this->getConf('status_special'),$a_status) !== false) continue;
730                    if((($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) || $project == $a_project  )
731                    {   if ($y>=$step) break;
732                        $y=$y+1;
733
734                        if($rowEven==="it_roweven") $rowEven="it_rowodd";
735                        else $rowEven="it_roweven";
736
737                        if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0))
738                        {   $a_project = $this->_get_one_value($issue,'project');
739                            $td_project = '<td class="itl__td_standard">'.$a_project.'</td>';
740                        }
741                        else{$td_project="";}
742
743                        $reduced_issues = $reduced_issues.'<tr id = "'.$a_project.' '.$this->_get_one_value($issue,'id').'" class="'.$rowEven.'" >'.NL.
744                                                          $td_project.NL.
745                                                          '<td'.$style.$this->_get_one_value($issue,'id').'</td>'.NL;
746                        foreach ($configs as $config)
747                        {
748                            $isval = $this->_get_one_value($issue,strtolower($config));
749                            if ($config == 'status')
750                            {
751                                if ($noStatIMG == false) {
752                                    $status_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($isval))).'.gif';
753                                    $reduced_issues .='<td class="it_center"><span style="display : none;">'.$a_status.'</span><img border="0" alt="'.$isval.'" title="'.$isval.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$status_img.'" width="16" height="16"/></td>'.NL;
754                                }
755                                else { $reduced_issues .= '<td'.$style.$isval.'</td>'.NL; }
756                            }
757                            elseif ($config == 'severity')
758                            {
759                                if ($noSevIMG == false) {
760                                    $severity_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($isval))).'.gif';
761                                    $reduced_issues .='<td  class="it_center"><span style="display : none;">'.$a_severity.'</span><img border="0" alt="'.$isval.'" title="'.$isval.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$severity_img.'" width="16" height="16"/></td>'.NL;
762                                }
763                                else { $reduced_issues .= '<td'.$style.$isval.'</td>'.NL; }
764                            }
765                            elseif ($config == 'title')
766                            {   // build parameter for $_GET method
767                                $pstring = sprintf("showid=%s&amp;project=%s", urlencode($this->_get_one_value($issue,'id')), urlencode($a_project));
768                                $reduced_issues .='<td>'.
769                                                  '<a href="doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" title="'.$isval.'">'.$isval.'</a></td>'.NL;
770                            }
771                            elseif ($config == 'created')
772                            {   $reduced_issues .='<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'created'))).'</td>'.NL;
773                            }
774                            elseif ($config == 'modified')
775                            {   $reduced_issues .='<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'modified'))).'</td>'.NL;
776                            }
777                            elseif ($config == 'resolution')
778                            {   $reduced_issues .='<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'resolution')).'</td>'.NL;
779                            }
780                            elseif ($config == 'description')
781                            {   $reduced_issues .='<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'description')).'</td>'.NL;
782                            }
783                            else
784                            {
785                                $reduced_issues .= '<td'.$style.$isval.'</td>'.NL;
786                            }
787                        }
788                        $reduced_issues .= '</tr>'.NL;
789                    }
790                  }
791              }
792
793            $head = NL.$reduced_header.NL;
794            $body = '<tbody>'.$reduced_issues.'</tbody>'.NL.'</table>'.NL.'</div>'.NL;
795        }
796// -----------------------------------------------------------------------------
797// Control render
798        if($data['myissues']==false) {$data['myissues'] = "";}
799        else {$data['myissues'] = "checked='true'";}
800
801        if($data['tblock']==false) { $data['tblock'] = ""; }
802        else $data['tblock'] = "checked='true'";
803
804        if (strtolower($data['controls'])==='on') {
805          $a_result = $this->_count_render($issues,$start,$step,$next_start,$data,$project);
806          $li_count =$a_result[1];
807          $count = $a_result[0];
808
809        $ret = '<div>'.NL.
810               '<script  type="text/javascript">'.NL.
811               '        function changeAction(where) {'.NL.
812               '           if(where==1) {'.NL.
813               '              document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_previous";'.NL.
814               '           }'.NL.
815               '           else if(where==2){'.NL.
816               '              document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_next";'.NL.
817               '           }'.NL.
818               '           else if(where==3){'.NL.
819               '              document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_filter";'.NL.
820               '           }'.NL.
821               '           document.forms["myForm"].submit();'.NL.
822               '        }'.NL.
823               '     </script>'.NL.
824               '<table class="itl__t1"><tbody>'.NL.
825               '<tr class="itd__tables_tr">'.NL.
826               '   <td colspan="4" align="left" valign="middle" height="30">'.NL.
827               '       <label class="it__cir_projectlabel">'.sprintf($this->getLang('lbl_issueqty'),$project).$count.'</label>'.NL.
828               '   </td>'.NL.
829               '   <td class="itl__showdtls" rowspan="2" width="30%">'.$li_count.'</td>'.NL.
830               '</tr>'.NL.
831
832               '<tr class="itd__tables_tr">'.NL.
833               '   <td align ="left" valign="top" width="15%">'.NL;
834
835               $ret .= '   <p class="it__cir_projectlabel">'.'<label for="itl_step"           style="align:left;">'.$this->getLang('lbl_scroll')                                                 .'</label><br />'.NL;
836                   if(stripos($this->getConf('ltdListFilters'),'Filter Severity')=== false)      $ret .= '<label for="itl_sev_filter"   style="align:left;">'.$this->getLang('lbl_filtersev')     .'</label><br />'.NL;
837                   if(stripos($this->getConf('ltdListFilters'),'Filter Status')=== false)        $ret .= '<label for="itl_stat_filter"  style="align:left;">'.$this->getLang('lbl_filterstat')    .'</label><br />'.NL;
838               $ret .= '</p><p class="it__cir_projectlabel">'.NL;
839                   if(stripos($this->getConf('ltdListFilters'),'Filter Product')=== false)       $ret .= '<label for="itl__prod_filter" style="align:left;">'.$this->getLang('lbl_filterprod')    .'</label><br />'.NL;
840                   if(stripos($this->getConf('ltdListFilters'),'Filter Version')=== false)       $ret .= '<label for="itl__vers_filter" style="align:left;">'.$this->getLang('lbl_filtervers')    .'</label><br />'.NL;
841                   if(stripos($this->getConf('ltdListFilters'),'Filter Component')=== false)     $ret .= '<label for="itl__comp_filter" style="align:left;">'.$this->getLang('lbl_filtercomp')    .'</label><br />'.NL;
842               $ret .= '</p><p class="it__cir_projectlabel">'.NL;
843                   if(stripos($this->getConf('ltdListFilters'),'Filter Test blocking')=== false) $ret .= '<label for="itl__block_filter" style="align:left;">'.$this->getLang('lbl_filterblock')  .'</label><br />'.NL;
844                   if(stripos($this->getConf('ltdListFilters'),'Filter Assignee')=== false)      $ret .= '<label for="itl__assi_filter" style="align:left;">'.$this->getLang('lbl_filterassi')    .'</label><br />'.NL;
845                   if(stripos($this->getConf('ltdListFilters'),'Filter Reporter')=== false)      $ret .= '<label for="itl__user_filter" style="align:left;">'.$this->getLang('lbl_filterreporter').'</label><br />'.NL;
846               $ret .= '</p><p class="it__cir_projectlabel">'.NL;
847                   if(stripos($this->getConf('ltdListFilters'),'MyIssues')=== false)             $ret .= '<label for="itl_myis_filter"  style="align:left;">'.$this->getLang('cbx_myissues')      .'</label><br />'.NL;
848                   if(stripos($this->getConf('ltdListFilters'),'Sort by')=== false)              $ret .= '<label for="it_glbl_sort"     style="align:left;">'.$this->getLang('lbl_sort')          .'</label>'.NL;
849               $ret .= '</p></td>'.NL;
850
851               $ret .= '   <td align ="left" valign="top" width="25%">'.NL.
852               '    <form name="myForm" action="" method="post">'.NL.
853               '       <input                          type="hidden" name="itl_start"        id="itl_start"        value="'.$start.'"/>'.NL.
854               '       <input                          type="hidden" name="itl_step"         id="itl_step"         value="'.$step.'"/>'.NL.
855               '       <input                          type="hidden" name="itl_next"         id="itl_next"         value="'.$next_start.'"/>'.NL.
856               '       <input                          type="hidden" name="itl_project"      id="itl_project"      value="'.$project.'"/>'.NL.
857               '       <input                          type="hidden" name="it_th_cols"       id="it_th_cols"       value="'.$data['columns'].'"/>'.NL.
858               '       <input class="itl__buttons"     type="button" name="showprevious"                           value="'.$this->getLang('btn_previuos').'" title="'.$this->getLang('btn_previuos_title').'" onClick="changeAction(1)"/>'.NL.
859               '       <input class="itl__step_input"  type="text"   name="itl_step"         id="itl_step"         value="'.$step.'"/>'.NL.
860               '       <input class="itl__buttons"     type="button" name="shownext"                               value="'.$this->getLang('btn_next').'"     title="'.$this->getLang('btn_next_title').'"     onClick="changeAction(2)"/><br />'.NL;
861
862                   if(stripos($this->getConf('ltdListFilters'),'Filter Severity')=== false)      $ret .= '<input class="itl__sev_filter"  type="text"   name="itl_sev_filter"   id="itl_sev_filter"   value="'.$data['severity'].'"/><br />'.NL;
863                   if(stripos($this->getConf('ltdListFilters'),'Filter Status')=== false)        $ret .= '<input class="itl__stat_filter" type="text"   name="itl_stat_filter"  id="itl_stat_filter"  value="'.$data['status'].'"/><br /></p>'.NL;
864               $ret .= '</p><p>'.NL;
865                   if(stripos($this->getConf('ltdListFilters'),'Filter Product')=== false)       $ret .= '<input class="itl__prod_filter" type="text"   name="itl__prod_filter" id="itl__prod_filter" value="'.$data['product'].'"/><br />'.NL;
866                   if(stripos($this->getConf('ltdListFilters'),'Filter Version')=== false)       $ret .= '<input class="itl__prod_filter" type="text"   name="itl__vers_filter" id="itl__vers_filter" value="'.$data['version'].'"/><br />'.NL;
867                   if(stripos($this->getConf('ltdListFilters'),'Filter Component')=== false)     $ret .= '<input class="itl__prod_filter" type="text"   name="itl__comp_filter" id="itl__comp_filter" value="'.$data['component'].'"/><br /></p>'.NL;
868               $ret .= '</p><p>'.NL;
869                   if(stripos($this->getConf('ltdListFilters'),'Filter Test blocking')=== false) $ret .= '<input                          type="checkbox" name="itl__block_filter" id="itl__block_filter" '   .$data['tblock'].'/><br />'.NL;
870                   if(stripos($this->getConf('ltdListFilters'),'Filter Assignee')=== false)      $ret .= '<input class="itl__prod_filter" type="text"   name="itl__assi_filter" id="itl__assi_filter" value="'.$data['assignee'].'"/><br />'.NL;
871                   if(stripos($this->getConf('ltdListFilters'),'Filter Reporter')=== false)      $ret .= '<input class="itl__prod_filter" type="text"   name="itl__user_filter" id="itl__user_filter" value="'.$data['reporter'].'"/><br />'.NL;
872               $ret .= '</p><p>'.NL;
873                   if(stripos($this->getConf('ltdListFilters'),'MyIssues')=== false)             $ret .= '<input                          type="checkbox" name="itl_myis_filter" id="itl_myis_filter" '       .$data['myissues'].' title="'.$this->getLang('cbx_myissues').'" /><br />'.NL;
874                   if(stripos($this->getConf('ltdListFilters'),'Sort by')=== false)              $ret .= '<input class="itl__sev_filter"  type="text"   name="it_glbl_sort"      id="it_glbl_sort"    value="'.$data['sort'].'"/><br /></p>'.NL;
875               $ret .= '</p><input class="itl__buttons" type="button" name="go" value="'.$this->getLang('btn_go').'" title="'.$this->getLang('btn_go').'" onClick="changeAction(3)"/><br />'.NL;
876               $ret .= '</form>'.NL.
877               '   </td>'.NL.
878               '   <td width="2%">&nbsp;</td>'.NL.
879               '   <td class="itl__showdtls" align ="left" width="40%">'.NL.
880               '    <form  method="post" action="doku.php?id=' . $ID . '&do=showcase">'.NL.
881               '       <label class="it__searchlabel">'.$this->getLang('lbl_showid').'</label>'.NL.
882               '       <input class="itl__sev_filter"    type="text"   name="showid"          id="showid"          value="0"/>'.NL.
883               '       <input                            type="hidden" name="project"         id="project"         value="'.$project.'"/>'.NL.
884               '       <input                            type="hidden" name="itl_sev_filter"  id="itl_sev_filter"  value="'.$data['severity'].'"/>'.NL.
885               '       <input                            type="hidden" name="itl_stat_filter" id="itl_stat_filter" value="'.$data['status'].'"/>'.NL.
886               '       <input                            type="hidden" name="itl_myis_filter" id="itl_myis_filter" '       .$data['myissues'].' />'.NL.
887               '       <input class="itl__showid_button" type="submit" name="showcase"        id="showcase"        value="'.$this->getLang('btn_showid').'"    title="'.$this->getLang('btn_showid_title').'"/>'.NL.
888               '    </form><br />'.NL.
889               '    <form  method="post" action="doku.php?id=' . $ID . '&do=it_search">'.NL.
890               '       <label class="it__searchlabel">'.$this->getLang('lbl_search').'</label>'.NL.
891               '       <input class="itl__sev_filter"    type="text"   name="it_str_search"   id="it_str_search"   value="'.$search.'"/>'.NL.
892               '       <input                            type="hidden" name="project"         id="project"         value="'.$project.'"/>'.NL.
893               '       <input class="itl__search_button" type="submit" name="searchcase"      id="searchcase"      value="'.$this->getLang('btn_search').'" title="'.$this->getLang('btn_search_title').'"/>'.NL.
894               '    </form>'.NL.
895               '   </td>'.NL.
896               '</tr>'.NL.'</tbody>'.NL.'</table>'.NL.'</div>'.NL;
897         }
898
899
900         $usr  = '<span style="display:none;" id="currentuser">'.$user_grp['userinfo']['name'].'</span>' ;   //to log issue mods
901         $usr .= '<span style="display:none;" id="currentID">'.urlencode($ID).'</span>' ; // to log issue mods
902         $a_lang  = '<span style="display:none;" name="table_kit_OK" id="table_kit_OK">'.$this->getLang('table_kit_OK').'</span>'; // for tablekit.js
903         $a_lang .= '<span style="display:none;" name="table_kit_Cancel" id="table_kit_Cancel">'.$this->getLang('table_kit_Cancel').'</span>'; // for tablekit.js
904         $ret  = $a_lang.$usr.$ret.$head.$body;
905         return $ret;
906    }
907/******************************************************************************/
908/* pic-up a single value
909*/
910    function _get_one_value($issue, $key) {
911        if (@array_key_exists($key,$issue))
912            return $issue[$key];
913        return '';
914    }
915
916/******************************************************************************/
917/* elaborate the display string of assignee (login, name or mail)
918*/
919    function _get_assignee($issue, $key) {
920        if(!$issue) return;
921        if (array_key_exists($key,$issue)) {
922            global $auth;
923            global $conf;
924            $filter['grps']  = $this->getConf('assign');
925            $usr_array       = $auth->retrieveUsers(0,0,$filter);
926            $shw_assignee_as = trim($this->getConf('shw_assignee_as'));
927            if(stripos("login, mail, name",$shw_assignee_as) === false) $shw_assignee_as = "login";
928            foreach ($usr_array as $u_key => $usr)
929            {     if($usr['mail']==$issue[$key])
930                  {   if   ($shw_assignee_as=='login') { return $u_key; }
931                      elseif($shw_assignee_as=='mail') { return $usr['mail']; }
932                      else                             { return $usr['name']; }
933                  }
934            }
935        }
936        if(stripos("mail",$shw_assignee_as) !== false) return $issue[$key];
937        else {
938          $b_display = explode("@",$issue[$key]);
939          return $b_display[0];
940        }
941    }
942/******************************************************************************/
943/* send an e-mail to admin due to new issue created
944*/
945    function _emailForNewIssue($project,$issue,$email_to)
946    {
947        if ($this->getConf('send_email')==1)
948        {   global $ID;
949
950            if ($this->getConf('mail_templates')==1) {
951              // load user html mail template
952              $sFilename = DOKU_PLUGIN.'issuetracker/mailtemplate/new_issue_mail.html';
953              $bodyhtml = file_get_contents($sFilename);
954            }
955            $subject=sprintf($this->getLang('issuenew_subject'),$issue['severity'], $project, $issue['product'],$issue['version']);
956            $subject= mb_encode_mimeheader($subject, "UTF-8", "Q" );
957            $pstring = sprintf("showid=%s&project=%s", urlencode($issue['id']), urlencode($project));
958
959            $body = $this->getLang('issuenew_head').chr(10).chr(10).
960                    $this->getLang('issuenew_intro').chr(10).
961                    $this->getLang('issuemod_title').$issue['title'].chr(10).
962                    $this->getLang('issuemod_issueid').$issue['id'].chr(10).
963                    $this->getLang('issuemod_product').$issue['product'].chr(10).
964                    $this->getLang('issuemod_version').$issue['version'].chr(10).
965                    $this->getLang('issuemod_severity').$issue['severity'].chr(10).
966                    $this->getLang('issuemod_status').$issue['status'].chr(10).
967                    $this->getLang('issuemod_creator').$issue['user_name'].chr(10).
968                    $this->getLang('th_assigned').$issue['assigned'].chr(10).chr(10).
969                    $this->getLang('issuenew_descr').$this->xs_format($issue['description']).chr(10).chr(10).
970                    $this->getLang('issuemod_see').DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring.chr(10).chr(10).
971                    $this->getLang('issuemod_br').chr(10).$this->getLang('issuemod_end');
972
973            $body = html_entity_decode($body);
974            if ($this->getConf('mail_templates')==1) $bodyhtml = $this->replace_bodyhtml($bodyhtml, $pstring, $project, $issue, $comment);
975            $from=$email_to ;
976            $to=$from;
977            $cc=$issue['add_user_mail'];
978            if ($this->getConf('mail_templates')==1) {
979              $headers = "Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable";
980              $this->mail_send_html($to, $subject, $body, $bodyhtml, $from, $cc, $bcc='', $headers, $params=null);
981            }
982            else {
983              mail_send($to, $subject, $body, $from, $cc, $bcc='', $headers=null, $params=null);
984            }
985        }
986    }
987
988/******************************************************************************/
989    /***********************************
990     * HTML Mail functions
991     *
992     * Sends HTML-formatted mail
993     * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com)
994     *
995     ***********************************/
996    function mail_send_html($to, $subject, $body, $bodyhtml, $from='', $cc='', $bcc='', $header='', $params=null){
997      if(defined('MAILHEADER_ASCIIONLY')){
998        $subject = utf8_deaccent($subject);
999        $subject = utf8_strip($subject);
1000      }
1001      if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n");
1002      if(!utf8_isASCII($subject)) {
1003        $subject = '=?UTF-8?Q?'.mail_quotedprintable_encode($subject,0).'?=';
1004        // Spaces must be encoded according to rfc2047. Use the "_" shorthand
1005        $subject = preg_replace('/ /', '_', $subject);
1006      }
1007
1008      $header  = '';
1009
1010      $usenames = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true;
1011
1012      $random_hash = md5(date('r', time())); // added
1013
1014      $to = mail_encode_address($to,'',$usenames);
1015      $header .= mail_encode_address($from,'From');
1016      $header .= mail_encode_address($cc,'Cc');
1017      $header .= mail_encode_address($bcc,'Bcc');
1018      $header .= 'MIME-Version: 1.0'.MAILHEADER_EOL;
1019      $header .= "Content-Type: multipart/alternative; boundary=PHP-alt-".$random_hash.MAILHEADER_EOL;
1020      $header  = trim($header);
1021
1022
1023      $body = mail_quotedprintable_encode($body,0);
1024      $bodyhtml = mail_quotedprintable_encode($bodyhtml,0);
1025
1026      $message =	"--PHP-alt-".$random_hash."\r\n".
1027    				"Content-Type: text/plain; charset=UTF-8"."\n".
1028    				"Content-Transfer-Encoding: quoted-printable"."\n\n".
1029    				$body."\n\n".
1030    				"--PHP-alt-".$random_hash."\r\n".
1031    				"Content-Type: text/html; charset=UTF-8"."\n".
1032    				"Content-Transfer-Encoding: quoted-printable"."\n\n".
1033    				$bodyhtml."\n".
1034    				"--PHP-alt-".$random_hash."--";
1035
1036      if($params == null){
1037        return mail($to,$subject,$message,$header);
1038      }else{
1039        return mail($to,$subject,$message,$header,$params);
1040      }
1041    }
1042/******************************************************************************/
1043    function replace_bodyhtml($bodyhtml, $pstring, $project, $issue, $comment) {
1044        global $ID;
1045        $bodyhtml = str_ireplace("%%_SEE%%",DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring,$bodyhtml);
1046        $bodyhtml = str_ireplace("%%issuemod_head%%",$this->getLang('issuemod_head'),$bodyhtml);
1047        $bodyhtml = str_ireplace("%%issuemod_issueid%%",$this->getLang('issuemod_issueid'),$bodyhtml);
1048        $bodyhtml = str_ireplace("%%ID%%",$issue['id'],$bodyhtml);
1049        $bodyhtml = str_ireplace("%%issuemod_title%%",$this->getLang('issuemod_title'),$bodyhtml);
1050        $bodyhtml = str_ireplace("%%TITEL%%",$issue['title'],$bodyhtml);
1051        $bodyhtml = str_ireplace("%%issuemod_status%%",$this->getLang('issuemod_status'),$bodyhtml);
1052        $bodyhtml = str_ireplace("%%STATUS%%",$issue['status'],$bodyhtml);
1053        $bodyhtml = str_ireplace("%%th_project%%",$this->getLang('th_project'),$bodyhtml);
1054        $bodyhtml = str_ireplace("%%PROJECT%%",$project,$bodyhtml);
1055        $bodyhtml = str_ireplace("%%issuemod_product%%",$this->getLang('issuemod_product'),$bodyhtml);
1056        $bodyhtml = str_ireplace("%%PRODUCT%%",$issue['product'],$bodyhtml);
1057        $bodyhtml = str_ireplace("%%issuemod_version%%",$this->getLang('issuemod_version'),$bodyhtml);
1058        $bodyhtml = str_ireplace("%%VERSION%%",$issue['version'],$bodyhtml);
1059        $bodyhtml = str_ireplace("%%issuemod_severity%%",$this->getLang('issuemod_severity'),$bodyhtml);
1060        $bodyhtml = str_ireplace("%%SEVERITY%%",$issue['severity'],$bodyhtml);
1061        $bodyhtml = str_ireplace("%%issuemod_creator%%",$this->getLang('issuemod_creator'),$bodyhtml);
1062        $bodyhtml = str_ireplace("%%CREATOR%%",$issue['user_name'],$bodyhtml);
1063        $bodyhtml = str_ireplace("%%CREATOR_MAIL%%",$issue['user_mail'],$bodyhtml);
1064        $bodyhtml = str_ireplace("%%th_assigned%%",$this->getLang('th_assigned'),$bodyhtml);
1065        $bodyhtml = str_ireplace("%%ASSIGNED%%",$issue['assigned'],$bodyhtml);
1066        $bodyhtml = str_ireplace("%%th_created%%",$this->getLang('th_created'),$bodyhtml);
1067        $bodyhtml = str_ireplace("%%CREATED%%",$issue['created'],$bodyhtml);
1068
1069        $bodyhtml = str_ireplace("%%issue_resolved_intro%%",$this->getLang('issue_resolved_intro'),$bodyhtml);
1070        $bodyhtml = str_ireplace("%%issue_resolved_text%%",$this->getLang('issue_resolved_text'),$bodyhtml);
1071        $frmt_res = str_ireplace(chr(10),"<br />",$issue['resolution']);
1072        $bodyhtml = str_ireplace("%%RESOLUTION%%",$this->xs_format($frmt_res),$bodyhtml);
1073        $bodyhtml = str_ireplace("%%TIMESTAMP%%",date($this->getConf('d_format')),$bodyhtml);
1074
1075        $user_grp = pageinfo();
1076        $usr      = $user_grp['userinfo']['name'] ;
1077        $bodyhtml = str_ireplace("%%RESOLVER%%",$usr,$bodyhtml);
1078        $bodyhtml = str_ireplace("%%MOD_BY%%",$usr,$bodyhtml);
1079        $bodyhtml = str_ireplace("%%issuedescrmod_subject%%",sprintf($this->getLang('issuedescrmod_subject'),$issue['id'], $project),$bodyhtml);
1080        $bodyhtml = str_ireplace("%%th_description%%",$this->getLang('th_description'),$bodyhtml);
1081        $frmt_descr = str_ireplace(chr(10),"<br />",$issue['description']);
1082        $bodyhtml = str_ireplace("%%DESCRIPTION%%",$this->xs_format($frmt_descr),$bodyhtml);
1083
1084
1085//        if($comment) {
1086            $bodyhtml = str_ireplace("%%lbl_cmts_wlog%%",$this->getLang('lbl_cmts_wlog'),$bodyhtml);
1087            $bodyhtml = str_ireplace("%%CMNT_ID%%",$comment['id'],$bodyhtml);
1088            $bodyhtml = str_ireplace("%%CMNT_AUTHOR%%",$comment['author'],$bodyhtml);
1089            $bodyhtml = str_ireplace("%%CMNT_TIMESTAMP%%",date($this->getConf('d_format'),strtotime($comment['timestamp'])),$bodyhtml);
1090            $frmt_cmnt = str_ireplace(chr(10),"<br />",$comment['comment']);
1091            $bodyhtml = str_ireplace("%%COMMENT%%",$this->xs_format($frmt_cmnt),$bodyhtml);
1092//        }
1093        $bodyhtml = str_ireplace("%%issuemod_br%%",$this->getLang('issuemod_br'),$bodyhtml);
1094        $bodyhtml = str_ireplace("%%issuemod_end%%",$this->getLang('issuemod_end'),$bodyhtml);
1095
1096        return $bodyhtml;
1097    }
1098/******************************************************************************/
1099/*  Report an Issue
1100*/
1101    function _report_render($data)
1102    {
1103        global $lang;
1104        global $ID;
1105        $imgBASE = DOKU_BASE."lib/plugins/issuetracker/images/";
1106        $project = $data['project'];
1107
1108        // retrive some basic information
1109        $user_mail = pageinfo();  //to get mail address of reporter
1110        $cur_date = date($this->getConf('d_format'));
1111        $user_check = $this->getConf('registered_users');
1112
1113        // check if current user is admin/assignee
1114        // check if syntax parameter asympupl is switched on
1115        $user_mail    = pageinfo();
1116        if(array_key_exists('userinfo', $user_mail))
1117        {   foreach ($user_mail['userinfo']['grps'] as $ugrp)
1118            {  $user_grps = $user_grps . $ugrp;  }
1119        }
1120        else
1121        {   $user_grps = 'all';  }
1122        $allowed_users = explode('|', $this->getConf('assign'));
1123        $cFlag = false;
1124        foreach ($allowed_users as $w)
1125        {   // check if one of the assigned user roles does match with current user roles
1126            if (strpos($user_grps,$w)!== false)
1127            {   $cFlag = true;
1128                break;  }
1129        }
1130
1131        $_cFlag = false;
1132        if($user_check == 0) {
1133            $_cFlag = true;  }
1134        elseif (($user_check == 1) && ($user_mail['perm'] > 1)) {
1135            $_cFlag = true;  }
1136
1137        if($_cFlag === true) {
1138            /*--------------------------------------------------------------------*/
1139            // load set of projects defined by admin
1140            /*--------------------------------------------------------------------*/
1141            $STR_PROJECT = "";
1142            $l_projects = explode(',', $this->getConf('projects')) ;
1143            $STR_PROJECT = '<option value="" >'.$project.'</option>'.NL;
1144            foreach ($l_projects as $a_project)
1145            {
1146                $a_project = trim($a_project);
1147                $STR_PROJECT .= '<option value="'.$a_project.'" >'.$a_project."</option>".NL;
1148            }
1149            /*--------------------------------------------------------------------*/
1150            // load set of product names defined by admin
1151            /*--------------------------------------------------------------------*/
1152            if($data['prod_limit'] !== "OFF") {
1153                $temp2 = explode(',', $this->getConf('products'));
1154                foreach($temp2 as $a) {
1155                    if(stripos(strtoupper($data['product']),strtoupper($a))!==false) {
1156                        if(strlen($temp)<1){
1157                            $temp .= $a;
1158                        }
1159                        else $temp .= ','.$a;
1160                    }
1161                }
1162                $products = explode(',', $temp);
1163            }
1164            else {
1165                 $products = explode(',', $this->getConf('products'));
1166            }
1167
1168            $STR_PRODUCTS = "";
1169            foreach ($products as $_products)
1170            {
1171                $x_products = trim($x_products);
1172                //if product is preselected by syntax
1173                if(strtoupper ($_products) == strtoupper ($data['product'])) { $option_param = '<option value="'.$_products.'" selected >'; }
1174                else { $option_param = '<option value="'.$_products.'" >'; }
1175
1176                $STR_PRODUCTS = $STR_PRODUCTS . $option_param .$_products."</option>".NL;
1177            }
1178
1179            /*--------------------------------------------------------------------*/
1180            // load set of components defined by admin
1181            /*--------------------------------------------------------------------*/
1182            $STR_COMPONENTS = "";
1183            $components = explode(',', $this->getConf('components')) ;
1184//            $STR_COMPONENTS = '<option value="" ></option>'.NL;
1185            foreach ($components as $_component)
1186            {
1187                $_component = trim($_component);
1188                $STR_COMPONENTS .= '<option value="'.$_component.'" >'.$_component."</option>".NL;
1189            }
1190            if($STR_COMPONENTS === "") $STR_COMPONENTS = '<option value="" ></option>'.NL;
1191
1192            /*--------------------------------------------------------------------*/
1193            // load set of severity values defined by admin
1194            /*--------------------------------------------------------------------*/
1195            $STR_SEVERITY = "";
1196            $severity = explode(',', $this->getConf('severity')) ;
1197            foreach ($severity as $_severity)
1198            {
1199                $_severity = trim($_severity);
1200                $STR_SEVERITY = $STR_SEVERITY . '<option value="'.$_severity.'" >'.$_severity."</option>".NL;
1201            }
1202
1203            /*--------------------------------------------------------------------*/
1204            // create the report template and check input on client site
1205            /*--------------------------------------------------------------------*/
1206            if($this->getConf('wysiwyg')==true) {
1207              $_editor_java ='if ((document.getElementById("a_description").innerHTML.length <= 5) & (document.getElementById("a_description").innerHTML.indexOf(" ") == -1)) {
1208                          alert ("'.$this->getLang('wmsg3').'");
1209                          frm.description.focus();
1210                          return false;}';
1211              $_editor_java_2 ='function myFunction() {
1212                                  document.getElementById("description").value = document.getElementById("a_description").innerHTML;
1213                                }';
1214              $myFunc = 'onsubmit="myFunction()"';
1215
1216            }
1217            else {
1218              $_editor_java ='if ((frm.description.value.length <= 5) & (frm.description.value.indexOf(" ") == -1)) {
1219                          alert ("'.$this->getLang('wmsg3').'");
1220                          frm.description.focus();
1221                          return false;';
1222
1223              $_editor_java_2 ='';
1224              $myFunc = 'onsubmit="return chkFormular(this)"';
1225            }
1226
1227            $ret = '<div class="it__cir_form"><script>
1228                   // JavaScript Document
1229                    function chkFormular(frm) {
1230
1231                        if (frm.product.value == "") {
1232                          alert("Please select a valid product!");
1233                          frm.product.focus();
1234                          return false;
1235                        }
1236
1237                        if (frm.version.value == "") {
1238                          alert("'.$this->getLang('wmsg2').'");
1239                          frm.version.focus();
1240                          return false;
1241                        }
1242
1243                        if (frm.user_name.value < 3) {
1244                          alert("Please enter your user name!");
1245                          frm.user_name.focus();
1246                          return false;
1247                        }
1248
1249                        if (frm.user_mail.value.indexOf("@") == -1) {
1250                          alert ("'.$this->getLang('wmsg1').'");
1251                          frm.user_mail.focus();
1252                          return false;
1253                        }
1254
1255                        if (frm.severity.value == "") {
1256                          alert ("Please select a severity");
1257                          frm.severity.focus();
1258                          return false;
1259                        }
1260
1261                        if ((frm.ittitle.value.length <= 5) & (frm.ittitle.value.indexOf(" ") == -1)) {
1262                          alert ("'.$this->getLang('wmsg5').'");
1263                          frm.ittitle.focus();
1264                          return false;
1265                        }
1266
1267                        '.NL.$_editor_java.NL.'
1268                    }
1269                    '.NL.$_editor_java_2.NL.'
1270                   }</script>'.NL;
1271            $ret .= '<form class="issuetracker__form" name="issuetracker__form" method="post" '.$myFunc.' accept-charset="'.$lang['encoding'].'" enctype="multipart/form-data" ><p>'.NL.
1272            formSecurityToken(false).
1273            '<input type="hidden" name="do" value="show" />'.NL.
1274            '<input type="hidden" name="id" value="'.$ID.'" />'.NL.
1275            '<input type="hidden" name="created" value="'.$cur_date.'"/>'.NL.
1276//            '<input type="hidden" name="comments" value="'.$comments_file.'"/>'.
1277            '</p>'.NL.
1278            '<table class="it_form_table">
1279              <tr>
1280                <td>'.$this->getLang('th_project').'</td>'.NL;
1281
1282                   //Check config if hidden
1283                  if($this->getConf('projects')==""){
1284                        $ret .= '<td><label class="it__cir_projectlabel">'.$project.'</label></td>'.NL; }
1285                  else {
1286                      $ret .='<td><select class="element select small it__cir_select" name="project">'.$STR_PROJECT.'</select></td>'.NL;
1287                  }
1288     $ret .= '</tr>'.NL.
1289             '<tr>
1290                <td>'.$this->getLang('th_product').'</td>
1291                <td><select class="element select small it__cir_select" name="product">'.$STR_PRODUCTS.'</select></td>
1292              </tr>'.NL.
1293             '<tr>';
1294                   //Check config if hidden
1295                  if(strpos($this->getConf('ltdReport'),'Version')!==false){
1296                      $STR_VERSIONS = ' ';
1297                      $ret .= ' <input type="hidden" class="it__cir_input" name="version" value="'.$STR_VERSIONS.'"/>';
1298                  }
1299                  else {
1300                      $ret .= ' <td>'.$this->getLang('th_version').'</td>
1301                                <td><input class="it__cir_input" name="version" value="'.$STR_VERSIONS.'"/></td>';
1302                  }
1303
1304        $ret .= '</tr><tr>'.NL;
1305                   //Check config if hidden
1306                  if(strpos($this->getConf('ltdReport'),'Components')!==false){
1307                      $STR_COMPONENTS = ' ';
1308                      $ret .= '<input type="hidden" class="it__cir_input" name="component" value="'.$STR_COMPONENTS.'"/>';
1309                  }
1310                  else {
1311                      $ret .='<td>'.$this->getLang('th_components').'</td>
1312                              <td><select class="element select small it__cir_select" name="component">'.$STR_COMPONENTS.'</select></td>'.NL;
1313                  }
1314        $ret .= '</tr><tr>'.NL;
1315
1316                   //Check config if hidden
1317                  if(strpos($this->getConf('ltdReport'),'Test blocking')!==false){
1318                      $ret .= '<input type="hidden" name="tblock" value="false">';
1319                  }
1320                  else {
1321                      $ret .='<td>'.$this->getLang('th_tblock').'</td>
1322                              <td><input class="it__cir_cbx" type="checkbox" name="tblock"></td>'.NL;
1323                  }
1324
1325        $ret .= '</tr><tr><td colspan=2>&nbsp;</td></tr>'.NL.
1326             '<tr>
1327                <td>'.$this->getLang('th_user_name').'</td>
1328                <td><input class="it__cir_input" name="user_name" value="'.$user_mail['userinfo']['name'].'"/></td>
1329              </tr>'.NL.
1330             '<tr>
1331                <td>'.$this->getLang('th_usermail').'</td>
1332                <td><input class="it__cir_input" name="user_mail" value="'.$user_mail['userinfo']['mail'].'"/></td>
1333              </tr>'.NL.
1334             '<tr>';
1335                  //Check config if hidden
1336                  if(strpos($this->getConf('ltdReport'),'User phone')!==false){
1337                      $ret .= ' <input type="hidden" class="it__cir_input" name="user_phone" value="'.$user_phone['userinfo']['phone'].'"/>';
1338                  }
1339                  else {
1340                      $ret .= ' <td>'.$this->getLang('th_userphone').'</td>
1341                                <td><input class="it__cir_input" name="user_phone" value="'.$user_phone['userinfo']['phone'].'"/></td>';
1342                  }
1343              $ret .= '</tr>'.NL.
1344             '<tr>';
1345                   //Check config if hidden
1346                  if(strpos($this->getConf('ltdReport'),'Add contact')!==false){
1347                      $ret .= ' <input type="hidden" class="it__cir_input" name="add_user_mail" value="'.$_REQUEST['add_user_mail'].'"/>';
1348                  }
1349                  else {
1350                      $ret .= ' <td>'.$this->getLang('th_reporteradcontact').'</td>
1351                                <td><input class="it__cir_input" name="add_user_mail" value="'.$_REQUEST['add_user_mail'].'"/></td>';
1352                  }
1353        $ret .= '</tr>'.NL.
1354            '<tr><td colspan=2>&nbsp;</td></tr>'.NL.
1355            '<tr>';
1356                   //Check config if hidden
1357                  if(strpos($this->getConf('ltdReport'),'Severity')!==false){
1358                      $severity = explode(',', $this->getConf('severity')) ;
1359                      $STR_SEVERITY = $severity[0];
1360                      $ret .= ' <input type="hidden" class="it__cir_input" name="severity" value="'.$STR_SEVERITY.'"/>';
1361                  }
1362                  else {
1363                      $ret .= ' <td>'.$this->getLang('th_severity').'</td>
1364                                <td><select class="element select small it__cir_select" name="severity">'.$STR_SEVERITY.'</select></td>';
1365                  }
1366        $ret .= '</tr>'.NL.
1367            '<tr>
1368                <td>'.$this->getLang('th_title').'</td>
1369                <td><input class="it__cir_linput" name="title" value="'.$_REQUEST['title'].'"/></td>
1370             </tr>'.NL.
1371            '<tr>
1372                <td>'.$this->getLang('th_description').'</td>
1373                <td>'.NL;
1374
1375// mod for editor ---------------------------------------------------------------------
1376// check the config setting what editor to be used
1377        if($this->getConf('wysiwyg')==true)
1378        {
1379                  //hack if DOKU_BASE is not properly set
1380                  if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $sFilename = DOKU_URL."lib/plugins/issuetracker/wysiwyg_editor.js";
1381                  else $sFilename = DOKU_BASE."lib/plugins/issuetracker/wysiwyg_editor.js";
1382                  $ret      .= '<script type="text/javascript" src="'.$sFilename.'"></script>';
1383                  $sFilename = DOKU_PLUGIN.'issuetracker/wysiwyg_editor.html';
1384                  $ret      .= file_get_contents($sFilename);
1385                  $ret       = str_ireplace("%%DOKU_BASE%%",DOKU_BASE,$ret);
1386                  $ret .= '<span class="reply_close_link">
1387                             <a href="javascript:resizeBoxId(\'description\', -20)"><img src="'.$imgBASE.'reduce.png" title="reduce textarea" style="float:right;" /></a>
1388                             <a href="javascript:resizeBoxId(\'description\', +20)"><img src="'.$imgBASE.'enlarge.png" title="enlarge textarea" style="float:right;" /></a>
1389                           </span>'.NL;
1390                  $ret .= '<textarea id="description" name="description" style="display: none;">'.$_REQUEST['description'].'</textarea>';
1391
1392
1393        }
1394        else
1395        {
1396                  if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $sFilename = DOKU_URL."lib/plugins/issuetracker/xsEditor.js";
1397                  else $sFilename = DOKU_BASE."lib/plugins/issuetracker/xsEditor.js";
1398                  $ret      .= '<script type="text/javascript" src="'.$sFilename.'"></script>';
1399                  $ret .= file_get_contents($sFilename);
1400                  global $_FILES;
1401                  $ret .= $this->it_edit_toolbar('description');
1402                  $ret .= '<textarea class="it__cir_linput" id="description" name="description" cols="109" rows="7">'.$_REQUEST['description'].'</textarea></td></tr>
1403                           <span class="reply_close_link">
1404                              <a href="javascript:resizeBoxId(\'description\', -20)"><img src="'.$imgBASE.'reduce.png" title="reduce textarea" style="float:right;" /></a>
1405                              <a href="javascript:resizeBoxId(\'description\', +20)"><img src="'.$imgBASE.'enlarge.png" title="enlarge textarea" style="float:right;" /></a>
1406                           </span>'.NL;
1407        }
1408// mod for editor ---------------------------------------------------------------------
1409
1410          $ret .= '<tr><td colspan=2>&nbsp;</td></tr>';
1411                  // check if symptom file upload is allowed
1412                  if(($this->getConf('upload')>0) || (($cFlag === true) && ($data['asympupl']=true))) {
1413                      //Check config if hidden
1414                      if(($cFlag === true) && ($data['asympupl']=true)) {
1415                          $ret .= '<tr><td>'.$this->getLang('th_sympt').'1</td>
1416                                       <td><input type="file" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/></td></tr>';
1417                      }
1418                      elseif(strpos($this->getConf('ltdReport'),'Symptom link 1')!==false){
1419                          $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/>';
1420                      }
1421                      else {
1422                          $ret .= '<tr><td>'.$this->getLang('th_sympt').'1</td>
1423                                       <td><input type="file" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/></td></tr>';
1424                      }
1425                      if(strpos($this->getConf('ltdReport'),'Symptom link 2')!==false){
1426                          $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment2" value="'.$_REQUEST['attachment2'].'"/>';
1427                      }
1428                      else {
1429                          $ret .= '<tr><td>'.$this->getLang('th_sympt').'2</td>
1430                                       <td><input type="file" class="it__cir_linput" name="attachment2" value="'.$_REQUEST['attachment2'].'"/></td></tr>';
1431                      }
1432                      if(strpos($this->getConf('ltdReport'),'Symptom link 3')!==false){
1433                          $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment3" value="'.$_REQUEST['attachment3'].'"/>';
1434                      }
1435                      else {
1436                          $ret .= '<tr><td>'.$this->getLang('th_sympt').'3</td>
1437                                       <td><input type="file" class="it__cir_linput" name="attachment3" value="'.$_REQUEST['attachment3'].'"/></td></tr>';
1438                      }
1439                  }
1440        $ret .= '</table><p><input type="hidden" name="modified" value="'.$cur_date.'"/>'.NL.
1441                '<input type="hidden" name="assigned" value="" />'.NL;
1442
1443            if ($this->getConf('use_captcha')==1)
1444            {
1445                $helper = null;
1446      		      if(@is_dir(DOKU_PLUGIN.'captcha'))
1447      			       $helper = plugin_load('helper','captcha');
1448
1449      		      if(!is_null($helper) && $helper->isEnabled())
1450      			    {
1451      			       $ret .= '<p>'.$helper->getHTML().'</p>';
1452      			    }
1453            }
1454         //<input name="do[save]" type="submit" value="Save" class="button" id="edbtn__save" accesskey="s" tabindex="4" title="Save [S]" />
1455            $ret .= '</p><p><input name="submit" type="submit" value="'.$this->getLang('btn_reportsave').'" class="button" id="edbtn__save" title="'.$this->getLang('btn_reportsave').'"/>'.
1456            '</p></form></div>'.NL;
1457        }
1458        // the user maybe registered within group "all" but the registered flag is turned on
1459        // eigther the user has to be moved into group "user" or the flag to be switched off
1460        elseif(($user_mail['perm'] < 2) && (strlen($user_mail['userinfo']['mail'])>1)) {
1461            $issue_edit_resolution ='<table class="itd__tables">
1462                                     <tr>
1463                                        <td class="itd_tables_tdh" colSpan="2" >'.$this->getLang('th_resolution').'</td>
1464                                    </tr>';
1465            $issue_edit_resolution .= '<tr class="itd__tables_tr">
1466                                        <td width="1%"></td>
1467                                        <td>'.$this->xs_format($x_resolution).'</td>
1468                                      </tr></table>'.NL;
1469
1470            $wmsg = $this->getLang('lbl_lessPermission');
1471            $issue_edit_resolution .= '<div class="it__standard_feedback">'.$wmsg.'</div>';
1472        }
1473        else {
1474           $ret .= '<div class="it__standard_feedback">'.$this->getLang('wmsg4').'</div>';
1475        }
1476
1477        return $ret;
1478    }
1479/******************************************************************************/
1480/* Display positive/negative message box according user input on submit->Report
1481*/
1482    function _show_message($string){
1483        return "<script type='text/javascript'>
1484            alert('$string');
1485        </script>";
1486    }
1487
1488/******************************************************************************/
1489/* improved implode needed
1490*/
1491    function array_implode($arrays, &$target = array())
1492    {
1493         foreach ($arrays as $item) {
1494             if (is_array($item)) {
1495                 $this->array_implode($item, $target);
1496             } else {
1497                 $target[] = $item;
1498             }
1499         }
1500         return $target;
1501    }
1502
1503/******************************************************************************/
1504/**  http://www.linuxjournal.com/article/9585?page=0,0
1505Validate an email address.
1506Provide email address (raw input)
1507Returns true if the email address has the email
1508address format and the domain exists.
1509*/
1510    function validEmail($email)
1511    {
1512       $isValid = true;
1513       $atIndex = strrpos($email, "@");
1514       if (is_bool($atIndex) && !$atIndex)
1515       {
1516          $isValid = false;
1517       }
1518       else
1519       {
1520          $domain = substr($email, $atIndex+1);
1521          $local = substr($email, 0, $atIndex);
1522          $localLen = strlen($local);
1523          $domainLen = strlen($domain);
1524          if ($localLen < 1 || $localLen > 64)
1525          {
1526             // local part length exceeded
1527             $isValid = false;
1528          }
1529          else if ($domainLen < 1 || $domainLen > 255)
1530          {
1531             // domain part length exceeded
1532             $isValid = false;
1533          }
1534          else if ($local[0] == '.' || $local[$localLen-1] == '.')
1535          {
1536             // local part starts or ends with '.'
1537             $isValid = false;
1538          }
1539          else if (preg_match('/\\.\\./', $local))
1540          {
1541             // local part has two consecutive dots
1542             $isValid = false;
1543          }
1544          else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
1545          {
1546             // character not valid in domain part
1547             $isValid = false;
1548          }
1549          else if (preg_match('/\\.\\./', $domain))
1550          {
1551             // domain part has two consecutive dots
1552             $isValid = false;
1553          }
1554          else if
1555    (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
1556                     str_replace("\\\\","",$local)))
1557          {
1558             // character not valid in local part unless local part is quoted
1559             if (!preg_match('/^"(\\\\"|[^"])+"$/',
1560                 str_replace("\\\\","",$local)))
1561             {
1562                $isValid = false;
1563             }
1564          }
1565
1566          if((!function_exists('checkdnsrr')) && ($this->getConf('validate_mail_addr')==true))
1567          {
1568              function checkdnsrr($host, $type='')
1569              {
1570                if(!empty($host))
1571                {
1572                    $type = (empty($type)) ? 'MX' :  $type;
1573                    exec('nslookup -type='.$type.' '.escapeshellcmd($host), $result);
1574                    $it = new ArrayIterator($result);
1575                    foreach(new RegexIterator($it, '~^'.$host.'~', RegexIterator::GET_MATCH) as $result)
1576                    {
1577                         if($result) {  return true;  }
1578                    }
1579                 }
1580                 return false;
1581              }
1582           }
1583          else if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")) && ($this->getConf('validate_mail_addr')==true))
1584          {
1585             // domain not found in DNS
1586             $isValid = false;
1587          }
1588       }
1589       return $isValid;
1590    }
1591/******************************************************************************/
1592/* replace simple formats used by editor buttons
1593*/
1594    function xs_format($x_comment)
1595    { // bold , italic, underline, etc.
1596        $x_comment = preg_replace('/\[([bius])\]/i', '<\\1>', $x_comment);
1597        $x_comment = preg_replace('/\[\/([bius])\]/i', '</\\1>', $x_comment);
1598
1599        $x_comment = preg_replace('/\[ol\]/i', '<ol>', $x_comment);
1600        $x_comment = preg_replace('/\[\/ol\]/i', '</ol>', $x_comment);
1601
1602        $x_comment = preg_replace('/\[ul\]/i', '<ul>', $x_comment);
1603        $x_comment = preg_replace('/\[\/ul\]/i', '</ul>', $x_comment);
1604
1605        $x_comment = preg_replace('/\[li\]/i', '<li>', $x_comment);
1606        $x_comment = preg_replace('/\[\/li\]/i', '</li>', $x_comment);
1607
1608        $x_comment = preg_replace('/\[sup\]/i', '<sup>', $x_comment);
1609        $x_comment = preg_replace('/\[\/sup\]/i', '</sup>', $x_comment);
1610
1611        $x_comment = preg_replace('/\[sub\]/i', '<sub>', $x_comment);
1612        $x_comment = preg_replace('/\[\/sub\]/i', '</sub>', $x_comment);
1613
1614        $x_comment = preg_replace('/\[hr\]/i', '<hr>', $x_comment);
1615
1616        $x_comment = preg_replace('/\[blockquote\]/i', '<blockquote>', $x_comment);
1617        $x_comment = preg_replace('/\[\/blockquote\]/i', '</blockquote>', $x_comment);
1618
1619        $x_comment = preg_replace('/\[code\]/i', '<div class="it_code"><code>', $x_comment);
1620        $x_comment = preg_replace('/\[\/code\]/i', '</code></div>', $x_comment);
1621
1622        $x_comment = preg_replace('/\[red\]/i', '<span style="color:red;">', $x_comment);
1623        $x_comment = preg_replace('/\[\/red\]/i', '</span>', $x_comment);
1624
1625        $x_comment = preg_replace('/\[grn\]/i', '<span style="color:green;">', $x_comment);
1626        $x_comment = preg_replace('/\[\/grn\]/i', '</span>', $x_comment);
1627
1628        $x_comment = preg_replace('/\[bgy\]/i', '<span style="background:yellow;">', $x_comment);
1629        $x_comment = preg_replace('/\[\/bgy\]/i', '</span>', $x_comment);
1630
1631        $x_comment = preg_replace('/\[blu\]/i', '<span style="color:blue;">', $x_comment);
1632        $x_comment = preg_replace('/\[\/blu\]/i', '</span>', $x_comment);
1633
1634        $urlsuch[]="/([^]_a-z0-9-=\"'\/])((https?|ftp):\/\/|www\.)([^ \r\n\(\)\^\$!`\"'\|\[\]\{\}<>]*)/si";
1635        $urlsuch[]="/^((https?|ftp):\/\/|www\.)([^ \r\n\(\)\^\$!`\"'\|\[\]\{\}<>]*)/si";
1636        $urlreplace[]="\\1[link]\\2\\4[/link]";
1637        $urlreplace[]="[link]\\1\\3[/link]";
1638        $x_comment = preg_replace($urlsuch, $urlreplace, $x_comment);
1639        $x_comment = preg_replace("/\[link\]www.(.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"http://www.\\1\">www.\\1</a>", $x_comment);
1640        $x_comment = preg_replace("/\[link=www.(.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"http://www.\\1\">\\2</a>", $x_comment);
1641        $x_comment = preg_replace("/\[link\](\:.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\1</a>", $x_comment);
1642        $x_comment = preg_replace("/\[link=(\:.*?)\]\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\1</a>", $x_comment);
1643        $x_comment = preg_replace("/\[link=(\:.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\2</a>", $x_comment);
1644        $x_comment = preg_replace("/\[link\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"\\1\">\\1</a>", $x_comment);
1645        $x_comment = preg_replace("/\[link=(.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"\\1\">\\2</a>", $x_comment);
1646
1647        $x_comment = preg_replace("/\[img\](http.*?)\[\/img\]/si", "<img src=\"\\1\"title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1648        $x_comment = preg_replace("/\[img=(http.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1649        $x_comment = preg_replace("/\[img\](file.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1650        $x_comment = preg_replace("/\[img=(file.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1651        $x_comment = preg_replace("/\[img\](\:.*?)\[\/img\]/si", "<img src=\"". DOKU_URL . "lib/exe/fetch.php?media=\\1\" title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1652        $x_comment = preg_replace("/\[img=(\:.*?)\](.*?)\[\/img\]/si", "<img src=\"". DOKU_URL . "lib/exe/fetch.php?media=\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1653        $x_comment = preg_replace("/\[img\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment);
1654        $x_comment = preg_replace("/\[img=(.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" style=\"max-width:850px;\" \/>", $x_comment);
1655
1656
1657
1658/*---------------------------------------------------------------------------------
1659*  think about parsing content by dokuwiki renderer for dokuwiki syntax recognition
1660*        $x_comment = p_render('xhtml',p_get_instructions($x_comment),$info);
1661*        take care to strip IssueTracker syntax to prevent endless loop
1662---------------------------------------------------------------------------------*/
1663
1664      return $x_comment;
1665    }
1666/******************************************************************************/
1667/* return html-code for edit toolbar
1668*/
1669    function it_edit_toolbar($type) {
1670        $imgBASE = DOKU_BASE."lib/plugins/issuetracker/images/";
1671        $it_edit_tb  = '<div class="itr_edittoolbar">'.NL;
1672      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."bold.png\" name=\"btnBold\" title=\"Bold\" onClick=\"doAddTags('[b]','[/b]','$type')\">".NL;
1673        $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."italic.png\" name=\"btnItalic\" title=\"Italic\" onClick=\"doAddTags('[i]','[/i]','$type')\">".NL;
1674      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."underline.png\" name=\"btnUnderline\" title=\"Underline\" onClick=\"doAddTags('[u]','[/u]','$type')\">".NL;
1675      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."strikethrough.png\" name=\"btnStrike\" title=\"Strike through\" onClick=\"doAddTags('[s]','[/s]','$type')\">".NL;
1676      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."subscript.png\" name=\"btnSubscript\" title=\"Subscript\" onClick=\"doAddTags('[sub]','[/sub]','$type')\">".NL;
1677      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."superscript.png\" name=\"btnSuperscript\" title=\"Superscript\" onClick=\"doAddTags('[sup]','[/sup]','$type')\">".NL;
1678      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."hr.png\" name=\"btnLine\" title=\"hLine\" onClick=\"doHLine('[hr]','$type')\">".NL;
1679      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."ordered.png\" name=\"btn_o_List\" title=\"Ordered List\" onClick=\"doList('[ol]','[/ol]','$type')\">".NL;
1680      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."unordered.png\" name=\"btn_u_List\" title=\"Unordered List\" onClick=\"doList('[ul]','[/ul]','$type')\">".NL;
1681      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."quote.png\" name=\"btnQuote\" title=\"Quote\" onClick=\"doAddTags('[blockquote]','[/blockquote]','$type')\">".NL;
1682      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."code.png\" name=\"btnCode\" title=\"Code\" onClick=\"doAddTags('[code]','[/code]','$type')\">".NL;
1683      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_red.png\" name=\"btnRed\" title=\"Red\" onClick=\"doAddTags('[red]','[/red]','$type')\">".NL;
1684      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_green.png\" name=\"btnGreen\" title=\"Green\" onClick=\"doAddTags('[grn]','[/grn]','$type')\">".NL;
1685      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_blue.png\" name=\"btnBlue\" title=\"Blue\" onClick=\"doAddTags('[blu]','[/blu]','$type')\">".NL;
1686      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."bg_yellow.png\" name=\"btn_bgYellow\" title=\"bgYellow\" onClick=\"doAddTags('[bgy]','[/bgy]','$type')\">".NL;
1687      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."link.png\" name=\"btn_link\" title=\"Link\" onClick=\"doAddTags('[link]','[/link]','$type')\">".NL;
1688      	$it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."img.png\" name=\"btn_img\" title=\"Image - max width 850px\" onClick=\"doAddTags('[img]','[/img]','$type')\">".NL;
1689      	$it_edit_tb .= "<a href=\"http://www.imageshack.us/\" target=\"_blank\"><<img class=\"xseditor_button\" src=\"".$imgBASE."imageshack.png\" name=\"btn_ishack\" title=\"ImageShack upload (ext TaC !)\">></a>".NL;
1690        $it_edit_tb .= "<br></div>".NL;
1691        return $it_edit_tb;
1692    }
1693/******************************************************************************/
1694/* log issue modificaions
1695 * who changed what and when per issue
1696*/
1697    function _log_mods($project, $issue, $usr, $column, $new_value)
1698    {     global $conf;
1699          // get mod-log file contents
1700          if($this->getConf('it_data')==false) $modfile = DOKU_CONF."../data/meta/".$project.'_'.$issue_id.'.mod-log';
1701          else $modfile = DOKU_CONF."../". $this->getConf('it_data').$project.'_'.$issue_id.'.mod-log';
1702          if (@file_exists($modfile))
1703              {$mods  = unserialize(@file_get_contents($modfile));}
1704          else
1705              {$mods = array();}
1706
1707          $mod_id = count($mods);
1708
1709          $mods[$mod_id]['timestamp'] = date ($this->getConf('d_format'));
1710          $mods[$mod_id]['user'] = $usr;
1711          $mods[$mod_id]['field'] = $column;
1712          $mods[$mod_id]['old_value'] = $old_value;
1713          $mods[$mod_id]['new_value'] = $new_value;
1714
1715          // Save issues file contents
1716          $fh = fopen($modfile, 'w');
1717          fwrite($fh, serialize($mods));
1718          fclose($fh);
1719    }
1720/******************************************************************************/
1721/* replace special characters in file names like German "Umlaute"
1722*/
1723  function img_name_encode($f_name) {
1724      $umlaute = $this->getLang('umlaute');
1725      $replace = $this->getLang('conv_umlaute');
1726      if((count($umlaute)>1) && (count($replace)>1)) $f_name = preg_replace($umlaute, $replace, $f_name);
1727      $f_name = strtolower($f_name);
1728      return $f_name;
1729  }
1730/******************************************************************************/
1731/* upload a file if valid on mime type and file extension
1732*/
1733  function _symptom_file_upload(&$issues, $issue_id, $attachment_id) {
1734      global $conf;
1735      if($this->getConf('it_data')==false) $target_path = "data/meta/";
1736      else $target_path = $this->getConf('it_data');
1737      $ip_block_path = $target_path."ipblock";
1738      $target_path .= 'symptoms/';
1739      if(!is_dir(DOKU_CONF."../".$target_path)) { mkdir(DOKU_CONF."../".$target_path, 0777); }
1740
1741      $valid_file_extensions = array();
1742      $valid_mimetypes = array();
1743      $mimetypes = getMimeTypes();
1744
1745      foreach($mimetypes as $key => $value) {
1746          $valid_file_extensions[] = $key;
1747          $valid_mimetypes[] = $value;
1748      }
1749
1750      if($this->getConf('ip_blocked') == 1){
1751          $ip_blocked_sec = $this->getConf('ip_blockd_time')*60;
1752
1753          // search folder ipblock
1754          if(is_dir(DOKU_INC.$ip_block_path)) {
1755              $path = openDir(DOKU_INC.$ip_block_path);
1756              while(false !== ($filename = readdir($path))){
1757                  if($filename != "." && $filename != ".."){
1758                      // delete aged ipblocks
1759                      if(file_exists(DOKU_INC.$ip_block_path.'/'.$filename)) {
1760                          $t_check = filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec;
1761                          if($t_check <= time()) { @unlink(DOKU_INC.$ip_block_path.'/'.$filename); }
1762                      }
1763                  }
1764              }
1765              closedir($path);
1766          }
1767          else {
1768              mkdir(DOKU_INC.$ip_block_path.'/', 0777);
1769          }
1770
1771          $ip_addr = $_SERVER['REMOTE_ADDR'];
1772          if($ip_addr == "") {
1773            if(getenv(HTTP_X_FORWARDED_FOR)) { $ip_addr = getenv('HTTP_X_FORWARD_FOR'); }
1774            else { $ip_addr = getenv('REMOTE_ADDR'); }
1775          }
1776
1777          if($ip_addr != ""){
1778              // check if ip already known
1779              if(file_exists(DOKU_INC.$ip_block_path.'/'.$ip_addr)) {
1780                  // check upload remaining attempts (to be larger than 0)
1781                  $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "r");
1782                  $attachments_left=fread($iplog, filesize(DOKU_INC.$ip_block_path.'/'.$ip_addr));
1783                  fclose($iplog);
1784                  if($attachments_left<1) {
1785                    $error_code = 1;
1786                    $t_check = intval((filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec-time())/60);
1787                    msg(sprintf($this->getLang('wmsg9'), $t_check),-1);
1788                  }
1789              }
1790              else $attachments_left = 3;
1791          }
1792      }
1793
1794      if(isset($error_code)){
1795        $t_check = intval((filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec-time())/60);
1796        $Generated_Header = '<div class="it__negative_feedback">'.sprintf($this->getLang('wmsg9'), $t_check).'</div>';
1797        $renderer->doc .= $Generated_Header;
1798        return;
1799      }
1800
1801      // get file extension
1802      $mime_type = $_FILES[$attachment_id]['type'];
1803      $file_extension = strrchr($_FILES[$attachment_id]['name'],'.'); // last occurance of dot to detect extension
1804      $file_dot_extension = strtolower($file_extension);
1805      $file_extension = str_replace(".", "", strtolower($file_dot_extension));
1806      $error_flag = 0;
1807
1808      // check validity of file extension
1809      if(!in_array($file_extension, $valid_file_extensions)) {
1810        $error_flag = 1;
1811        $Generated_Header .= '<span>'.$this->getLang('wmsg7').' (File: <b>'.$_FILES[$attachment_id]['name'].'</b>)</span><br>';
1812      }
1813      // check mime type
1814      if((!in_array($mime_type, $valid_mimetypes)) && (!in_array("!".$mime_type, $valid_mimetypes)) ) {
1815        $error_flag = 1;
1816        $Generated_Header .= '<span>'.$this->getLang('wmsg8').' (File: <b>'.$_FILES[$attachment_id]['name'].', Mime-Type: '.$mime_type.'</b>)</span><br>';
1817      }
1818      // check file-size
1819      if($_FILES[$attachment_id]['size'] > ($this->getConf('max_fsize'))){
1820          $error_flag = 1;
1821          $Generated_Header .= '<span>'.sprintf($this->getLang('wmsg6'), $this->getConf('max_fsize')).' (File: <b>'.$_FILES[$attachment_id]['name'].'</b>)</span><br>';
1822      }
1823// -----------------------------------------------------------------------------
1824    if($error_flag > 0) {
1825      echo $Generated_Header = '<div class="it__negative_feedback">'.$Generated_Header.'</div>';
1826    }
1827    else {
1828      //$safe_filename = preg_replace(array("/\s+/", "/[^-\.\w]+/"),array("_", ""),trim(basename( $_FILES[$attachment_id]['name'])));
1829      // delete all other characters beside the following defined
1830      $safe_filename = preg_replace('#[^A-Za-z0-9_.-]#', '',trim(basename( $_FILES[$attachment_id]['name'])));
1831      $target_path = $target_path . $issue_id . '_sympt_' . $safe_filename;
1832      if(move_uploaded_file($_FILES[$attachment_id]['tmp_name'], DOKU_INC.$target_path)) {
1833          $attachments_left = $attachments_left-1;
1834          $issues[$issue_id]['attachment1'] = DOKU_URL.$target_path;
1835//          msg("The file ".$safe_filename." has been successfully uploaded to ".DOKU_URL.$target_path,1);
1836          msg("The file ".$safe_filename." has been successfully uploaded.",1);
1837      } else{
1838//          msg("There was an error uploading the file to ".DOKU_URL.$target_path." \n, please try again!",-1);
1839          msg("There was an error uploading the file, please try again!",-1);
1840      }
1841// -----------------------------------------------------------------------------
1842      // block ip
1843      if($this->getConf('ip_blocked') == 1) {
1844              $ip_addr=$_SERVER['REMOTE_ADDR'];
1845              if($ip_addr==""){
1846                  if(getenv(HTTP_X_FORWARDED_FOR)) { $ip_addr = getenv('HTTP_X_FORWARD_FOR'); }
1847                  else { $ip_addr = getenv('REMOTE_ADDR'); }
1848              }
1849              if(!is_dir(DOKU_INC.$ip_block_path) && ($ip_addr != "")) {
1850                  @mkdir(DOKU_INC.$ip_block_path.'/', 0777);
1851                  $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "w+");
1852                  fwrite($iplog, $attachments_left);
1853                  fclose($iplog);
1854                  }
1855              elseif($ip_addr != ""){
1856                  $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "w+");
1857                  fwrite($iplog, $attachments_left);
1858                  fclose($iplog);
1859              }
1860          }
1861    }
1862// -----------------------------------------------------------------------------
1863    return $Generated_Header;
1864  }
1865/******************************************************************************/
1866  function __find_projects($path) {
1867    if(!is_dir($path))  return false;  // prevent the php-warning
1868    if ($handle=opendir($path)) {
1869      while (false!==($file=readdir($handle))) {
1870        if ($file<>"." AND $file<>"..") {
1871          if (is_file($path.'/'.$file)) {
1872            $ext = explode('.',$file);
1873            $last = count($ext) - 1;
1874	          if ($ext[$last] == 'issues') {
1875              $projects .= ','.substr($file,0,strlen($file)-strlen('.issues'));
1876            }
1877          }
1878        }
1879      }
1880    }
1881    return $projects;
1882  }
1883/******************************************************************************/
1884/*
1885 * Check for MyIssues
1886 *
1887 * Check if the issue is related to the current user
1888 * the user maybe the issue reporter, assignee or registered as follower
1889 * it will return true/false
1890 *
1891 * @author   Taggic <taggic@t-online.de>
1892 * @param    array $issue the single issue
1893 * @param    array $user the current user info
1894 * @return   bool       true if foo in bar
1895 *
1896 */
1897
1898  function _find_myissues($issue, $user) {
1899      // current user is issue reporter
1900      if($user['userinfo']['mail'] === $issue['user_mail']) return true;
1901
1902      // current user is assigned to this issue
1903      if($user['userinfo']['mail'] === $issue['assigned']) return true;
1904
1905      // current user is registered as follower within the comments log of actual issue
1906      if(stristr($issue['add_user_mail'],$user['userinfo']['mail']) !== false) return true;
1907
1908      // else return false
1909       return false;
1910  }
1911/******************************************************************************/
1912/*
1913 * Load all issues into an array
1914 *
1915 * Check if multi_project is set to true
1916 * Load current $project or all projects of it_data_store
1917 * Return the issues array
1918 *
1919 * @author   Taggic <taggic@t-online.de>
1920 * @param    array $data
1921 * @return   $issues
1922 *
1923 */
1924
1925  function _get_issues($data, $all = false) {
1926    // detect the IssueTracker data store (path)
1927    if($this->getConf('it_data')==false) $it_datastore = DOKU_CONF."../data/meta/";
1928    else $it_datastore = DOKU_CONF."../". $this->getConf('it_data');
1929
1930    // check if last sign is a slash
1931    $i = strrchr ($it_datastore, chr(47));     // chr(47) = "/"
1932    $j = strrchr ($it_datastore, chr(92));     // chr(92) = "\"
1933    if(($i !== strlen($it_datastore)) && ($i !== strlen($it_datastore))) { $it_datastore .= chr(47); }
1934
1935    if(($this->getConf('multi_projects')!==false) && ($all !== false)) {
1936        // loop through it_datastore and list all .issues files
1937        $xprojects = $this->__find_projects($it_datastore);
1938
1939        $x_projects = explode(',',$xprojects);
1940        $issues = array();
1941        $tmp    = array();
1942
1943        foreach ($x_projects as $project)
1944        {   $project = trim($project);
1945            if(is_file($it_datastore.$project.'.issues') == true) {
1946                $tmp = unserialize(@file_get_contents($it_datastore.$project.'.issues'));
1947
1948                // loop through the field and add project to each row
1949                foreach($tmp as &$tmps)
1950                {   $tmps['project'] = $project; }
1951
1952                $issues = array_merge($issues, $tmp);
1953                $tmp = array();
1954            }
1955        }
1956    }
1957    else {
1958        // get issues from single project file
1959        if($this->getConf('it_data')==false) $pfile = $it_datastore.$data['project'].'.issues';
1960        else $pfile = $it_datastore.$data['project'].'.issues';
1961
1962        if (@file_exists($pfile))
1963        	{$issues  = unserialize(@file_get_contents($pfile));}
1964        else
1965        	{$issues = array();}
1966        }
1967
1968    return $issues;
1969  }
1970/******************************************************************************/
1971/* sort the issues array according the selected key                           */
1972    function _issues_globalsort($issues, $sort_key) {
1973/*        $tmp = Array();
1974        foreach($issues as &$ma)  $tmp[] = &$ma[$sort_key];
1975        array_multisort($tmp, $issues);                          */
1976        foreach ($issues as $key => $row) {
1977            $down[$key]    = $row['id'];
1978            $up[$key]      = $row[$sort_key];
1979        }
1980        if($up) { @array_multisort($up, constant($this->getConf('global_sort')), $down, SORT_ASC, $issues); }
1981        return $issues;
1982    }
1983}
1984