Main Page | Directories | File List | File Members

trackers/general.php

Go to the documentation of this file.
00001 <?php
00002 # This file is part of the Savane project
00003 # <http://gna.org/projects/savane/>
00004 #
00005 # $Id: general.php 5460 2006-02-20 15:08:43Z yeupou $
00006 #
00007 #  Copyright 1999-2000 (c) The SourceForge Crew
00008 #  Copyright 2001-2002 (c) Laurent Julliard, CodeX Team, Xerox
00009 #
00010 #  Copyright 2003-2006 (c) Mathieu Roy <yeupou--gnu.org>
00011 #                          Yves Perrin <yves.perrin--cern.ch>
00012 #
00013 #
00014 # The Savane project is free software; you can redistribute it and/or
00015 # modify it under the terms of the GNU General Public License
00016 # as published by the Free Software Foundation; either version 2
00017 # of the License, or (at your option) any later version.
00018 #
00019 # The Savane project is distributed in the hope that it will be useful,
00020 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 # GNU General Public License for more details.
00023 #
00024 # You should have received a copy of the GNU General Public License
00025 # along with the Savane project; if not, write to the Free Software
00026 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00027 
00028 
00029 # Return the file that should be included, according to the URL
00030 # requested. If the file start with ?, it's an index.
00031 function trackers_include()
00032 {
00033   # Keep the dirname only if it's admin
00034   $dir = get_module_include_dir($GLOBALS['PHP_SELF'], 0, 1);
00035   if ($dir != "admin")
00036     {
00037       unset($dir);
00038     }
00039   else
00040     {
00041       $dir = $dir."/";
00042       $pre = "../";
00043     }
00044 
00045   return $pre."../include/trackers_run/".$dir.basename($GLOBALS['PHP_SELF']);
00046 }
00047 
00048 # Does like trackers_include() but load an arbitrary page of the common
00049 # tracker code. This is useful for trackers that have non-standard behavior
00050 # needs to present some standard page inside a non standard location
00051 function trackers_bastardinclude($page, $is_admin_page='0')
00052 {
00053   unset($pre);
00054   if ($is_admin_page)
00055     {
00056       $pre = "../";
00057     }
00058 
00059   return $pre."../include/trackers_run/".$page.".php";
00060 }
00061 
00062 
00063 # Generate URL arguments from a variable wether scalar or array
00064 function trackers_convert_to_url_arg($varname, $var)
00065 {
00066 
00067   if (is_array($var))
00068     {
00069       reset($var);
00070       while (list(,$v) = each($var))
00071         {
00072           $ret .= '&'.$varname.'[]='.$v;
00073         }
00074     }
00075   else
00076     {
00077       $ret .= '&'.$varname.'='.$var;
00078     }
00079   return $ret;
00080 }
00081 
00082 function trackers_header($params)
00083 {
00084   global $group_id,$is_bug_page,$DOCUMENT_ROOT,$advsrch;
00085 
00086   #used so the search box will add the necessary element to the pop-up box
00087   # yeupou, 2005-09-11: is that still useful?
00088   $is_bug_page=1;
00089 
00090   #required params for site_project_header();
00091   $params['group']=$group_id;
00092   $params['context']=ARTIFACT;
00093 
00094   $project=project_get_object($group_id);
00095 
00096   #needs to be turned  on
00097   if (ARTIFACT == "bugs"  && !$project->Uses("bugs") ||
00098       ARTIFACT == "support" &&  !$project->Uses("support") ||
00099       ARTIFACT == "task" && !$project->Uses("task") ||
00100       ARTIFACT == "patch" && !$project->Uses("patch"))
00101     {
00102       exit_error(_("This project has turned off this tracker."));
00103     }
00104   print site_project_header($params);
00105 
00106 }
00107 
00108 function trackers_header_admin($params)
00109 {
00110   global $group_id,$is_bug_page,$DOCUMENT_ROOT;
00111 
00112   #used so the search box will add the necessary element to the pop-up box
00113   $is_bug_page=1;
00114 
00115   #required params for site_project_header();
00116   $params['group']=$group_id;
00117   $params['context']='a'.ARTIFACT;
00118 
00119   $project=project_get_object($group_id);
00120 
00121   # need to be turned on
00122   if (ARTIFACT == "bugs"  && !$project->Uses("bugs") ||
00123       ARTIFACT == "support" &&  !$project->Uses("support") ||
00124       ARTIFACT == "task" && !$project->Uses("task") ||
00125       ARTIFACT == "patch" && !$project->Uses("patch"))
00126     {
00127       exit_error(_("This project has turned off this tracker."));
00128     }
00129   print site_project_header($params);
00130 }
00131 
00132 function trackers_footer($params)
00133 {
00134   site_project_footer($params);
00135 }
00136 
00137 function trackers_init($group_id)
00138 {
00139   # Set the global arrays for faster processing at init time
00140   trackers_data_get_all_fields($group_id, true);
00141 }
00142 
00143 function trackers_report_init($group_id, $report_id)
00144 {
00145   # Set the global array with report information for faster processing
00146   trackers_data_get_all_report_fields($group_id, $report_id, true);
00147 }
00148 
00149 function trackers_list_all_fields($sort_func=false,$by_field_id=false)
00150 {
00151   global $BF_USAGE_BY_ID, $BF_USAGE_BY_NAME, $AT_START;
00152 
00153   # If its the first element we fetch then apply the sort
00154   # function
00155   if ($AT_START)
00156     {
00157       if (!$sort_func)
00158         { $sort_func = cmp_place; }
00159       uasort($BF_USAGE_BY_ID, $sort_func);
00160       uasort($BF_USAGE_BY_NAME, $sort_func);
00161       $AT_START=false;
00162     }
00163 
00164   # return the next bug field in the list. If the global
00165   # bug field usage array is not set then set it the
00166   # first time.
00167   # by_field_id: true return the list of field id, false returns the
00168   # list of field names
00169 
00170   if ( list($key, $field_array) = each($BF_USAGE_BY_ID))
00171     {
00172       return($by_field_id ? $field_array['bug_field_id'] : $field_array['field_name']);
00173     }
00174   else
00175     {
00176       # rewind internal pointer for next time
00177       reset($BF_USAGE_BY_ID);
00178       reset($BF_USAGE_BY_NAME);
00179       $AT_START=true;
00180       return(false);
00181     }
00182 }
00183 
00184 function trackers_field_label_display ($field_name, $group_id,$break=false,$ascii=false, $tab=25)
00185 {
00186   $label = trackers_data_get_label($field_name).':';
00187 
00188   if (!$ascii)
00189     { $output = '<span class="preinput"><span class="help" title="'.trackers_data_get_description($field_name).'">'.$label.'</span></span>'; }
00190 
00191   if ($break)
00192     { $output .= ($ascii?"\n":'<br />'); }
00193   else
00194     {
00195       if (!$ascii)
00196         { $output .= '&nbsp;'; }
00197       else
00198         {
00199           $output .= sprintf("%".$tab."s", $label).' ';
00200         }
00201      }
00202 
00203   return $output;
00204 }
00205 
00206 function trackers_field_display ($field_name,
00207                                  $group_id,
00208                                  $value='xyxy',
00209                                  $break=false, #4
00210                                  $label=true,
00211                                  $ro=false, #6
00212                                  $ascii=false,
00213                                  $show_none=false, #8
00214                                  $text_none='None',
00215                                  $show_any=false, #10
00216                                  $text_any='Any',
00217                                  $allowed_transition_only=false, #12
00218                                  $show_unknown=false,
00219                                  $tab=25)
00220 {
00221   /*
00222           Display a bug field either as a read-only value or as a read-write
00223           making modification possible
00224           - field_name : name of the bug field (column name)
00225           - group_id : the group id (project id)
00226           - value: the current value stored in this field (for select boxes type of field
00227                   it is the value_id actually. It can also be an array with mutliple values.
00228           - break: true if a break line is to be inserted between the field label
00229                  and the field value
00230           - label: if true display the field label.
00231           - ro: true if only the field value is to be displayed. Otherwise
00232                  display an HTML select box, text field or text area to modify the value
00233           - ascii: if true do not use any HTML decoration just plain text (if true
00234                  then read-only (ro) flag is forced to true as well)
00235           - show_none: show the None entry in the select box if true (value_id 100)
00236           - text_none: text associated with the none value_id to display in the select box
00237           - show_any: show the Any entry in the select box if true (value_id 0)
00238           - text_any: text associated with the any value_id  tp display in the select box
00239           - allowed_transition_only: print only transition allowed
00240   */
00241 
00242   global $sys_datefmt;
00243 
00244   if ($label)
00245     {
00246       $output = trackers_field_label_display($field_name,
00247                                              $group_id,
00248                                              $break,
00249                                              $ascii,
00250                                              $tab);
00251     }
00252 
00253   # display depends upon display type of this field
00254   switch (trackers_data_get_display_type($field_name))
00255     {
00256 
00257     case 'SB':
00258       if ($ro)
00259         {
00260 
00261           # if multiple selected values return a list of <br /> separated values
00262           $arr = ( is_array($value) ? $value : array($value));
00263           for ($i=0;$i < count($arr); $i++)
00264             {
00265               if ($arr[$i] == 0 )
00266                 { $arr[$i] = $text_any; }
00267               else if ($arr[$i] == 100 && $field_name != 'percent_complete')
00268                 { $arr[$i] = $text_none; }
00269               else
00270                 { $arr[$i] = trackers_data_get_value($field_name,$group_id,$arr[$i]); }
00271             }
00272           $output .= join('<br />', $arr);
00273 
00274         }
00275       else
00276         {
00277           # If it is a user name field (assigned_to, submitted_by) then make
00278           # sure to add the "None" entry in the menu 'coz it's not in the DB
00279           if (trackers_data_is_username_field($field_name))
00280             {
00281               $show_none=true;
00282               $text_none='None';
00283             }
00284 
00285           if (is_array($value))
00286             {
00287               $output .= trackers_multiple_field_box($field_name,'',$group_id, $value,
00288                                                      $show_none,$text_none,$show_any,
00289                                                      $text_any);
00290             }
00291           else
00292             {
00293               $output .= trackers_field_box($field_name,
00294                                             '',
00295                                             $group_id,
00296                                             $value, #4
00297                                             $show_none,
00298                                             $text_none,
00299                                             $show_any,
00300                                             $text_any, #8
00301                                             $allowed_transition_only,
00302                                             $show_unknown);
00303             }
00304         }
00305       break;
00306 
00307     case 'DF':
00308       if ($ascii)
00309         {
00310           $output .= ( ($value == 0) ? '' : format_date($sys_datefmt,$value));
00311         }
00312       else
00313         {
00314           if ($ro)
00315             { $output .= format_date($sys_datefmt,$value); }
00316         else
00317           {
00318             $output .= trackers_field_date($field_name,
00319                                            (($value == 0) ? '' : strftime("%Y-%m-%d",$value)));
00320           }
00321         }
00322       break;
00323 
00324     case 'TF':
00325       if ($ascii)
00326         { $output .= utils_unconvert_htmlspecialchars($value); }
00327       else
00328         { $output .= ($ro ? $value: trackers_field_text($field_name,$value)); }
00329       break;
00330 
00331     case 'TA':
00332       if ($ascii)
00333         { $output .= utils_unconvert_htmlspecialchars($value); }
00334       else
00335         { $output .= ($ro ? nl2br($value):trackers_field_textarea($field_name,$value)); }
00336       break;
00337 
00338     default:
00339       $output .= 'Unknown '.ARTIFACT.' Field Display Type';
00340     }
00341 
00342   return($output);
00343 }
00344 
00345 function trackers_field_date($field_name,$value='',$size=0,$maxlength=0,$ro=false)
00346 {
00347 
00348   # value is formatted as Y-m-d
00349   list($year, $month, $day) = split("-", $value);
00350 
00351   if ($ro)
00352     {
00353       $html = $value;
00354     }
00355   else
00356     {
00357       if (!$size || !$maxlength)
00358         { list($size, $maxlength) = trackers_data_get_display_size($field_name);
00359     }
00360 
00361       # date part are missing, take the date of the day
00362       $today = localtime();
00363       if (!$day)
00364         { $day = ($today[3]); }
00365       if (!$month)
00366         { $month = ($today[4]+1); }
00367       if (!$year)
00368         { $year = ($today[5]+1900); }
00369 
00370       # FIXME: order of year/day/month must be local specific
00371       $html = calendar_selectbox("day", $day, $field_name.'_dayfd').calendar_selectbox("month", $month, $field_name.'_monthfd').' <input type="text" name="'.$field_name.'_yearfd" size="4" maxlength="4" value="'.$year.'" />';
00372     }
00373   return($html);
00374 
00375 }
00376 
00377 function trackers_multiple_field_date($field_name,$date_begin='',$date_end='',$size=0,$maxlength=0,$ro=false)
00378 {
00379 
00380   # CAUTION!!!! The Javascript below assumes that the date always appear
00381   # in a field called 'bug_form'
00382 
00383   # FIXME: this is broken, should be made as trackers_field_date
00384 
00385   if ($ro)
00386     if ($date_begin || $date_end)
00387       $html = "Start:&nbsp;$date_begin<br />End:&nbsp;$date_end";
00388     else
00389       $html = 'Any time';
00390   else
00391     {
00392       if (!$size || !$maxlength)
00393         list($size, $maxlength) = trackers_data_get_display_size($field_name);
00394 
00395       $html = 'Start:<br /><input type="text" name="'.$field_name.
00396          '" size="'.$size.'" MAXLENGTH="'.$maxlength.'" VALUE="'.$date_begin.'">'.
00397          '<a href="javascript:show_calendar(\'document.bug_form.'.$field_name.'\', document.bug_form.'.$field_name.'.value);">'.
00398          '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/task.png" border="0" alt="'._("Click Here to Pick up a date").'" /></a>'.
00399          '</td></tr><tr><td>'.
00400          'End:<br /><INPUT TYPE="text" name="'.$field_name.'_end'.
00401          '" size="'.$size.'" MAXLENGTH="'.$maxlength.'" VALUE="'.$date_end.'">'.
00402          '<a href="javascript:show_calendar(\'document.bug_form.'.$field_name.'_end\', document.bug_form.'.$field_name.'_end.value);">'.
00403          '<img src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/task.png" border="0" alt="'._("Click Here to Pick up a date").'" /></a>';
00404 
00405       $html = '<table><tr><td>'.$html.'</td></tr></table>';
00406     }
00407 
00408   return($html);
00409 
00410 }
00411 
00412 function trackers_field_date_operator($field_name,$value='',$ro=false)
00413 {
00414 
00415   if ($ro)
00416     $html = htmlspecialchars($value);
00417   else
00418     $html = '<SELECT name="'.$field_name.'_op">'.
00419       '<OPTION VALUE=">"'.(($value == '>') ? ' SELECTED':'').'>&gt;</OPTION>'.
00420       '<OPTION VALUE="="'.(($value == '=') ? ' SELECTED':'').'>=</OPTION>'.
00421       '<OPTION VALUE="<"'.(($value == '<') ? ' SELECTED':'').'>&lt;</OPTION>'.
00422       '</SELECT>';
00423   return($html);
00424 
00425 }
00426 
00427 function trackers_field_text($field_name,$value='',$size=0,$maxlength=0)
00428 {
00429 
00430   if (!$size || !$maxlength)
00431     list($size, $maxlength) = trackers_data_get_display_size($field_name);
00432 
00433   $html = '<input type="text" name="'.$field_name.
00434      '" size="'.$size.'" maxlength="'.$maxlength.'" value="'.$value.'" />';
00435   return($html);
00436 
00437 }
00438 
00439 function trackers_field_textarea($field_name,$value='',$cols=0,$rows=0)
00440 {
00441 
00442   if (!$cols || !$rows)
00443     {
00444       list($cols, $rows) = trackers_data_get_display_size($field_name);
00445 
00446       # Nothing defined for this field? Use hardcoded default values
00447       if (!$cols || !$rows)
00448         {
00449           $cols = "65";
00450           $rows = "16";
00451         }
00452     }
00453 
00454   $html = '<textarea name="'.$field_name.
00455      '" rows="'.$rows.'" cols="'.$cols.'" wrap="soft">'.$value.'</textarea>';
00456   return($html);
00457 
00458 }
00459 
00460 function trackers_field_box ($field_name,
00461                              $box_name='',
00462                              $group_id,
00463                              $checked=false, #4
00464                              $show_none=false,
00465                              $text_none='None',
00466                              $show_any=false,
00467                              $text_any='Any', #8
00468                              $allowed_transition_only=false,
00469                              $show_unknown=false)
00470 {
00471 
00472   # Returns a select box populated with field values for this project
00473   # if box_name is given then impose this name in the select box
00474   # of the  HTML form otherwise use the field_name
00475   if (!$group_id)
00476     { return _('Error: no group defined'); }
00477   else
00478     {
00479       $result = trackers_data_get_field_predefined_values($field_name,$group_id,$checked);
00480 
00481       if ($box_name == '')
00482         { $box_name = $field_name; }
00483 
00484       if ($allowed_transition_only)
00485         {
00486           # yeupou--gnu.org 2004-09-12: where the hell is by_field_id set?
00487           $field_id = ($by_field_id ? $field_name : trackers_data_get_field_id($field_name));
00488 
00489           # first check if group has defined transitions for this field
00490           $default_auth = db_result(db_query("SELECT transition_default_auth ".
00491                                              "FROM ".ARTIFACT."_field_usage ".
00492                                              "WHERE group_id='$group_id' AND bug_field_id='$field_id'"), 0, 'transition_default_auth');
00493           # avoid corrupted database content, if its not F, it must be A.
00494           if ($default_auth != "F")
00495             { $default_auth = "A"; }
00496 
00497           $sql="SELECT from_value_id,to_value_id,is_allowed,notification_list ".
00498              "FROM trackers_field_transition ".
00499              "WHERE group_id='$group_id' AND artifact='".ARTIFACT."' AND field_id='$field_id' AND (from_value_id='$checked' OR from_value_id='0')";
00500 
00501           $trans_result = db_query($sql);
00502           $forbidden_to_id = array();
00503           $allowed_to_id = array();
00504           $rows = db_numrows($trans_result);
00505           if ($trans_result && $rows > 0 || $default_auth == "F")
00506             {
00507               while ($transition = db_fetch_array($trans_result))
00508                 {
00509                   if ($transition['is_allowed'] == 'F')
00510                     {
00511                       $forbidden_to_id[$transition['to_value_id']] = 0;
00512                     }
00513                   else
00514                     {
00515                       $allowed_to_id[$transition['to_value_id']] = 0;
00516                     }
00517                 }
00518 
00519               # get all the predefined values for this field
00520               $rows=db_numrows($result);
00521 
00522               if ($rows > 0) {
00523                 $val_label = array();
00524                 while ($val_row = db_fetch_array($result))
00525                   {
00526                     $value_id = $val_row['value_id'];
00527                     $value   = $val_row['value'];
00528                     if ((($default_auth == 'A') && (!array_key_exists($value_id, $forbidden_to_id))) ||
00529                         (($default_auth == 'F') && (array_key_exists($value_id, $allowed_to_id))) ||
00530                         ($value_id == $checked))
00531                       {
00532                         $val_label[$value_id] = $value;
00533                       }
00534                   }
00535 
00536                 # always add the any values cases
00537                 return html_build_select_box_from_arrays(array_keys($val_label),
00538                                                          array_values($val_label),
00539                                                          $box_name,
00540                                                          $checked, #4
00541                                                          $show_none,
00542                                                          $text_none, #6
00543                                                          $show_any,
00544                                                          $text_any, #8
00545                                                          $show_unknown);
00546           }
00547         }
00548       }
00549 
00550 # if no transition defined use 'normal' code
00551 
00552       return html_build_select_box ($result,$box_name,$checked,$show_none,$text_none,$show_any, $text_any,$show_unknown);
00553 
00554     }
00555 }
00556 
00557 function trackers_multiple_field_box($field_name,
00558                                      $box_name='',
00559                                      $group_id,
00560                                      $checked=false,
00561                                      $show_none=false,
00562                                      $text_none='None',
00563                                      $show_any=false,
00564                                      $text_any='Any',
00565                                      $show_value=false)
00566 {
00567   # Returns a multiplt select box populated with field values for this project
00568   # if box_name is given then impose this name in the select box
00569   # of the  HTML form otherwise use the field_name
00570 
00571   if (!$group_id)
00572     { return _("Internal error: no group id"); }
00573   else
00574     {
00575       $result = trackers_data_get_field_predefined_values($field_name,$group_id,$checked);
00576 
00577       if ($box_name == '')
00578         {
00579           $box_name = $field_name.'[]';
00580         }
00581       return html_build_multiple_select_box($result,$box_name,$checked,6,$show_none,$text_none, $show_any,$text_any,$show_value);
00582     }
00583 }
00584 
00585 # Similar to trackers_multiple_field_box except that it will use checkboxes
00586 # instead of a multiple select field. Multiple select field is nice for
00587 # expert users, but it is not simple user-friendly, unlike checkboxes.
00588 function trackers_multiple_field_box2 ($field_name,
00589                                        $box_name='',
00590                                        $group_id,
00591                                        $checked=false,
00592                                        $show_none=false,
00593                                        $text_none='None',
00594                                        $show_any=false,
00595                                        $text_any='Any',
00596                                        $show_value=false)
00597 {
00598   if (!$group_id)
00599     { return _("Internal error: no group id"); }
00600   else
00601     {
00602       $result = trackers_data_get_field_predefined_values($field_name,$group_id,$checked);
00603 
00604       if ($box_name == '')
00605         {
00606           $box_name = $field_name.'[]';
00607         }
00608       return html_build_checkbox($result,$box_name,$checked,6,$show_none,$text_none, $show_any,$text_any,$show_value);
00609     }
00610 
00611 
00612 }
00613 
00614 function trackers_extract_field_list($post_method=true)
00615 {
00616 
00617   global $HTTP_GET_VARS, $HTTP_POST_VARS, $BF_USAGE_BY_NAME;
00618   /*
00619        Returns the list of field names in the HTML Form corresponding to a
00620        field used by this project
00621   */
00622 
00623   # Specific: it must build the date fields if it finds _dayfd, _monthfd
00624   # or _yearfd, because date fields comes from 3 separated input.
00625   $vfl = array();
00626   $date = array();
00627   if ($post_method)
00628     {
00629       reset($HTTP_POST_VARS);
00630       while ( list($key, $val) = each($HTTP_POST_VARS))
00631         {
00632           if (preg_match("/^(.*)_(day|month|year)fd$/", $key, $found))
00633             {
00634               # Must build the date field key.
00635               $field_name = $found[1];
00636               $field_name_part = $found[2];
00637 
00638               # We also must increment $day and $month, because the select
00639               # start from zero
00640 
00641               # get what we already have
00642               list($year, $month, $day) = split("-", $vfl[$field_name]);
00643               if ($field_name_part  == 'day')
00644                 { $vfl[$field_name] = "$year-$month-$val"; }
00645               elseif ($field_name_part == 'month')
00646                 { $vfl[$field_name] = "$year-$val-$day"; }
00647               elseif ($field_name_part == 'year')
00648                 { $vfl[$field_name] = "$val-$month-$day"; }
00649             }
00650           elseif (isset($BF_USAGE_BY_NAME[$key]) || $key == 'comment')
00651             {
00652               $vfl[$key] = $val;
00653             }
00654           else
00655             {
00656               dbg("Rejected key = ".$key." val = $val");
00657             }
00658         }
00659     }
00660   else
00661     {
00662       reset($HTTP_GET_VARS);
00663       while ( list($key, $val) = each($HTTP_GET_VARS))
00664         {
00665           if (preg_match("/^(.*)_(day|month|year)fd$/", $key, $found))
00666             {
00667               # Must build the date field key.
00668               $field_name = $found[1];
00669               $field_name_part = $found[2];
00670 
00671               # get what we already have
00672               list($year, $month, $day) = split("-", $vfl[$field_name]);
00673               if ($field_name_part  == 'day')
00674                 { $vfl[$field_name] = "$year-$month-$val"; }
00675               elseif ($field_name_part == 'month')
00676                 { $vfl[$field_name] = "$year-$val-$day"; }
00677               elseif ($field_name_part == 'year')
00678                 { $vfl[$field_name] = "$val-$month-$day"; }
00679             }
00680           elseif (isset($BF_USAGE_BY_NAME[$key]) || $key == 'comment')
00681             {
00682               $vfl[$key] = $val;
00683             }
00684           else
00685             {
00686               dbg("Rejected key = ".$key." val = $val");
00687             }
00688         }
00689 
00690     }
00691   return($vfl);
00692 }
00693 
00694 # Check whether a field was shown to the submitter
00695 # (useful if a field is mandatory if shown to the submitter)
00696 function trackers_check_is_shown_to_submitter ($field_name, $group_id, $submitter_id)
00697 {
00698   if ($submitter_id == 100)
00699     {
00700       # Anonymous user
00701       if (trackers_data_is_showed_on_add_nologin($field_name))
00702         { return true; }
00703     }
00704   else
00705     {
00706       if (!member_check($submitter_id, $group_id))
00707         {
00708           # Not a member of the group
00709           if (trackers_data_is_showed_on_add($field_name))
00710             { return true; }
00711         }
00712       else
00713         {
00714           # Group member
00715           if (trackers_data_is_showed_on_add_members($field_name))
00716             { return true; }
00717         }
00718     }
00719 
00720   # if we reach this point, it was not mandatory
00721   return false;
00722 }
00723 
00724 
00725 function trackers_check_empty_fields($field_array, $new_item=true)
00726 {
00727   # Check whether empty values are allowed for the bug fields
00728   # field_array: associative array of field_name -> value
00729   unset($previous_form_bad_fields);
00730   global $previous_form_bad_fields;
00731   $previous_form_bad_fields = array();
00732 
00733 
00734   reset($field_array);
00735   while (list($field_name, $val) = each($field_array))
00736     {
00737       # Only the field percent_complete is allowed to use the special value
00738       # hundred.
00739       # FIXME: maybe it should not use that value at all, however it would
00740       # require one more database migration. Something that should indeed be
00741       # done if at some point we feel the need for one more exception.
00742       if ($field_name == "percent_complete")
00743         { continue; }
00744 
00745       # Check if it is empty
00746       $is_empty = (trackers_data_is_select_box($field_name) ? ($val==100) : ($val==''));
00747       if (!$is_empty)
00748         { continue; }
00749 
00750       # Check if it is mandatory
00751       $mandatory_flag = trackers_data_mandatory_flag($field_name);
00752       unset($is_mandatory);
00753       if ($mandatory_flag == 1)
00754         {
00755           # Not mandatory
00756           continue;
00757         }
00758       elseif ($mandatory_flag == 3)
00759         {
00760           # Mandatory whenever possible
00761           $is_mandatory = 1;
00762         }
00763       elseif ($new_item)
00764         {
00765           # Mandatory when shown to the submitter while we are creating
00766           # a new item.
00767           # ($mandatory_flag = 0)
00768           $is_mandatory = 1;
00769         }
00770       else
00771         {
00772           # Mandatory when shown to the submitter, we are updating an item
00773           # ($mandatory_flag = 0)
00774 
00775           global $item_id, $group_id, $mandatorycheck_submitter_id;
00776           if (!$mandatorycheck_submitter_id)
00777             {
00778               # Save that information for further mandatory checks,
00779               # to avoid avoid a SQL request per field checked
00780               $submitter_sql = "SELECT submitted_by FROM ".ARTIFACT." WHERE bug_id='$item_id' AND group_id='$group_id'";
00781               $submitter_res = db_query($submitter_sql);
00782               $mandatorycheck_submitter_id = db_result($submitter_res,0,'submitted_by');
00783             }
00784 
00785           if (trackers_check_is_shown_to_submitter($field_name, $group_id, $mandatorycheck_submitter_id))
00786             {
00787               $is_mandatory = 1;
00788             }
00789         }
00790 
00791       if ($is_mandatory)
00792         {
00793           $value = trackers_data_get_label($field_name);
00794           $previous_form_bad_fields[$field_name] = $value;
00795         }
00796     }
00797 
00798   if (count($previous_form_bad_fields) > 0)
00799     {
00800       # If not_new_item is true, it mean that there was no previous value to
00801       # reset the entry.
00802       if ($new_item)
00803         {
00804           fb(sprintf(ngettext("The field '%s' is mandatory. Fill it and re-submit the form.","The fields '%s' are mandatory. Fill them and re-submit the form.", count($previous_form_bad_fields)), join(', ',$previous_form_bad_fields)), 1);
00805         }
00806       else
00807         {
00808           fb(sprintf(ngettext("The field '%s' is mandatory. It has been reset to its previous value. Check it and re-submit the form.","The fields '%s' are mandatory. They have been reset to their previous value. Check them and re-submit the form.", count($previous_form_bad_fields)), join(', ',$previous_form_bad_fields)), 1);
00809         }
00810 
00811       return false;
00812     }
00813   else
00814     {
00815       return true;
00816     }
00817 
00818 }
00819 
00820 function trackers_canned_response_box ($group_id,$name='canned_response')
00821 {
00822   if (!$group_id)
00823     {
00824       fb(_("Error, no group_id"),1);
00825       return 0;
00826     }
00827   else
00828     {
00829       $vals = array();
00830       $texts = array();
00831       $result = trackers_data_get_canned_responses($group_id);
00832       if (db_numrows($result) > 0)
00833         {
00834           if (db_numrows($result) > 1)
00835             {
00836               $vals[] = '!multiple!';
00837               $texts[] = "> "._("Multiple Canned Responses");
00838             }
00839 
00840           while ($entry = db_fetch_array($result))
00841             {
00842               $vals[] = $entry['bug_canned_id'];
00843               $texts[] = $entry['title'];
00844 
00845             }
00846 
00847           return html_build_select_box_from_arrays($vals, $texts ,$name);
00848         }
00849       else
00850         {
00851           return form_input("hidden", "canned_response", "100")._("No canned response available");
00852         }
00853     }
00854 }
00855 
00856 function trackers_build_notification_matrix($user_id)
00857 {
00858   # Build the notif matrix indexed with roles and events labels (not id)
00859   $res_notif = trackers_data_get_notification_with_labels($user_id);
00860   while ($arr = db_fetch_array($res_notif))
00861     {
00862       $arr_notif[$arr['role_label']][$arr['event_label']] = $arr['notify'];
00863     }
00864   return $arr_notif;
00865 }
00866 
00867 
00868 function trackers_check_notification($user_id, $role, $changes=false)
00869 {
00870 
00871   $send = false;
00872   $arr_notif = trackers_build_notification_matrix($user_id);
00873   if (!$arr_notif)
00874     { return true; }
00875 
00876   #echo "==== DBG Checking Notif. for $user_id (role=$role)<br />";
00877   $user_name = user_getname($user_id);
00878 
00879   #----------------------------------------------------------
00880   # If it's a new bug only (changes is false) check the NEW_ITEM event and
00881   # ignore all other events
00882   if ($changes==false)
00883     {
00884       if ($arr_notif[$role]['NEW_ITEM'])
00885         {
00886           #echo "DBG NEW_ITEM notified<br />";
00887           return true;
00888         }
00889       else
00890         {
00891           #echo "DBG No notification<br />";
00892           return false;
00893         }
00894     }
00895 
00896   #----------------------------------------------------------
00897   #Check: I_MADE_IT  (I am the author of the change )
00898   # Check this one first because if the user said no she doesn't want to be
00899   # aware of any of her change in this role and we can return immediately.
00900   if (($user_id == user_getid()) && !$arr_notif[$role]['I_MADE_IT'])
00901     {
00902       #echo "DBG Dont want to receive my own changes<br />";
00903       return false;
00904     }
00905 
00906   #----------------------------------------------------------
00907   # Check :  NEW_COMMENT  A new followup comment is added
00908   if ($arr_notif[$role]['NEW_COMMENT'] && isset($changes['details']))
00909     {
00910       #echo "DBG NEW_COMMENT notified<br />";
00911       return true;
00912     }
00913 
00914   #----------------------------------------------------------
00915   #Check: NEW_FILE  (A new file attachment is added)
00916   if ($arr_notif[$role]['NEW_FILE'] && isset($changes['attach']))
00917     {
00918       #echo "DBG NEW_FILE notified<br />";
00919       return true;
00920     }
00921 
00922   #----------------------------------------------------------
00923   #Check: CLOSED  (The bug is closed)
00924   # Rk: this one has precedence over PSS_CHANGE. So notify even if PSS_CHANGE
00925   # says no.
00926   if ($arr_notif[$role]['CLOSED'] && ($changes['status_id']['add'] == 'Closed'))
00927     {
00928       #echo "DBG CLOSED bug notified<br />";
00929       return true;
00930     }
00931 
00932   #----------------------------------------------------------
00933   #Check: PSS_CHANGE  (Priority,Status,Severity changes)
00934   if ($arr_notif[$role]['PSS_CHANGE'] &&
00935       (isset($changes['priority']) || isset($changes['status_id']) || isset($changes['severity'])) )
00936     {
00937       #echo "DBG PSS_CHANGE notified<br />";
00938       return true;
00939     }
00940 
00941 
00942   #----------------------------------------------------------
00943   # Check :  ROLE_CHANGE (I'm added to or removed from this role)
00944   # Rk: This event is meanningless for Commenters. It also is for submitter but may be
00945   # one day the submitter will be changeable by the project admin so test it.
00946   # Rk #2: check this one at the end because it is the most CPU intensive and this
00947   # event seldomly happens
00948   if ($arr_notif['SUBMITTER']['ROLE_CHANGE'] &&
00949       (($changes['submitted_by']['add'] == $user_name) || ($changes['submitted_by']['del'] == $user_name)) &&
00950       ($role == 'SUBMITTER') )
00951     {
00952       #echo "DBG ROLE_CHANGE for submitter notified<br />";
00953       return true;
00954     }
00955 
00956   if ($arr_notif['ASSIGNEE']['ROLE_CHANGE'] &&
00957       (($changes['assigned_to']['add'] == $user_name) || ($changes['assigned_to']['del'] == $user_name)) &&
00958       ($role == 'ASSIGNEE') )
00959     {
00960       #echo "DBG ROLE_CHANGE for role assignee notified<br />";
00961       return true;
00962     }
00963 
00964   $arr_cc_changes = array();
00965   if (isset($changes['CC']['add']))
00966     $arr_cc_changes = split(',',$changes['CC']['add']);
00967   $arr_cc_changes[] = $changes['CC']['del'];
00968   $is_user_in_cc_changes = in_array($user_name,$arr_cc_changes);
00969   $are_anyother_user_in_cc_changes =
00970      (!$is_user_in_cc_changes || count($arr_cc_changes)>1);
00971 
00972   if ($arr_notif['CC']['ROLE_CHANGE'] && ($role == 'CC'))
00973     {
00974       if ($is_user_in_cc_changes)
00975         {
00976           #echo "DBG ROLE_CHANGE for cc notified<br />";
00977           return true;
00978         }
00979     }
00980 
00981   #----------------------------------------------------------
00982   #Check: CC_CHANGE  (CC_CHANGE is added or removed)
00983   # check this right after because  role cahange for cc can contradict
00984   # thee cc_change notification. If the role change on cc says no notification
00985   # then it has precedence over a cc_change
00986   if ($arr_notif[$role]['CC_CHANGE'] && isset($changes['CC']))
00987     {
00988       # its enough to test role against 'CC' because if we are at that point
00989       # it means that the role_change for CC was false or that role is not CC
00990       # So if role is 'CC' and we are here it means that the user asked to not be
00991       # notified on role_change as CC, unless other users are listed in the cc changes
00992       if (($role != 'CC') || (($role == 'CC') && $are_anyother_user_in_cc_changes))
00993         {
00994           #echo "DBG CC_CHANGE notified<br />";
00995           return true;
00996         }
00997     }
00998 
00999 
01000   #----------------------------------------------------------
01001   #Check: CHANGE_OTHER  (Any changes not mentioned above)
01002   # *** THIS ONE MUST ALWAYS BE TESTED LAST
01003 
01004   # Delete all tested fields from the $changes array. If any remains then it
01005   # means a notification must be sent
01006   unset($changes['details']);
01007   unset($changes['attach']);
01008   unset($changes['priority']);
01009   unset($changes['severity']);
01010   unset($changes['status_id']);
01011   unset($changes['CC']);
01012 
01013 # assignee and submitter related changes can't be unset globally. 
01014 # What needs to be unset is only what has been handled in this particular
01015 # call of the function
01016 
01017   if (($changes['assigned_to']['add'] == $user_name) && ($role == 'ASSIGNEE')) {    unset($changes['assigned_to']['add']);
01018   }
01019   if (($changes['assigned_to']['del'] == $user_name) && ($role == 'ASSIGNEE')) {    unset($changes['assigned_to']['del']);
01020   }
01021   if (count($changes['assigned_to']) == 0) { unset($changes['assigned_to']);}
01022                                                                                 
01023   if (($changes['submitted_by']['add'] == $user_name) && ($role == 'SUBMITTER')) {
01024     unset($changes['submitted_by']['add']);
01025   }
01026   if (($changes['submitted_by']['del'] == $user_name) && ($role == 'SUBMITTER')) {
01027     unset($changes['submitted_by']['del']);
01028   }
01029   if (count($changes['submitted_by']) == 0) { unset($changes['submitted_by']);}
01030 
01031   if ($arr_notif[$role]['ANY_OTHER_CHANGE'] && count($changes))
01032     {
01033       #echo "DBG ANY_OTHER_CHANGE notified<br />";
01034       return true;
01035     }
01036 
01037   # Sorry, no notification...
01038   #echo "DBG No notification!!<br />";
01039   return false;
01040 }
01041 
01042 function trackers_build_notification_list($item_id, $group_id, $changes)
01043 {
01044 
01045   $sql="SELECT assigned_to, submitted_by from ".ARTIFACT." WHERE bug_id='$item_id'";
01046   $res_as=db_query($sql);
01047 
01048   # Rk: we store email addresses in a hash to make sure they are only
01049   # stored once. Normally if an email is repeated several times sendmail
01050   # would take care of it but I prefer taking care of it now.
01051   # Same for user ids.
01052   # We also use the user_ids hash to check if a user has already been selected for
01053   # notification. If so it is not necessary to check it again in another role.
01054   $addresses = array();
01055   $user_ids = array();
01056 
01057   # check submitter notification preferences
01058   $user_id = db_result($res_as,0,'submitted_by');
01059   if ($user_id != 100)
01060     {
01061       if (trackers_check_notification($user_id, 'SUBMITTER', $changes))
01062         {
01063           $user_ids[$user_id] = true;
01064         }
01065     }
01066 
01067   # check assignee  notification preferences
01068   $user_id = db_result($res_as,0,'assigned_to');
01069   if ($user_id != 100)
01070     {
01071       if (!$user_ids[$user_id] && trackers_check_notification($user_id, 'ASSIGNEE', $changes))
01072         {
01073           $user_ids[$user_id] = true;
01074         }
01075     }
01076 
01077   # check old assignee  notification preferences if assignee was just changed
01078   $user_name = $changes['assigned_to']['del'];
01079   if ($user_name)
01080     {
01081       $res_oa = user_get_result_set_from_unix($user_name);
01082       $user_id = db_result($res_oa,0,'user_id');
01083       if ($user_id != 100 && !$user_ids[$user_id] && trackers_check_notification($user_id, 'ASSIGNEE', $changes))
01084         {
01085           $user_ids[$user_id] = true;
01086         }
01087     }
01088 
01089   # check all CC
01090   # a) check all the people in the current CC list
01091   # b) check the CC that has just been removed if any and see if she
01092   # wants to be notified as well
01093   # if the CC indentifier is an email address then notify in any case
01094   # because this user has no personal setting
01095   $res_cc = trackers_data_get_cc_list($item_id);
01096   $arr_cc = array();
01097   if ($res_cc && (db_numrows($res_cc) > 0))
01098     {
01099       while ($row = db_fetch_array($res_cc))
01100         {
01101           $arr_cc[] = $row['email'];
01102         }
01103     }
01104   # Only one CC can be deleted at once so just append it to the list....
01105   $arr_cc[] = $changes['CC']['del'];
01106 
01107   while (list(,$cc) = each($arr_cc))
01108     {
01109       if (validate_email($cc))
01110         {
01111           $addresses[utils_normalize_email($cc)] = true;
01112         }
01113       else
01114         {
01115           $res = user_get_result_set_from_unix($cc);
01116           $user_id = db_result($res,0,'user_id');
01117           if (!$user_ids[$user_id] && trackers_check_notification($user_id, 'CC', $changes))
01118             {
01119               $user_ids[$user_id] = true;
01120             }
01121         }
01122     } # while
01123 
01124 
01125   # check all commenters
01126   $res_com = trackers_data_get_commenters($item_id);
01127   if (db_numrows($res_com) > 0)
01128     {
01129       while ($row = db_fetch_array($res_com))
01130         {
01131           $user_id = $row['mod_by'];
01132           if ($user_id != 100)
01133             {
01134               if (!$user_ids[$user_id] && trackers_check_notification($user_id, 'COMMENTER', $changes))
01135                 {
01136                   $user_ids[$user_id] = true;
01137                 }
01138             }
01139         }
01140     }
01141 
01142   # build the final list of email addresses
01143   reset($user_ids);
01144   while (list($user_id,) = each($user_ids))
01145     {
01146       if ($user_id)
01147         {
01148           # Dirty hack: for a reason need to be cleared out,
01149           # a user_id = 0 arrived here.
01150           # Must not define email address so soon. Just passing user_id
01151           $addresses[$user_id] = true;
01152         }
01153     }
01154 
01155   # return an array with all the email addresses the notification must be sent to
01156   return (array_keys($addresses));
01157 
01158 }
01159 
01160 function trackers_mail_followup ($item_id,$more_addresses=false,$changes=false,$force_exclude_list=false, $artifact=0)
01161 {
01162   global $sys_datefmt;
01163 
01164   if (!$artifact)
01165     { $artifact = ARTIFACT; }
01166 
01167   $sql="SELECT * from $artifact WHERE bug_id='$item_id'";
01168 
01169   $result = db_query($sql);
01170   $bug_href = "http://".$GLOBALS['sys_default_domain'].$GLOBALS['sys_home']."$artifact/?$item_id";
01171 
01172   if ($result && db_numrows($result) > 0)
01173   {
01174 
01175   $group_id = db_result($result,0,'group_id');
01176 
01177   unset($content_type);
01178   # CERN SPECIFIC (at least for now) BEGIN '
01179   # Maybe later we ll implement a way to select mail templates, or prepared
01180   # mail format (like: text / html).
01181   # But it will have to be done in a well planned way that take into account
01182   # necessary cases and is not encumbered by very very specific things.
01183   # Until this happen, cern will use its own functions to deals with notif.
01184   # Indeed, this part will maintained and modified by CERN only.
01185   #
01186   # To ease maintainance, such specific things should usually not be added.
01187   # Please write to savane-dev if you intend to make such changes.
01188   # The upstream code cannot be cluttered by tons of things like that.
01189   # This is a one time exception, or almost, needed because this cannot
01190   # be directly merged in a generic way right now.
01191   if ($GLOBALS['sys_default_domain'] == "savannah.cern.ch" || $GLOBALS['sys_debug_cerntest'])
01192   {
01193     $content_type = group_get_preference($group_id, "notif_content");
01194     if ($content_type == "")
01195      {
01196        $content_type = '2';   # by default select maximum
01197      }
01198 
01199     # Now, if the content type is 0, go on with Savane standard notif.
01200     # If it s something else, use trackers_mail_followup_cernspecifichack()
01201     if ($content_type > 0)
01202      {
01203        return trackers_mail_followup_cernspecifichack($group_id,$bug_href,$result,$content_type,$item_id,$more_addresses,$changes,$force_exclude_list);
01204      }
01205   }
01206   # CERN SPECIFIC (at least for now) END
01207 
01208   # CONTENT OF THE MAIL MUST NOT BE TRANSLATED
01209 
01210   unset($body);
01211 
01212       if ($changes)
01213         {
01214           $body = format_item_changes($changes, $item_id, $group_id)."\n";
01215         }
01216       else
01217         {
01218       $body .= "URL:\n  <".$bug_href.">\n\n";
01219       $body .= trackers_field_display('summary', $group_id, db_result($result,0,'summary'),false,true,true,true)."\n";
01220       $body .= sprintf("%25s", "Project:").' '.group_getname($group_id)."\n";
01221       $body .= trackers_field_display('submitted_by', $group_id, db_result($result,0,'submitted_by'),false,true,true,true)."\n";
01222       $body .= trackers_field_display('date', $group_id, db_result($result,0,'date'),false,true,true,true)."\n";
01223 
01224       # All other regular fields now
01225       $i=0;
01226       while ($field_name = trackers_list_all_fields())
01227       {
01228 
01229           # if the field is a special field or if not used by his project
01230           # then skip it. Otherwise print it in ASCII format.
01231           if (!trackers_data_is_special($field_name) &&
01232               trackers_data_is_used($field_name))
01233             {
01234 
01235               $body .= trackers_field_display($field_name,
01236                                               $group_id,
01237                                               db_result($result,0,$field_name),
01238                                               false,
01239                                               true,
01240                                               true,
01241                                               true);
01242 
01243               $i++;
01244               $body .= "\n";
01245             }
01246         }
01247       $body .= "\n";
01248 
01249       # Now display other special fields
01250       $body .= "    _______________________________________________________\n\nDetails:\n".trackers_field_display('details',
01251                                        $group_id,
01252                                        db_result($result,0,'details'),
01253                                        true,true,true,true);
01254 
01255       # Then output the history of bug details from newest to oldest
01256       $body .= "\n\n".format_item_details($item_id, $group_id, true);
01257 
01258       # Then output the CC list
01259       $body .= "\n\n".format_item_cc_list($item_id, $group_id, true);
01260 
01261       # Then output the history of bug details from newest to oldest
01262       $body .= "\n\n".format_item_attached_files($item_id, $group_id, true);
01263          }
01264 
01265       # Finally output the message trailer
01266       $body .= "\n    _______________________________________________________\n\n";
01267       $body .= "Reply to this item at:";
01268       $body .= "\n\n  <".$bug_href.">";
01269 
01270 
01271 
01272 
01273       # See who is going to receive the notification.
01274       # Plus append any other email
01275       # given at the end of the list.
01276       $arr_addresses = trackers_build_notification_list($item_id,$group_id,$changes);
01277       $to = join(',',$arr_addresses);
01278       $from = user_getrealname(0,1).' <'.$GLOBALS['sys_mail_replyto'].'@'.$GLOBALS['sys_mail_domain'].'>';
01279       $subject = utils_unconvert_htmlspecialchars(db_result($result,0,'summary'));
01280 
01281       if ($more_addresses)
01282         {
01283           $to .= ($to ? ',':'').$more_addresses;
01284         }
01285 
01286       # If the item is private, take into account the exclude-list
01287       if (db_result($result,0,'privacy') == '2')
01288         {
01289            $exclude_list = db_result(db_query("SELECT ".$artifact."_private_exclude_address FROM groups WHERE group_id='$group_id'"),0, $artifact."_private_exclude_address");
01290 
01291         }
01292 
01293       # Disallow mail notification for an address, private or not
01294       if ($force_exclude_list)
01295       {
01296         if ($exclude_list)
01297           { $exclude_list .= ",".$force_exclude_list; }
01298         else
01299           { $exclude_list = $force_exclude_list; }
01300       }
01301 
01302 
01303       sendmail_mail($from, $to, $subject, $body, group_getunixname($group_id), $artifact, $item_id, 0, 0, $exclude_list);
01304       # Useless feedback, already added by sendmail_mail()
01305       #fb(_("Item update sent."));
01306 
01307     }
01308   else
01309     {
01310       fb(_("Could not send item update."), 0);
01311     }
01312 }
01313 
01314 
01315 function trackers_attach_file($item_id,
01316                               $group_id,
01317                               $input_file,
01318                               $input_file_name, # 4
01319                               $input_file_type,
01320                               $input_file_size, # 6
01321                               $file_description,
01322                               &$changes)
01323 {
01324 
01325 
01326   $user_id = (user_isloggedin() ? user_getid(): 100);
01327 
01328   # Open the file
01329   $data = fopen($input_file, 'r');
01330   if (!$data)
01331     {
01332       fb(_("File not attached: unable to open it."), 1);
01333       return false;
01334     }
01335 
01336   # Check file size:
01337   #  - first with filesize(), that can result appropriate result for big files
01338   #  unlike strlen. If it is too big, we stop here.
01339   #  - then with strlen after the call the addslashes(): the check must be
01340   #  made on the final size for import in the database.
01341   #
01342   if (filesize($input_file) > 524288) {
01343     fb(sprintf(_("File not attached: the allowed size is 512 kB, after escaping characters as required. The file you were trying to attach is %s kB large."), filesize($input_file)/1024), 1);
01344     return false;
01345   }
01346   $data = addslashes(fread($data, filesize($input_file)));
01347   if (strlen($data) > 524288)
01348     {
01349       fb(sprintf(_("File not attached: the allowed size is 512 kB. After escaping characters as required, it sized %s kB."), strlen($data)/1024), 1);
01350       return false;
01351     }
01352 
01353   $sql = 'INSERT into trackers_file (item_id,artifact,submitted_by,date,description, file,filename,filesize,filetype) '.
01354      "VALUES ($item_id,'".ARTIFACT."',$user_id,'".time()."','".htmlspecialchars($file_description).
01355      "','$data','$input_file_name','$input_file_size','$input_file_type')";
01356 
01357   $res = db_query($sql);
01358 
01359   if (!$res)
01360     {
01361       fb(_("Error while attaching file:").' '.db_error($res), 1);
01362       return false;
01363     }
01364   else
01365     {
01366       $file_id = db_insertid($res);
01367       fb(sprintf(_("file #%s attached"), $file_id));
01368       $changes['attach']['description'] = $file_description;
01369       $changes['attach']['name'] = $input_file_name;
01370       $changes['attach']['size'] = $input_file_size;
01371       $changes['attach']['href'] = 'http://'.$GLOBALS['sys_default_domain'].$GLOBALS['sys_home'].ARTIFACT."/download.php?file_id=$file_id";
01372       trackers_data_add_history("Attached File",
01373                                 "-",
01374                                 "Added ".$input_file_name.", #".$file_id,
01375                                 $item_id,
01376                                 0,0,1);
01377       return true;
01378     }
01379 }
01380 
01381 function trackers_exist_cc($item_id,$cc)
01382 {
01383   $sql = "SELECT bug_cc_id FROM ".ARTIFACT."_cc WHERE bug_id='$item_id' AND email='$cc'";
01384   $res = db_query($sql);
01385   return (db_numrows($res) >= 1);
01386 }
01387 
01388 function trackers_insert_cc($item_id,$cc,$added_by,$comment,$date)
01389 {
01390   $sql = "INSERT INTO ".ARTIFACT."_cc (bug_id,email,added_by,comment,date) ".
01391      "VALUES ('$item_id','$cc','$added_by','".htmlspecialchars($comment)."','$date')";
01392   $res = db_query($sql);
01393 
01394   trackers_data_add_history("Carbon-Copy",
01395                             "-",
01396                             "Added ".utils_email($cc,1),
01397                             $item_id,
01398                             0,0,1);
01399   return ($res);
01400 
01401 }
01402 
01403 function trackers_add_cc($item_id,$group_id,$email,$comment,&$changes)
01404 {
01405   global $feedback,$ffeedback;
01406 
01407   $user_id = (user_isloggedin() ? user_getid(): 100);
01408 
01409   $arr_email = utils_split_emails($email);
01410   $date = time();
01411   $ok = true;
01412   $changed = false;
01413   while (list(,$cc) = each($arr_email))
01414     {
01415       # Add this cc only if not there already
01416       if (!trackers_exist_cc($item_id,$cc))
01417         {
01418           $changed = true;
01419           $res = trackers_insert_cc($item_id,$cc,$user_id,$comment,$date);
01420           if (!$res)
01421             { $ok = false; }
01422         }
01423     }
01424 
01425   if (!$ok)
01426     {
01427       fb(_("CC addition failed."), 0);
01428     }
01429   else
01430     {
01431       fb(_("CC added."));
01432     }
01433   return $ok;
01434 }
01435 
01436 function trackers_delete_cc($group_id=false,$item_id=false,$item_cc_id=false)
01437 {
01438   global $feedback,$ffeedback;
01439 
01440   # If both bug_id and bug_cc_id are given make sure the cc belongs
01441   # to this bug (it's a bit paranoid but...)
01442   if ($item_id)
01443     {
01444       $res1 = db_query("SELECT bug_id,email from ".ARTIFACT."_cc WHERE bug_cc_id='$item_cc_id'");
01445       if ((db_numrows($res1) <= 0) || (db_result($res1,0,'bug_id') != $item_id) )
01446         {
01447           " This $item_cc_id doesn't belong to this item, nothing will be done.";
01448           return false;
01449         }
01450     }
01451 
01452   # Now delete the CC address
01453   $res2 = db_query("DELETE FROM ".ARTIFACT."_cc WHERE bug_cc_id='$item_cc_id'");
01454   if (!$res2)
01455     {
01456       fb(_("Failed to remove CC.").db_error($res2), 0);
01457       return false;
01458     }
01459   else
01460     {
01461       fb(_("CC Removed."));
01462       trackers_data_add_history("Carbon-Copy",
01463                                 "Removed ".utils_email(db_result($res1, 0, 'email'),1),
01464                                 "-",
01465                                 $item_id,
01466                                 0,0,1);
01467       return true;
01468     }
01469 }
01470 
01471 
01472 function trackers_delete_dependancy ($group_id, $item_id, $item_depends_on, $item_depends_on_artifact, &$changes)
01473 {
01474 
01475   # Can be done only by at least technicians
01476   # Note that is it possible to fake the system by providing a false group_id.
01477   # But well, consequences would be small an it will be easy to identify
01478   # the criminal.
01479 
01480   if (member_check(0,$group_id, member_create_tracker_flag(ARTIFACT).'1'))
01481     {
01482       $result = db_query("DELETE FROM ".ARTIFACT."_dependencies WHERE item_id='$item_id' AND is_dependent_on_item_id='$item_depends_on' AND is_dependent_on_item_id_artifact='$item_depends_on_artifact'");
01483     }
01484 
01485   if (!$result)
01486     {
01487       fb(_("Failed to delete dependancy.").db_error($result), 0);
01488       return false;
01489     }
01490   else
01491     {
01492       fb(_("Dependency Removed."));
01493       trackers_data_add_history("Dependencies",
01494                                 "Removed dependancy to ".$item_depends_on_artifact." #".$item_depends_on,
01495                                 "-",
01496                                 $item_id,
01497                                 0,0,1);
01498       trackers_data_add_history("Dependencies",
01499                                 "Removed dependancy from ".ARTIFACT." #".$item_id,
01500                                 "-",
01501                                 $item_depends_on,
01502                                 0,0,1);
01503 
01504       $changes['Dependency Removed']['add'] = $item_depends_on_artifact." #".$item_depends_on;
01505 
01506       return true;
01507     }
01508 }
01509 
01510 
01511 
01512 /*
01513    The ANY value is 0. The simple fact that
01514    ANY (0) is one of the value means it is Any even if there are
01515    other non zero values in the  array
01516 */
01517 function trackers_isvarany($var)
01518 {
01519   if (is_array($var))
01520     {
01521       reset($var);
01522       while (list(,$v) = each($var))
01523         {
01524           if ($v == 0)
01525             { return true; }
01526         }
01527       return false;
01528     }
01529   else
01530     {
01531       return ($var == 0);
01532     }
01533 
01534 }
01535 
01536 
01537 # Check is a sort criteria is already in the list of comma
01538 # separated criterias. If so invert the sort order, if not then
01539 # simply add it
01540 function trackers_add_sort_criteria($criteria_list, $order, $msort)
01541 {
01542   #echo "<br />DBG \$criteria_list=$criteria_list,\$order=$order";
01543 
01544   if ($criteria_list)
01545     {
01546       $arr = explode(',',$criteria_list);
01547       $i = 0;
01548       while (list(,$attr) = each($arr))
01549         {
01550           preg_match("/\s*([^<>]*)([<>]*)/", $attr,$match);
01551           list(,$mattr,$mdir) = $match;
01552           #echo "<br />DBG \$mattr=$mattr,\$mdir=$mdir";
01553           if ($mattr == $order)
01554             {
01555               if ( ($mdir == '>') || (!isset($mdir)) )
01556                 {
01557                   $arr[$i] = $order.'<';
01558                 }  else
01559                   {
01560                     $arr[$i] = $order.'>';
01561                   }
01562               $found = true;
01563             }
01564           $i++;
01565         }
01566     }
01567 
01568   if (!$found)
01569     {
01570       if (!$msort)
01571         { unset($arr); }
01572       if ( ($order == 'severity') || ($order == 'hours') || (trackers_data_is_date_field($order)) )
01573         {
01574           # severity, effort and dates sorted in descending order by default
01575           $arr[] = $order.'<';
01576         }
01577       else
01578         {
01579           $arr[] = $order.'>';
01580         }
01581     }
01582 
01583   #echo "<br />DBG \$arr[]=".join(',',$arr);
01584 
01585   return(join(',', $arr));
01586 
01587 }
01588 
01589 # Transform criteria list to SQL query (+ means ascending
01590 # - is descending)
01591 function trackers_criteria_list_to_query($criteria_list)
01592 {
01593 
01594   $criteria_list = str_replace('>',' ASC',$criteria_list);
01595   $criteria_list = str_replace('<',' DESC',$criteria_list);
01596   return $criteria_list;
01597 }
01598 
01599 # Transform criteria list to readable text statement
01600 # $url must not contain the morder parameter
01601 function trackers_criteria_list_to_text($criteria_list, $url)
01602 {
01603 
01604   if ($criteria_list)
01605     {
01606 
01607       $arr = explode(',',$criteria_list);
01608 
01609       while (list(,$crit) = each($arr))
01610         {
01611 
01612           $morder .= ($morder ? ",".$crit : $crit);
01613           $attr = str_replace('>','',$crit);
01614           $attr = str_replace('<','',$attr);
01615           $morder = htmlspecialchars($morder);
01616 
01617           $arr_text[] = '<a href="'.$url.'&amp;morder='.$morder.'#results">'.
01618              trackers_data_get_label($attr).'</a><img class="icon" src="'.$GLOBALS['sys_home'].'images/'.SV_THEME.'.theme/'.
01619              ((substr($crit, -1) == '>') ? 'down' : 'up').
01620              '.png" border="0" />';
01621         }
01622     }
01623 
01624   return join(' &gt; ',$arr_text);
01625 }
01626 
01627 function trackers_build_match_expression($field, &$to_match)
01628 {
01629 
01630   # First get the field type
01631   $res = db_query("SHOW COLUMNS FROM ".ARTIFACT." LIKE '$field'");
01632   $type = db_result($res,0,'Type');
01633 
01634   #echo "<br />DBG '$field' field type = $type";
01635 
01636   if (preg_match('/text|varchar|blob/i', $type))
01637     {
01638 
01639       # If it is sourrounded by /.../ the assume a regexp
01640       # else transform into a series of LIKE %word%
01641       if (preg_match('/\/(.*)\#/', $to_match, $matches))
01642         $expr = "$field RLIKE '".$matches[1]."' ";
01643       else
01644         {
01645           $words = preg_split('/\s+/', $to_match);
01646           reset($words);
01647           while ( list($i,$w) = each($words))
01648             {
01649               #echo "<br />DBG $i, $w, $words[$i]";
01650               $words[$i] = "$field LIKE '%$w%'";
01651             }
01652           $expr = join(' AND ', $words);
01653         }
01654 
01655     }
01656   else if (preg_match('/int/i', $type))
01657     {
01658 
01659       # If it is sourrounded by /.../ then assume a regexp
01660       # else assume an equality
01661       if (preg_match('/\/(.*)\#/', $to_match, $matches))
01662         {
01663           $expr = "$field RLIKE '".$matches[1]."' ";
01664         }
01665       else
01666         {
01667           $int_reg = '[+\-]*[0-9]+';
01668           if (preg_match("/\s*(<|>|>=|<=)\s*($int_reg)/", $to_match, $matches))
01669             {
01670               # It's < or >,  = and a number then use as is
01671               $matches[2] = (string)((int)$matches[2]);
01672               $expr = "$field ".$matches[1]." '".$matches[2]."' ";
01673               $to_match = $matches[1].' '.$matches[2];
01674 
01675             }
01676           else if (preg_match("/\s*($int_reg)\s*-\s*($int_reg)/", $to_match, $matches))
01677             {
01678               # it's a range number1-number2
01679               $matches[1] = (string)((int)$matches[1]);
01680               $matches[2] = (string)((int)$matches[2]);
01681               $expr = "$field >= '".$matches[1]."' AND $field <= '". $matches[2]."' ";
01682               $to_match = $matches[1].'-'.$matches[2];
01683 
01684             }
01685           else if (preg_match("/\s*($int_reg)/", $to_match, $matches))
01686             {
01687               # It's a number so use  equality
01688               $matches[1] = (string)((int)$matches[1]);
01689               $expr = "$field = '".$matches[1]."'";
01690               $to_match = $matches[1];
01691 
01692             }
01693           else
01694             {
01695               # Invalid syntax - no condition
01696               $expr = '1';
01697               $to_match = '';
01698             }
01699         }
01700 
01701     }
01702   else if (preg_match('/float/i', $type))
01703     {
01704 
01705       # If it is sourrounded by /.../ the assume a regexp
01706       # else assume an equality
01707       if (preg_match('/\/(.*)\#', $to_match, $matches))
01708         {
01709           $expr = "$field RLIKE '".$matches[1]."' ";
01710         }
01711       else
01712         {
01713           $flt_reg = '[+\-0-9.eE]+';
01714 
01715           if (preg_match("/\s*(<|>|>=|<=)\s*($flt_reg)/", $to_match, $matches))
01716             {
01717               # It's < or >,  = and a number then use as is
01718               $matches[2] = (string)((float)$matches[2]);
01719               $expr = "$field ".$matches[1]." '".$matches[2]."' ";
01720               $to_match = $matches[1].' '.$matches[2];
01721 
01722             }
01723           else if (preg_match("/\s*($flt_reg)\s*-\s*($flt_reg)/", $to_match, $matches) )
01724             {
01725               # it's a range number1-number2
01726               $matches[1] = (string)((float)$matches[1]);
01727               $matches[2] = (string)((float)$matches[2]);
01728               $expr = "$field >= '".$matches[1]."' AND $field <= '". $matches[2]."' ";
01729               $to_match = $matches[1].'-'.$matches[2];
01730 
01731             }
01732           else if (preg_match("/\s*($flt_reg)/", $to_match, $matches))
01733             {
01734 
01735               # It's a number so use  equality
01736               $matches[1] = (string)((float)$matches[1]);
01737               $expr = "$field = '".$matches[1]."'";
01738               $to_match = $matches[1];
01739             }
01740           else
01741             {
01742               # Invalid syntax - no condition
01743               $expr = '1';
01744               $to_match = '';
01745             }
01746         }
01747 
01748     }
01749   else
01750     {
01751       # All the rest (???) use =
01752       $expr = "$field = '$to_match'";
01753     }
01754 
01755   #echo "<br />DBG expr to match for '$field' = $expr";
01756   return ' ('.$expr.') ';
01757 
01758 }
01759 
01760 # function moved to data.
01761 function trackers_delete_file($group_id=false,$item_id=false,$item_file_id=false)
01762 {
01763 
01764   return trackers_data_delete_file($group_id, $item_id, $item_file_id);
01765 }
01766 
01767 # register a msg id for an item update notification
01768 function trackers_register_msgid ($msgid, $artifact, $item_id)
01769 {
01770   return db_affected_rows(db_query("INSERT INTO trackers_msgid (msg_id,artifact,item_id) VALUES ('$msgid','$artifact','$item_id')"));
01771 }
01772 
01773 # Get a list, separated  a msg id for an item update notification
01774 function trackers_get_msgid ($artifact, $item_id, $latest="")
01775 {
01776   if ($latest)
01777     { $latest = "ORDER BY id DESC LIMIT 1"; }
01778 
01779   $result = db_query("SELECT msg_id FROM trackers_msgid WHERE artifact='$artifact' AND item_id='$item_id' $latest");
01780   unset($list);
01781   while ($id = db_fetch_array($result))
01782     {
01783       if (isset($list))
01784         { $list .= " "; }
01785       $list .= "<".$id['msg_id'].">";
01786     }
01787   return $list;
01788 }
01789 
01790 ############## NASTY HACK
01791 
01792   # CERN SPECIFIC (at least for now) BEGIN '
01793   # Maybe later we ll implement a way to select mail templates, or prepared
01794   # mail format (like: text / html).
01795   # But it will have to be done in a well planned way that take into account
01796   # necessary cases and is not encumbered by very very specific things.
01797   # Until this happen, cern will use its own functions to deals with notif.
01798   # Indeed, this part will maintained and modified by CERN only.
01799   #
01800   # To ease maintainance, such specific things should usually not be added.
01801   # Please write to savane-dev if you intend to make such changes.
01802   # The upstream code cannot be cluttered by tons of things like that.
01803   # This is a one time exception, or almost, needed because this cannot
01804   # be directly merged in a generic way right now.
01805 function trackers_mail_followup_cernspecifichack ($group_id, $bug_href, $result,$content_type, $item_id, $more_addresses=false, $changes=false,$force_exclude_list=false) {
01806   global $sys_datefmt;
01807 
01808   # MUST BE DEFINED HERE, dont ask me why
01809   $subject = utils_unconvert_htmlspecialchars(db_result($result,0,'summary'));
01810 
01811 if ($content_type == '2') {   # for now means CERN present format
01812                                # (last + overview + all followups)
01813 
01814   $body = "This is an automated notification sent by ".$GLOBALS['sys_name']. ".
01815 It relates to:\n\t\t".ARTIFACT." #".$item_id.", project ".group_getname($group_id)."\n";
01816 
01817       if ($changes)
01818         {
01819           $body .= "\n==============================================================================\n";
01820           $body .= " LATEST MODIFICATIONS of ".ARTIFACT." #".$item_id.":\n";
01821           $body .= "==============================================================================\n\n";
01822 
01823 
01824    ### format_item_changes of savane 1.0.6
01825  # FIXME: strange, with %25s it does not behave exactly like
01826   # trackers_field_label_display
01827   $fmt = "%24s: %23s => %-23s\n";
01828 
01829   $separator = "\n    _______________________________________________________\n\n";
01830 
01831   # Process most of the fields
01832   reset($changes);
01833   while (list($field,$h) = each($changes))
01834     {
01835 
01836       # If both removed and added items are empty skip - Sanity check
01837       if (!$h['del'] && !$h['add'])
01838         { continue; }
01839 
01840       if ($field == "details" || $field == "attach")
01841         { continue; }
01842 
01843       $label = trackers_data_get_label($field);
01844       if (!$label)
01845         { $label = $field; }
01846       $out .= sprintf($fmt, $label, $h['del'],$h['add']);
01847     }
01848 
01849   if ($out)
01850     {
01851       $out = "Update of ".utils_get_tracker_prefix(ARTIFACT)." #".$item_id." (project ".group_getunixname($group_id)."):\n\n".$out;
01852     }
01853 
01854 
01855   # Process special cases: follow-up comments
01856   if ($changes['details'])
01857     {
01858 
01859       if ($out)
01860         { $out .= $separator; }
01861 
01862       $out_com = "Follow-up Comment #".db_numrows(trackers_data_get_followups($item_id));
01863       if (!$out)
01864         {
01865           $out_com .= ", ".utils_get_tracker_prefix(ARTIFACT)." #".$item_id." (project ".group_getunixname($group_id).")";
01866         }
01867 
01868       $out_com .= ":\n\n";
01869       if ($changes['details']['type'] != 'None' && $changes['details']['type'] != '(Error - Not Found)')
01870         {
01871           $out_com .= '['.$changes['details']['type']."]\n";
01872         }
01873       $out_com .= utils_unconvert_htmlspecialchars($changes['details']['add']);
01874       unset($changes['details']);
01875 
01876       $out .= $out_com;
01877     }
01878 
01879   # Process special cases: file attachment
01880   if ($changes['attach'])
01881     {
01882       if ($out)
01883         { $out .= $separator; }
01884 
01885       $out_att = "Additional Item Attachment";
01886       if (!$out)
01887         {
01888           $out_att .= ", ".utils_get_tracker_prefix(ARTIFACT)." #".$item_id." (project ".group_getunixname($group_id).")";
01889         }
01890       $out_att .= ":\n\n";
01891       $out_att .= sprintf("File name: %-30s Size:%d KB\n",$changes['attach']['name'],
01892                           intval($changes['attach']['size']/1024) );
01893       $out_att .= $changes['attach']['description']."\n".'<'.$changes['attach']['href'].'>';
01894       unset($changes['attach']);
01895 
01896       $out .= $out_att;
01897     }
01898 
01899    $body .= $out;
01900    ### format_item_changes of savane 1.0.6
01901 
01902    $body .= "\n";
01903         }
01904 
01905       $body .= "\n==============================================================================\n";
01906       $body .= " OVERVIEW of ".ARTIFACT." #".$item_id.":\n";
01907       $body .= "==============================================================================\n\n";
01908       $body .= "URL:\n  <".$bug_href.">\n\n";
01909       $body .= trackers_field_display('summary', $group_id, db_result($result,0,'summary'),false,true,true,true)."\n";
01910       $body .= sprintf("%25s", "Project:").' '.group_getname($group_id)."\n";
01911       $body .= trackers_field_display('submitted_by', $group_id, db_result($result,0,'submitted_by'),false,true,true,true)."\n";
01912       $body .= trackers_field_display('date', $group_id, db_result($result,0,'date'),false,true,true,true)."\n";
01913 
01914       # All other regular fields now
01915       $i=0;
01916       while ($field_name = trackers_list_all_fields())
01917         {
01918 
01919           # if the field is a special field or if not used by his project
01920           # then skip it. Otherwise print it in ASCII format.
01921           if (!trackers_data_is_special($field_name) &&
01922               trackers_data_is_used($field_name))
01923             {
01924 
01925               $body .= trackers_field_display($field_name,
01926                                               $group_id,
01927                                               db_result($result,0,$field_name),
01928                                               false,
01929                                               true,
01930                                               true,
01931                                               true);
01932 
01933               $i++;
01934               $body .= "\n";
01935             }
01936         }
01937       $body .= "\n";
01938 
01939       # Now display other special fields
01940       $body .= "    _______________________________________________________\n\n".trackers_field_display('details',
01941                                        $group_id,
01942                                        db_result($result,0,'details'),
01943                                        true,true,true,true);
01944 
01945       # Then output the history of bug details from newest to oldest
01946       $body .= "\n\n";
01947       # format_item_details($item_id, $group_id, true); of savane 1.0.6
01948       $result=trackers_data_get_followups($item_id);
01949       $rows=db_numrows($result);
01950 
01951   # No followup comment -> return now
01952   if ($rows > 0)
01953     {
01954        unset($out);
01955       $out .= "    _______________________________________________________\n\nFollow-up Comments:\n\n";
01956 
01957   # Loop throuh the follow-up comments and format them
01958   for ($i=0; $i < $rows; $i++)
01959     {
01960 
01961       $comment_type = db_result($result, $i, 'comment_type');
01962       if ($comment_type == 'None')
01963         { $comment_type = ''; }
01964       else
01965         { $comment_type = '['.$comment_type.']'; }
01966 
01967           $fmt = "\n-------------------------------------------------------\n".
01968              "Date: %-30sBy: %s\n";
01969           if ($comment_type)
01970             { $fmt .= "%s\n%s"; }
01971           else
01972             { $fmt .= "%s%s"; }
01973           $fmt .= "\n";
01974 
01975 
01976       # I wish we had sprintf argument swapping in PHP3 but
01977       # we dont so do it the ugly way...
01978 
01979          if (db_result($result, $i, 'realname'))
01980             {
01981               $name = db_result($result, $i, 'realname')." <".db_result($result, $i, 'user_name').">";
01982             }
01983           else
01984             {
01985               $name = "Anonymous"; # must no be translated, part of mails notifs
01986                                      }
01987           $out .= sprintf($fmt,
01988                           format_date($sys_datefmt,db_result($result, $i, 'date')),
01989                           $name,
01990                           $comment_type,
01991                           utils_unconvert_htmlspecialchars(db_result($result, $i, 'old_value'))
01992                           );
01993 
01994           }
01995      # final touch...
01996      $out .=  "\n\n\n";
01997      $body .= $out;
01998      }
01999       # format_item_details($item_id, $group_id, true); of savane 1.0.6 end
02000 
02001 
02002       # Then output the CC list
02003       $body .= "\n\n";
02004       # format_item_cc_list($item_id, $group_id, true); of savane 1.0.6
02005    $result=trackers_data_get_cc_list($item_id);
02006    $rows=db_numrows($result);
02007 
02008   # No file attached -> return now
02009   if ($rows > 0)
02010     {
02011       unset($out);
02012       $out .= "    _______________________________________________________\n\n"."Carbon-Copy List:\n\n";
02013       $fmt = "%-35s | %s\n";
02014       $out .= sprintf($fmt, 'CC Address', 'Comment');
02015       $out .= "------------------------------------+-----------------------------\n";
02016 
02017   # Loop through the cc and format them
02018   for ($i=0; $i < $rows; $i++)
02019     {
02020 
02021       $email = db_result($result, $i, 'email');
02022       $item_cc_id = db_result($result, $i, 'bug_cc_id');
02023 
02024       # If the CC is a user point to its user page.
02025       # Do not build mailto, we do not need to help spammers.
02026       $res_username = user_get_result_set_from_unix($email);
02027       if ($res_username && (db_numrows($res_username) == 1))
02028         { $href_cc = utils_user_link($email); }
02029       else
02030         { $href_cc = $email; }
02031 
02032           $out .= sprintf($fmt, $email, db_result($result, $i, 'comment'));
02033 
02034     }
02035     # final touch...
02036   $out .= "\n";
02037   $body .= $out;
02038   }
02039    # format_item_cc_list($item_id, $group_id, true); of savane 1.0.6 end
02040 
02041       # Then output the history of bug details from newest to oldest
02042       $body .= "\n\n";
02043       # format_item_attached_files of savane 1.0.6
02044       #format_item_attached_files($item_id, $group_id, true);
02045   $result=trackers_data_get_attached_files($item_id);
02046   $rows=db_numrows($result);
02047 
02048   # No file attached -> return now
02049   if ($rows > 0)
02050     {
02051       unset($out);
02052       $out .= "    _______________________________________________________\n\nFile Attachments:\n\n";
02053       $fmt = "\n-------------------------------------------------------\n".
02054          "Date: %s  Name: %s  Size: %s   By: %s\n%s\n%s";
02055  # Loop throuh the attached files and format them
02056 
02057   for ($i=0; $i < $rows; $i++)
02058     {
02059 
02060       $item_file_id = db_result($result, $i, 'bug_file_id');
02061           $href = $GLOBALS['sys_home'].ARTIFACT."/download.php?item_id=$item_id&item_file_id=$item_file_id";
02062 
02063        $out .= sprintf($fmt,
02064                           format_date($sys_datefmt,db_result($result, $i, 'date')),
02065                           db_result($result, $i, 'filename'),
02066                           utils_filesize(0, intval(db_result($result, $i, 'filesize'))),
02067                           db_result($result, $i, 'user_name'),
02068                           db_result($result, $i, 'description'),
02069                           '<http://'.$GLOBALS['sys_default_domain'].utils_unconvert_htmlspecialchars($href).'>');
02070 
02071                         }
02072 
02073                 # final touch...
02074                 $out .= "\n";
02075 $body .= $out;
02076      }
02077 
02078       # format_item_attached_files of savane 1.0.6 end
02079 
02080 
02081       # Finally output the message trailer
02082       $body .= "\n==============================================================================\n\n";
02083       $body .= "This item URL is:";
02084       $body .= "\n  <".$bug_href.">";
02085 }
02086 
02087 if ($content_type == '1') {   # for now means ROOT wishes (UGLY ... I know!)
02088   $body = "";
02089   $was_new_item = false;
02090 
02091   if (user_isloggedin()) {
02092     $body .= "Posted by: ".user_getrealname($user_id).' <'.user_getname($user_id).">";
02093   } else {
02094     $body .= "Posted by an anonymous user";
02095   }
02096   $body .= "\n";
02097   $body .= "Related to: [".group_getname($group_id)." ".ARTIFACT." #".$item_id."] ".utils_unconvert_htmlspecialchars(db_result($result,0,'summary'))."\n";
02098   $body .= "URL: <".$bug_href.">\n\n";
02099 
02100   if ($changes) {
02101     # $body .= format_item_changes($changes)."\n";
02102 
02103     #Process special cases first: follow-up comment
02104     $fmt = "%s: %23s -> %-23s\n";
02105     $was_followup = false;
02106     if ($changes['details']) {
02107       $body .= "Follow-up Comment:\n\n";
02108       if ($changes['details']['type'] != 'None' && $changes['details']['type'] != '(Error - Not Found)') {
02109         $body .= '['.$changes['details']['type']."]\n";
02110       }
02111       $body .= utils_unconvert_htmlspecialchars($changes['details']['add']);
02112       $body .= "\n";
02113       unset($changes['details']);
02114       # set flag to skip output of this followup comment at the end
02115       $was_followup = true;
02116     }
02117   } else {
02118     # if new submission start with description
02119     $body .= trackers_field_display('details',
02120                                      $group_id,
02121                                      db_result($result,0,'details'),
02122                                      true,true,true,true);
02123     $body .= "\n";
02124     # set flag to skip output of original submission at the end
02125     $was_new_item = true;
02126   }
02127 
02128   if ($changes) {
02129     #Process special cases first: bug file attachment
02130     if ($changes['attach']) {
02131       $body .= sprintf("Attachment of file: %s   Size:%d KB  ",$changes['attach']['name'], intval($changes['attach']['size']/1024) );
02132       $body .= $changes['attach']['description']."\n".'<'.$changes['attach']['href'].'>';
02133       unset($changes['attach']);
02134       $body .= "\n";
02135     }
02136 
02137     # All the rest of the fields now
02138     reset($changes);
02139     if (count($changes)) {
02140       $body .= "\n";
02141       while ( list($field,$h) = each($changes)) {
02142         # If both removed and added items are empty skip - Sanity check
02143         if (!$h['del'] && !$h['add']) { continue; }
02144         $label = trackers_data_get_label($field);
02145         if (!$label) { $label = $field; }
02146         $off = sprintf("%d", 23-strlen($label)-2);
02147         $fmt = "%s: %".$off."s -> %-23s\n";
02148         $body .= sprintf($fmt, $label, $h['del'],$h['add']);
02149       }
02150     } else {
02151       $body .= "\n";
02152     }
02153     $body .= "\n";
02154   } else {
02155     $body .= "\n";
02156   }
02157 
02158   $body .= trackers_field_display('submitted_by', $group_id, db_result($result,0,'submitted_by'),false,true,true,true,false,'',false,'',false,false,-3)."\n";
02159 
02160   # All other regular fields now
02161   $i=0;
02162   while ($field_name = trackers_list_all_fields()) {
02163     # if the field is a special field or if not used by his project
02164     # then skip it. Otherwise print it in ASCII format.
02165     if (!trackers_data_is_special($field_name) && trackers_data_is_used($field_name)) {
02166       $body .= trackers_field_display($field_name, $group_id,
02167                                       db_result($result,0,$field_name),
02168                                       false, true, true, true, false,
02169                                       '',false,'',false,false,-3);
02170       $i++;
02171       $body .= "\n";
02172     }
02173   }
02174 
02175   # Then output the history of bug details from newest to oldest
02176 
02177   # $body .= format_item_details($item_id, $group_id, true);
02178 
02179   $fu_result=trackers_data_get_followups($item_id);
02180   $fu_rows=db_numrows($fu_result);
02181   if ($fu_rows > 0) {
02182     # Loop throuh the follow-up comments and format them
02183     $fmt = "\n-----Reply from %s on %s-----\n%s\n";
02184     for ($i=0; $i < $fu_rows; $i++) {
02185       # prevent output of most recent if already shown
02186       if ($was_followup && ($i == 0)) { continue; }
02187       if (db_result($fu_result, $i, 'realname')) {
02188         $name = db_result($fu_result, $i, 'realname')." <".db_result($fu_result, $i, 'user_name').">";
02189       } else {
02190         $name = "Anonymous"; # must no be translated, part of mails notifs
02191       }
02192       if (user_get_timezone()) {
02193         $tz = ' ('.user_get_timezone().')';
02194       } else {
02195         $tz = '';
02196       }
02197       $body .= sprintf($fmt, $name,
02198                        format_date($sys_datefmt,db_result($fu_result, $i, 'date')).$tz,
02199                        utils_unconvert_htmlspecialchars(db_result($fu_result, $i, 'old_value'))
02200                       );
02201     }
02202   }
02203 
02204   if (!$was_new_item) {
02205     # Now display Original Submission
02206     $body .= "\n  -----Original Message-----".trackers_field_display('details', $group_id, db_result($result,0,'details'), true,true,true,true);
02207   }
02208 }
02209 
02210 # stuff is formatted
02211 
02212       # See who is going to receive the notification.
02213       # Plus append any other email
02214       # given at the end of the list.
02215       $arr_addresses = trackers_build_notification_list($item_id,$group_id,$changes);
02216       $to = join(',',$arr_addresses);
02217 # CERN SPECIFIC HACK
02218       $from = '"noreply ['.user_getrealname(0,0).']" <'.$GLOBALS['sys_mail_replyto'].'@'.$GLOBALS['sys_mail_domain'].'>';
02219 #      $from = user_getrealname(0,1).' <'.$GLOBALS['sys_mail_replyto'].'@'.$GLOBALS['sys_mail_domain'].'>';
02220 
02221 # replace usernames with user_ids (as expected by sendmail_mail)
02222       $repl_addresses = '';
02223       $more_addr_arr = explode(',',$more_addresses);
02224       while (list(,$maddr) = each($more_addr_arr)) {
02225         $maddr = ereg_replace(" ","", $maddr);
02226         if (validate_email($maddr)) {
02227           $repl_addresses .= ($repl_addresses ? ',':'').$maddr;
02228         } else {
02229           $maddr_user_id = user_getid($maddr);
02230           if (user_exists($maddr_user_id)) {
02231             $repl_addresses .= ($repl_addresses ? ',':'').$maddr_user_id;
02232           } else {
02233             $repl_addresses .= ($repl_addresses ? ',':'').$maddr;
02234           }
02235         }
02236       } # while
02237 
02238       if ($repl_addresses)
02239         {
02240           $to .= ($to ? ',':'').$repl_addresses;
02241         }
02242 
02243       # If the item is private, take into account the exclude-list
02244       if (db_result($result,0,'privacy') == '2')
02245         {
02246            $exclude_list = db_result(db_query("SELECT ".ARTIFACT."_private_exclude_address FROM groups WHERE group_id='$group_id'"),0, ARTIFACT."_private_exclude_address");
02247 
02248         }
02249 
02250       # Disallow mail notification for an address, private or not
02251       if ($force_exclude_list)
02252       {
02253         if ($exclude_list)
02254           { $exclude_list .= ",".$force_exclude_list; }
02255         else
02256           { $exclude_list = $force_exclude_list; }
02257       }
02258 
02259       sendmail_mail($from, $to, $subject, $body, group_getunixname($group_id), ARTIFACT, $item_id, 0, 0, $exclude_list);
02260 
02261  # Done it upstream function already
02262  # else
02263  #   {
02264  #     fb(_("Could not send item update."), 0);
02265  #   }
02266  return true;
02267 }
02268 # CERN SPECIFIC (at least for now) END
02269 
02270 ?>

Generated on Sun Feb 26 13:23:04 2006 for Savane PHP Frontend Developer Reference by  doxygen 1.4.4