Changeset de68765 in github


Ignore:
Timestamp:
May 31, 2012 4:42:46 AM (12 months ago)
Author:
Thomas Bruederli <thomas@…>
Branches:
master, HEAD, pdo
Children:
8ce6024
Parents:
8c16ea9 (diff), a71039d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merged CHANGELOG

Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r8c16ea9 rde68765  
    33 
    44- Don't let error message popups cover the login form (#1488500) 
     5- Display Tiff as Jpeg in browsers without Tiff support (#1488452) 
     6- Don't display Pdf/Tiff/Flash attachments inline without browser support (#1488452, #1487929) 
    57- Don't show errors when moving contacts into groups they are already in (#1488493) 
    68- Make folders with unread messages in subfolders bold again (#1486793) 
  • program/include/rcube_image.php

    r041c93c r19cc5b9  
    1414 |                                                                       | 
    1515 | PURPOSE:                                                              | 
    16  |   Image resizer                                                       | 
     16 |   Image resizer and converter                                         | 
    1717 |                                                                       | 
    1818 +-----------------------------------------------------------------------+ 
     
    2525{ 
    2626    private $image_file; 
     27 
     28    const TYPE_GIF = 1; 
     29    const TYPE_JPG = 2; 
     30    const TYPE_PNG = 3; 
     31    const TYPE_TIF = 4; 
     32 
     33    public static $extensions = array( 
     34        self::TYPE_GIF => 'gif', 
     35        self::TYPE_JPG => 'jpg', 
     36        self::TYPE_PNG => 'png', 
     37        self::TYPE_TIF => 'tif', 
     38    ); 
     39 
    2740 
    2841    function __construct($filename) 
     
    6780     * @param string $filename  Output filename 
    6881     * 
    69      * @return Success of convert as true/false 
     82     * @return bool True on success, False on failure 
    7083     */ 
    7184    public function resize($size, $filename = null) 
     
    96109 
    97110            if (in_array($type, explode(',', $p['types']))) { // Valid type? 
    98                 $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === ''; 
    99             } 
    100  
    101             if ($result) { 
     111                $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p); 
     112            } 
     113 
     114            if ($result === '') { 
    102115                return true; 
    103116            } 
     
    149162        } 
    150163 
     164        // @TODO: print error to the log? 
     165        return false; 
     166    } 
     167 
     168    /** 
     169     * Convert image to a given type 
     170     * 
     171     * @param int    $type      Destination file type (see class constants) 
     172     * @param string $filename  Output filename (if empty, original file will be used 
     173     *                          and filename extension will be modified) 
     174     * 
     175     * @return bool True on success, False on failure 
     176     */ 
     177    public function convert($type, $filename = null) 
     178    { 
     179        $rcube   = rcube::get_instance(); 
     180        $convert = $rcube->config->get('im_convert_path', false); 
     181 
     182        if (!$filename) { 
     183            $filename = $this->image_file; 
     184 
     185            // modify extension 
     186            if ($extension = self::$extensions[$type]) { 
     187                $filename = preg_replace('/\.[^.]+$/', '', $filename) . '.' . $extension; 
     188            } 
     189        } 
     190 
     191        // use ImageMagick 
     192        if ($convert) { 
     193            $p['in']   = $this->image_file; 
     194            $p['out']  = $filename; 
     195            $p['type'] = self::$extensions[$type]; 
     196 
     197            $result = rcube::exec($convert . ' 2>&1 -colorspace RGB -quality 75 {in} {type}:{out}', $p); 
     198 
     199            if ($result === '') { 
     200                return true; 
     201            } 
     202        } 
     203 
     204        // use GD extension (TIFF isn't supported) 
     205        $props    = $this->props(); 
     206        $gd_types = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); 
     207 
     208        if ($props['gd_type'] && in_array($props['gd_type'], $gd_types)) { 
     209            if ($props['gd_type'] == IMAGETYPE_JPEG) { 
     210                $image = imagecreatefromjpeg($this->image_file); 
     211            } 
     212            else if ($props['gd_type'] == IMAGETYPE_GIF) { 
     213                $image = imagecreatefromgif($this->image_file); 
     214            } 
     215            else if ($props['gd_type'] == IMAGETYPE_PNG) { 
     216                $image = imagecreatefrompng($this->image_file); 
     217            } 
     218 
     219            if ($type == self::TYPE_JPG) { 
     220                $result = imagejpeg($image, $filename, 75); 
     221            } 
     222            else if ($type == self::TYPE_GIF) { 
     223                $result = imagegif($image, $filename); 
     224            } 
     225            else if ($type == self::TYPE_PNG) { 
     226                $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); 
     227            } 
     228        } 
    151229 
    152230        // @TODO: print error to the log? 
     
    170248        } 
    171249    } 
     250 
    172251} 
  • program/js/app.js

    r041c93c ra71039d  
    308308        } 
    309309 
     310        // detect browser capabilities 
     311        if (!this.is_framed()) 
     312          this.browser_capabilities_check(); 
     313 
    310314        break; 
    311315 
     
    628632          if (uid && (!this.env.uid || uid != this.env.uid)) { 
    629633            if (this.env.mailbox == this.env.drafts_mailbox) 
    630               this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); 
     634              this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true); 
    631635            else 
    632636              this.show_message(uid); 
     
    650654 
    651655      case 'edit': 
    652         if (this.task=='addressbook' && (cid = this.get_single_cid())) 
     656        if (this.task == 'addressbook' && (cid = this.get_single_cid())) 
    653657          this.load_contact(cid, 'edit'); 
    654         else if (this.task=='settings' && props) 
     658        else if (this.task == 'settings' && props) 
    655659          this.load_identity(props, 'edit-identity'); 
    656         else if (this.task=='mail' && (cid = this.get_single_uid())) { 
    657           url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid='; 
    658           this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true); 
     660        else if (this.task == 'mail' && (cid = this.get_single_uid())) { 
     661          url = { _mbox: this.env.mailbox }; 
     662          url[this.env.mailbox == this.env.drafts_mailbox ? '_draft_uid' : '_uid'] = cid; 
     663          this.goto_url('compose', url, true); 
    659664        } 
    660665        break; 
     
    981986      case 'reply': 
    982987        if (uid = this.get_single_uid()) { 
    983           url = '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); 
     988          url = {_reply_uid: uid, _mbox: this.env.mailbox}; 
    984989          if (command == 'reply-all') 
    985990            // do reply-list, when list is detected and popup menu wasn't used  
    986             url += '&_all=' + (!props && this.commands['reply-list'] ? 'list' : 'all'); 
     991            url._all = (!props && this.commands['reply-list'] ? 'list' : 'all'); 
    987992          else if (command == 'reply-list') 
    988             url += '&_all=list'; 
     993            url._all = list; 
    989994 
    990995          this.goto_url('compose', url, true); 
     
    9951000      case 'forward': 
    9961001        if (uid = this.get_single_uid()) { 
    997           url = '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); 
     1002          url = { _forward_uid: uid, _mbox: this.env.mailbox }; 
    9981003          if (command == 'forward-attachment' || (!props && this.env.forward_attachment)) 
    999             url += '&_attachment=1'; 
     1004            url._attachment = 1; 
    10001005          this.goto_url('compose', url, true); 
    10011006        } 
     
    10231028      case 'download': 
    10241029        if (uid = this.get_single_uid()) 
    1025           this.goto_url('viewsource', '&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+'&_save=1'); 
     1030          this.goto_url('viewsource', { _uid: uid, _mbox: this.env.mailbox, _save: 1 }); 
    10261031        break; 
    10271032 
     
    10761081      case 'export': 
    10771082        if (this.contact_list.rowcount > 0) { 
    1078           this.goto_url('export', { _source:this.env.source, _gid:this.env.group, _search:this.env.search_request }); 
     1083          this.goto_url('export', { _source: this.env.source, _gid: this.env.group, _search: this.env.search_request }); 
    10791084        } 
    10801085        break; 
     
    15771582    var uid = list.get_single_selection(); 
    15781583    if (uid && this.env.mailbox == this.env.drafts_mailbox) 
    1579       this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); 
     1584      this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true); 
    15801585    else if (uid) 
    15811586      this.show_message(uid, false, false); 
     
    19441949      url += '&_search='+this.env.search_request; 
    19451950 
    1946     if (action == 'preview' && String(target.location.href).indexOf(url) >= 0) 
     1951    // add browser capabilities, so we can properly handle attachments 
     1952    url += '&_caps='+urlencode(this.browser_capabilities()); 
     1953 
     1954    if (preview && String(target.location.href).indexOf(url) >= 0) 
    19471955      this.show_contentframe(true); 
    19481956    else { 
     
    19501958 
    19511959      // mark as read and change mbox unread counter 
    1952       if (action == 'preview' && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) { 
     1960      if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) { 
    19531961        this.preview_read_timer = setTimeout(function() { 
    19541962          ref.set_message(id, 'unread', false); 
     
    37973805 
    37983806    // ...new search value contains old one and previous search was not finished or its result was empty 
    3799     if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || !ac.num) && this.env.contacts && !this.env.contacts.length) 
     3807    if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || ac.num <= 0) && this.env.contacts && !this.env.contacts.length) 
    38003808      return; 
    38013809 
     
    49194927    // submit request with appended token 
    49204928    if (confirm(this.get_label('deleteidentityconfirm'))) 
    4921       this.goto_url('delete-identity', '_iid='+id+'&_token='+this.env.request_token, true); 
     4929      this.goto_url('delete-identity', { _iid: id, _token: this.env.request_token }, true); 
    49224930 
    49234931    return true; 
     
    63696377  }; 
    63706378 
     6379  // Checks browser capabilities eg. PDF support, TIF support 
     6380  this.browser_capabilities_check = function() 
     6381  { 
     6382    if (!this.env.browser_capabilities) 
     6383      this.env.browser_capabilities = {}; 
     6384 
     6385    if (this.env.browser_capabilities.pdf === undefined) 
     6386      this.env.browser_capabilities.pdf = this.pdf_support_check(); 
     6387 
     6388    if (this.env.browser_capabilities.flash === undefined) 
     6389      this.env.browser_capabilities.flash = this.flash_support_check(); 
     6390 
     6391    if (this.env.browser_capabilities.tif === undefined) 
     6392      this.tif_support_check(); 
     6393  }; 
     6394 
     6395  // Returns browser capabilities string 
     6396  this.browser_capabilities = function() 
     6397  { 
     6398    if (!this.env.browser_capabilities) 
     6399      return ''; 
     6400 
     6401    var n, ret = []; 
     6402 
     6403    for (n in this.env.browser_capabilities) 
     6404      ret.push(n + '=' + this.env.browser_capabilities[n]); 
     6405 
     6406    return ret.join(); 
     6407  }; 
     6408 
     6409  this.tif_support_check = function() 
     6410  { 
     6411    var img = new Image(); 
     6412 
     6413    img.onload = function() { rcmail.env.browser_capabilities.tif = 1; }; 
     6414    img.onerror = function() { rcmail.env.browser_capabilities.tif = 0; }; 
     6415    img.src = 'program/blank.tif'; 
     6416  }; 
     6417 
     6418  this.pdf_support_check = function() 
     6419  { 
     6420    var plugin = navigator.mimeTypes ? navigator.mimeTypes["application/pdf"] : {}, 
     6421      plugins = navigator.plugins, 
     6422      len = plugins.length, 
     6423      regex = /Adobe Reader|PDF|Acrobat/i; 
     6424 
     6425    if (plugin && plugin.enabledPlugin) 
     6426        return 1; 
     6427 
     6428    if (window.ActiveXObject) { 
     6429      try { 
     6430        if (axObj = new ActiveXObject("AcroPDF.PDF")) 
     6431          return 1; 
     6432      } 
     6433      catch (e) {} 
     6434      try { 
     6435        if (axObj = new ActiveXObject("PDF.PdfCtrl")) 
     6436          return 1; 
     6437      } 
     6438      catch (e) {} 
     6439    } 
     6440 
     6441    for (i=0; i<len; i++) { 
     6442      plugin = plugins[i]; 
     6443      if (typeof plugin === 'String') { 
     6444        if (regex.test(plugin)) 
     6445          return 1; 
     6446      } 
     6447      else if (plugin.name && regex.test(plugin.name)) 
     6448        return 1; 
     6449    } 
     6450 
     6451    return 0; 
     6452  }; 
     6453 
     6454  this.flash_support_check = function() 
     6455  { 
     6456    var plugin = navigator.mimeTypes ? navigator.mimeTypes["application/x-shockwave-flash"] : {}; 
     6457 
     6458    if (plugin && plugin.enabledPlugin) 
     6459        return 1; 
     6460 
     6461    if (window.ActiveXObject) { 
     6462      try { 
     6463        if (axObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) 
     6464          return 1; 
     6465      } 
     6466      catch (e) {} 
     6467    } 
     6468 
     6469    return 0; 
     6470  }; 
     6471 
    63716472}  // end object rcube_webmail 
    63726473 
  • program/steps/mail/func.inc

    r041c93c r19cc5b9  
    8282    } 
    8383 
    84       $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); 
    85       $OUTPUT->set_env('search_mods', $search_mods); 
     84    $search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT); 
     85    $OUTPUT->set_env('search_mods', $search_mods); 
    8686  } 
    8787 
     
    115115  if ($CONFIG['junk_mbox']) 
    116116    $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); 
     117 
     118  if (!empty($_SESSION['browser_caps'])) 
     119    $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']); 
    117120 
    118121  if (!$OUTPUT->ajax_call) 
     
    11041107 
    11051108      // Content-Type: image/*... 
    1106       if (preg_match('/^image\//i', $attach_prop->mimetype) || 
    1107         // ...or known file extension: many clients are using application/octet-stream 
    1108         ($attach_prop->filename && 
    1109           preg_match('/^application\/octet-stream$/i', $attach_prop->mimetype) && 
    1110           preg_match('/\.(jpg|jpeg|png|gif|bmp)$/i', $attach_prop->filename)) 
    1111       ) { 
     1109      if (rcmail_part_image_type($attach_prop)) { 
    11121110        $out .= html::tag('hr') . html::p(array('align' => "center"), 
    11131111          html::img(array( 
     
    11271125} 
    11281126 
     1127function rcmail_part_image_type($part) 
     1128{ 
     1129  $rcmail = rcmail::get_instance(); 
     1130 
     1131  // Skip TIFF images if browser doesn't support this format... 
     1132  $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']); 
     1133  // until we can convert them to JPEG 
     1134  $tiff_support = $tiff_support || $rcmail->config->get('im_convert_path'); 
     1135 
     1136  // Content-type regexp 
     1137  $mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i'; 
     1138 
     1139  // Content-Type: image/*... 
     1140  if (preg_match($mime_regex, $part->mimetype)) { 
     1141    return $part->mimetype; 
     1142  } 
     1143 
     1144  // Many clients use application/octet-stream, we'll detect mimetype 
     1145  // by checking filename extension 
     1146 
     1147  // Supported image filename extensions to image type map 
     1148  $types = array( 
     1149    'jpg'  => 'image/jpeg', 
     1150    'jpeg' => 'image/jpeg', 
     1151    'png'  => 'image/png', 
     1152    'gif'  => 'image/gif', 
     1153    'bmp'  => 'image/bmp', 
     1154  ); 
     1155  if ($tiff_support) { 
     1156    $types['tif']  = 'image/tiff'; 
     1157    $types['tiff'] = 'image/tiff'; 
     1158  } 
     1159 
     1160  if ($part->filename 
     1161    && preg_match('/^application\/octet-stream$/i', $part->mimetype) 
     1162    && preg_match('/\.([^.])$/i', $part->filename, $m) 
     1163    && ($extension = strtolower($m[1])) 
     1164    && isset($types[$extension]) 
     1165  ) { 
     1166    return $types[$extension]; 
     1167  } 
     1168} 
    11291169 
    11301170/** 
  • program/steps/mail/get.inc

    r041c93c r19cc5b9  
    2323// show loading page 
    2424if (!empty($_GET['_preload'])) { 
    25   $url = preg_replace('/[&?]+_preload=1/', '', $_SERVER['REQUEST_URI']); 
     25  $url = preg_replace('/([&?]+)_preload=/', '\\1_embed=', $_SERVER['REQUEST_URI']); 
    2626  $message = rcube_label('loadingdata'); 
    2727 
     
    7777    // overwrite modified vars from plugin 
    7878    $mimetype = $plugin['mimetype']; 
     79 
     80    // TIFF to JPEG conversion, if needed 
     81    $tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']); 
     82    if (!empty($_REQUEST['_embed']) && !$tiff_support 
     83      && $RCMAIL->config->get('im_convert_path') 
     84      && rcmail_part_image_type($part) == 'image/tiff' 
     85    ) { 
     86      $tiff2jpeg = true; 
     87      $mimetype = 'image/jpeg'; 
     88    } 
     89 
    7990    list($ctype_primary, $ctype_secondary) = explode('/', $mimetype); 
    8091    if ($plugin['body']) 
     
    151162      header("Content-Disposition: $disposition; filename=\"$filename\""); 
    152163 
     164      // handle tiff to jpeg conversion 
     165      if (!empty($tiff2jpeg)) { 
     166        $temp_dir  = unslashify($RCMAIL->config->get('temp_dir')); 
     167        $file_path = tempnam($temp_dir, 'rcmAttmnt'); 
     168 
     169        // write content to temp file 
     170        if ($part->body) { 
     171          $saved = file_put_contents($file_path, $part->body); 
     172        } 
     173        else if ($part->size) { 
     174          $fd = fopen($file_path, 'w'); 
     175          $saved = $RCMAIL->storage->get_message_part($MESSAGE->uid, $part->mime_id, $part, false, $fd); 
     176          fclose($fd); 
     177        } 
     178 
     179        // convert image to jpeg and send it to the browser 
     180        if ($saved) { 
     181          $image = new rcube_image($file_path); 
     182          if ($image->convert(rcube_image::TYPE_JPG, $file_path)) { 
     183            header("Content-Length: " . filesize($file_path)); 
     184            readfile($file_path); 
     185          } 
     186          unlink($file_path); 
     187        } 
     188      } 
    153189      // do content filtering to avoid XSS through fake images 
    154       if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) { 
     190      else if (!empty($_REQUEST['_embed']) && $browser->ie && $browser->ver <= 8) { 
    155191        if ($part->body) { 
    156192          echo preg_match('/<(script|iframe|object)/i', $part->body) ? '' : $part->body; 
  • program/steps/mail/show.inc

    r041c93c r19cc5b9  
    2121 
    2222$PRINT_MODE = $RCMAIL->action=='print' ? TRUE : FALSE; 
     23 
     24// Read browser capabilities and store them in session 
     25if ($caps = get_input_value('_caps', RCUBE_INPUT_GET)) { 
     26  $browser_caps = array(); 
     27  foreach (explode(',', $caps) as $cap) { 
     28    $cap = explode('=', $cap); 
     29    $browser_caps[$cap[0]] = $cap[1]; 
     30  } 
     31  $_SESSION['browser_caps'] = $browser_caps; 
     32} 
    2333 
    2434// similar code as in program/steps/mail/get.inc 
     
    5262 
    5363  // mimetypes supported by the browser (default settings) 
    54   $mimetypes = $RCMAIL->config->get('client_mimetypes', 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/x-javascript,application/pdf,application/x-shockwave-flash'); 
    55   $OUTPUT->set_env('mimetypes', is_string($mimetypes) ? explode(',', $mimetypes) : (array)$mimetypes); 
     64  $mimetypes = $RCMAIL->config->get('client_mimetypes', 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,image/bmp,image/tiff,application/x-javascript,application/pdf,application/x-shockwave-flash'); 
     65  $mimetypes = is_string($mimetypes) ? explode(',', $mimetypes) : (array)$mimetypes; 
     66 
     67  // Remove unsupported types, which makes that attachment which cannot be 
     68  // displayed in a browser will be downloaded directly without displaying an overlay page 
     69  if (empty($_SESSION['browser_caps']['pdf']) && ($key = array_search('application/pdf', $mimetypes)) !== false) { 
     70    unset($mimetypes[$key]); 
     71  } 
     72  if (empty($_SESSION['browser_caps']['flash']) && ($key = array_search('application/x-shockwave-flash', $mimetypes)) !== false) { 
     73    unset($mimetypes[$key]); 
     74  } 
     75  if (empty($_SESSION['browser_caps']['tif']) && ($key = array_search('image/tiff', $mimetypes)) !== false) { 
     76    // we can convert tiff to jpeg 
     77    if (!$RCMAIL->config->get('im_convert_path')) { 
     78      unset($mimetypes[$key]); 
     79    } 
     80  } 
     81 
     82  $OUTPUT->set_env('mimetypes', $mimetypes); 
    5683 
    5784  if ($CONFIG['drafts_mbox']) 
  • skins/larry/ui.js

    r041c93c r8c16ea9  
    263263 
    264264      var pos = $(p.object).offset(); 
     265      pos.top -= (rcmail.env.task == 'login' ? 20 : 160); 
    265266      me.messagedialog.dialog('close'); 
    266267      me.messagedialog.html(p.message) 
     
    273274            me.messagedialog.dialog('destroy').hide(); 
    274275          }, 
    275           position: ['center', pos.top - 160], 
     276          position: ['center', pos.top], 
    276277          hide: { effect:'drop', direction:'down' }, 
    277278          width: 420, 
Note: See TracChangeset for help on using the changeset viewer.