thomascube
2005-11-06 10a699759d4f106f29c077a6d65d3b8d212825e5
Added localized messages to client and check form input


18 files modified
400 ■■■■ changed files
CHANGELOG 7 ●●●● patch | view | raw | blame | history
INSTALL 35 ●●●●● patch | view | raw | blame | history
program/include/main.inc 27 ●●●●● patch | view | raw | blame | history
program/include/rcube_db.inc 18 ●●●●● patch | view | raw | blame | history
program/include/rcube_mdb2.inc 52 ●●●●● patch | view | raw | blame | history
program/js/app.js 104 ●●●●● patch | view | raw | blame | history
program/js/common.js 15 ●●●●● patch | view | raw | blame | history
program/localization/de/labels.inc 2 ●●●●● patch | view | raw | blame | history
program/localization/de/messages.inc 17 ●●●●● patch | view | raw | blame | history
program/localization/en/labels.inc 2 ●●●●● patch | view | raw | blame | history
program/localization/en/messages.inc 20 ●●●●● patch | view | raw | blame | history
program/steps/addressbook/edit.inc 6 ●●●● patch | view | raw | blame | history
program/steps/addressbook/save.inc 35 ●●●● patch | view | raw | blame | history
program/steps/mail/compose.inc 4 ●●●● patch | view | raw | blame | history
program/steps/mail/sendmail.inc 13 ●●●● patch | view | raw | blame | history
program/steps/settings/edit_identity.inc 5 ●●●●● patch | view | raw | blame | history
program/steps/settings/func.inc 3 ●●●●● patch | view | raw | blame | history
program/steps/settings/save_identity.inc 35 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -60,7 +60,7 @@
- Display folder names with special chars correctly (Bug #1330157)
2005/11/02
2005/11/06
----------
- Added Finnish, Romanian and Chinese translation
- Get IMAP server capabilities in array
@@ -71,4 +71,7 @@
- Fixed XSS in address book and identities
- Added more XSS protection (Bug #1308236)
- Added tab indexes for compose form
- Added 'changed' col to contacts table
- Support for 160-bit session hashes
- Added input check for contacts and identities (Patch #1346523)
- Added messages/warning to compose step (Patch #1323895)
INSTALL
@@ -3,16 +3,47 @@
============
1. Decompress and put this folder somewhere inside your document root
2. Make sure that the following directories are writable by the webserver
2. Make sure that the following directories (and the files within)
   are writable by the webserver
   - /temp
   - /logs
3. Create a new database and a database user for RoundCube
3. Create a new database and a database user for RoundCube (see DATABASE SETUP)
4. Create database tables using the queries in file 'SQL/*.initial.sql'
   (* stands for your database type)
5. Rename the files config/*.inc.php.dist to config/*.inc.php
6. Modify the files in config/* to suit your local environment
7. Done!
DATABASE SETUP
==============
* MySQL
-------
Setting up the mysql database can be done by creating an empty database,
importing the table layout and granting the proper permissions to the
roundcube user. Here is an example of that procedure:
# mysql
> create database 'roundcubemail';
> GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost
        IDENTIFIED BY 'password';
> quit
# mysql roundcubemail < SQL/mysql.initial.sql
* SQLite
--------
Sqlite requires specifically php5 (sqlite in php4 currently doesn't
work with roundcube), and you need sqlite 2 (preferably 2.8) to setup
the sqlite db (sqlite 3.x also doesn't work at the moment). Here is
an example how you can setup the sqlite.db for roundcube:
# sqlite -init SQL/sqlite.initial.sql sqlite.db
Make sure your configuration points to the sqlite.db file and that the
webserver can write to the file.
UPGRADING
=========
If you already have a previous version of RoundCube installed,
program/include/main.inc
@@ -248,6 +248,9 @@
    $OUTPUT->set_charset($CONFIG['charset']);
  else
    rcmail_set_locale($sess_user_lang);
  // add some basic label to client
  rcube_add_label('loading');
  }  
@@ -401,6 +404,16 @@
  }
// overwrite action variable
function rcmail_overwrite_action($action)
  {
  global $OUTPUT, $JS_OBJECT_NAME;
  $GLOBALS['_action'] = $action;
  $OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $action));
  }
function show_message($message, $type='notice')
  {
  global $OUTPUT, $JS_OBJECT_NAME, $REMOTE_REQUEST;
@@ -490,6 +503,20 @@
  }
// add a localized label to the client environment
function rcube_add_label()
  {
  global $OUTPUT, $JS_OBJECT_NAME;
  $arg_list = func_get_args();
  foreach ($arg_list as $i => $name)
    $OUTPUT->add_script(sprintf("%s.add_label('%s', '%s');",
                                $JS_OBJECT_NAME,
                                $name,
                                rep_specialchars_output(rcube_label($name), 'js')));
  }
// ************** template parsing and gui functions **************
program/include/rcube_db.inc
@@ -220,7 +220,17 @@
        return $result->fetchRow(DB_FETCHMODE_ASSOC);
    }
    function quoteIdentifier ( $str )
    function quote($input, $type=null)
    {
        if (!$this->db_handle)
            $this->db_connect('r');
        return $this->db_handle->quote($input);
    }
    function quoteIdentifier($str)
    {
        if (!$this->db_handle)
            $this->db_connect('r');
@@ -228,6 +238,12 @@
        return $this->db_handle->quoteIdentifier($str);
    }
    
    function quote_identifier($str)
    {
        return $this->quoteIdentifier($str);
    }
    function unixtimestamp($field)
    {
        switch($this->db_provider)
program/include/rcube_mdb2.inc
@@ -102,39 +102,24 @@
    }
    // Query database
    function query()
    {
        $params = func_get_args();
        $query = array_shift($params);
        return $this->_query($query, 0, 0, $params);
    }
    function limitquery()
    {
        $params = func_get_args();
        $query = array_shift($params);
        $offset = array_shift($params);
        $numrows = array_shift($params);
        return $this->_query($query, $offset, $numrows, $params);
    }
    
    function _query($query, $offset, $numrows, $params)
@@ -168,6 +153,7 @@
        return $this->_add_result($result, $query);
    }
    function num_rows($res_id=NULL)
    {
        if (!$this->db_handle)
@@ -181,6 +167,7 @@
              return FALSE;
    }
    function affected_rows($res_id=NULL)
    {
        if (!$this->db_handle)
@@ -188,6 +175,7 @@
    
        return $this->db_handle->affectedRows();
    }
    function insert_id($sequence = '')
    {
@@ -212,42 +200,44 @@
        return $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    }
    function quoteIdentifier ( $str )
    {
    function quote($input, $type=null)
    {
        if (!$this->db_handle)
            $this->db_connect('r');
        return $this->db_handle->quote($input, $type);
    }
    function quoteIdentifier($str)
    {
        if (!$this->db_handle)
            $this->db_connect('r');
        return $this->db_handle->quoteIdentifier($str);
    }
    function unixtimestamp($field)
    function quote_identifier($str)
    {
        return $this->quoteIdentifier($str);
    }
    function unixtimestamp($field)
    {
        switch($this->db_provider)
            {
            case 'pgsql':
                return "EXTRACT (EPOCH FROM $field)";
                break;
            default:
                return "UNIX_TIMESTAMP($field)";
            }
    }
    function _add_result($res, $query)
    {
        // sql error occured
program/js/app.js
@@ -6,7 +6,7 @@
 | Copyright (C) 2005, RoundCube Dev, - Switzerland                      |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | Modified: 2005/11/01 (roundcube)                                      |
 | Modified: 2005/11/06 (roundcube)                                      |
 |                                                                       |
 +-----------------------------------------------------------------------+
 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
@@ -19,6 +19,7 @@
function rcube_webmail()
  {
  this.env = new Object();
  this.labels = new Object();
  this.buttons = new Object();
  this.gui_objects = new Object();
  this.commands = new Object();
@@ -48,6 +49,14 @@
    //if (!this.busy)
      this.env[name] = value;    
    };
  // add a localized label to the client environment
  this.add_label = function(key, value)
    {
    this.labels[key] = value;
    };
  // add a button to the button list
  this.register_button = function(command, id, type, act, sel, over)
@@ -513,7 +522,37 @@
      case 'save-identity':
      case 'save':
        if (this.gui_objects.editform)
          {
          var input_pagesize = rcube_find_object('_pagesize');
          var input_name  = rcube_find_object('_name');
          var input_email = rcube_find_object('_email');
          // user prefs
          if (input_pagesize && input_pagesize.value == '')
            {
            alert(this.get_label('nopagesizewarning'));
            input_pagesize.focus();
            break;
            }
          // contacts/identities
          else
            {
            if (input_name && input_name.value == '')
              {
              alert(this.get_label('nonamewarning'));
              input_name.focus();
              break;
              }
            else if (input_email && !rcube_check_email(input_email.value))
              {
              alert(this.get_label('noemailwarning'));
              input_email.focus();
              break;
              }
            }
          this.gui_objects.editform.submit();
          }
        break;
      case 'delete':
@@ -639,14 +678,46 @@
        var input_to = rcube_find_object('_to');
        var input_subject = rcube_find_object('_subject');
        var input_message = rcube_find_object('_message');
        if (input_to.value!='' && input_message.value!='')
        // check for empty recipient
        if (input_to && !rcube_check_email(input_to.value, true))
          {
          this.set_busy(true, 'sendingmessage');
          var form = this.gui_objects.messageform;
          form.submit();
          alert(this.get_label('norecipientwarning'));
          input_to.focus();
          break;
          }
        // display localized warning for missing subject
        if (input_subject && input_subject.value == '')
          {
          var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject'));
          // user hit cancel, so don't send
          if (!subject && subject !== '')
            {
            input_subject.focus();
            break;
            }
          else
            {
            input_subject.value = subject ? subject : this.get_label('nosubject');
            }
          }
        // check for empty body
        if (input_message.value=='')
          {
          if (!confirm(this.get_label('nobodywarning')))
            {
            input_message.focus();
            break;
            }
          }
        // all checks passed, send message
        this.set_busy(true, 'sendingmessage');
        var form = this.gui_objects.messageform;
        form.submit();
        break;
      case 'add-attachment':
@@ -760,7 +831,13 @@
  this.set_busy = function(a, message)
    {
    if (a && message)
      this.display_message('Loading...', 'loading', true);
      {
      var msg = this.get_label(message);
      if (msg==message)
        msg = 'Loading...';
      this.display_message(msg, 'loading', true);
      }
    else if (!a && this.busy)
      this.hide_message();
@@ -780,6 +857,17 @@
    };
  // return a localized string
  this.get_label = function(name)
    {
    if (this.labels[name])
      return this.labels[name];
    else
      return name;
    };
  // switch to another application task
  this.switch_task = function(task)
    {
    if (this.task===task && task!='mail')
program/js/common.js
@@ -6,7 +6,7 @@
 | Copyright (C) 2005, RoundCube Dev, - Switzerland                      |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | Modified:2005/10/21 (roundcube)                                       |
 | Modified:2005/11/06 (roundcube)                                       |
 |                                                                       |
 +-----------------------------------------------------------------------+
 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
@@ -264,6 +264,19 @@
  }
// check if input is a valid email address
function rcube_check_email(input, inline)
  {
  if (input && window.RegExp)
    {
    var reg_str = '([a-z0-9][-a-z0-9\.\+_]*)\@([a-z0-9]([-a-z0-9][\.]?)*[a-z0-9]\.[a-z]{2,9})';
    var reg1 = inline ? new RegExp(reg_str, 'i') : new RegExp('^'+reg_str+'$', 'i');
    var reg2 = /[\._\-\@]{2}/;
    return reg1.test(input) && !reg2.test(input) ? true : false;
    }
  return false;
  }
// find a value in a specific array and returns the index
function find_in_array()
program/localization/de/labels.inc
@@ -119,6 +119,8 @@
$labels['high']    = 'Hoch';
$labels['highest'] = 'Höchste';
$labels['nosubject']  = '(kein Betreff)';
$labels['showimages'] = 'Bilder anzeigen';
program/localization/de/messages.inc
@@ -32,7 +32,9 @@
$messages['mailboxempty'] = 'Ordner ist leer';
$messages['loadingdata'] = 'Daten werden geladen...';
$messages['loading'] = $messages['loadingdata'] = 'Daten werden geladen...';
$messages['sendingmessage'] = 'Nachricht wird gesendet...';
$messages['messagesent'] = 'Nachricht erfolgreich gesendet';
@@ -52,5 +54,18 @@
$messages['errorsaving'] = 'Beim Speichern ist ein Fehler aufgetreten';
$messages['formincomplete']    = 'Das Formular wurde nicht vollständig ausgefüllt';
$messages['noemailwarning']    = 'Bitte geben Sie eine gültige E-Mail-Adresse ein';
$messages['nonamewarning']     = 'Bitte geben Sie einen Namen ein';
$messages['nopagesizewarning'] = 'Bitte geben Sie eine Einträge pro Seite ein';
$messages['norecipientwarning'] = 'Bitte geben Sie mindestens einen Empfänger an';
$messages['nosubjectwarning']  = 'Die Betreffzeile ist leer. Möchten Sie jetzt einen Betreff eingeben?';
$messages['nobodywarning'] = 'Diese Nachricht ohne Inhalt senden?';
?>
program/localization/en/labels.inc
@@ -119,6 +119,8 @@
$labels['high']    = 'High';
$labels['highest'] = 'Highest';
$labels['nosubject']  = '(no subject)';
$labels['showimages'] = 'Display images';
program/localization/en/messages.inc
@@ -32,7 +32,11 @@
$messages['mailboxempty'] = 'Mailbox is empty';
$messages['loading'] = 'Loading...';
$messages['loadingdata'] = 'Loading data...';
$messages['sendingmessage'] = 'Sending message...';
$messages['messagesent'] = 'Message sent successfully';
@@ -56,5 +60,21 @@
$messages['errordeleting'] = 'Could not delete the message';
$messages['errordeleting'] = 'Could not delete the message';
$messages['formincomplete']    = 'The form was not completely filled out';
$messages['noemailwarning']    = 'Please enter a valid email address';
$messages['nonamewarning']     = 'Please enter a name';
$messages['nopagesizewarning'] = 'Please enter a page size';
$messages['norecipientwarning'] = 'Please enter at least one recipient';
$messages['nosubjectwarning']  = 'The "Subject" field is empty. Would you like to enter one now?';
$messages['nobodywarning'] = 'Send this message without text?';
?>
program/steps/addressbook/edit.inc
@@ -31,7 +31,7 @@
             $_SESSION['user_id']);
  
  $CONTACT_RECORD = $DB->fetch_assoc();
  if (is_array($CONTACT_RECORD))
    $OUTPUT->add_script(sprintf("%s.set_env('cid', '%s');", $JS_OBJECT_NAME, $CONTACT_RECORD['contact_id']));
  }
@@ -45,6 +45,10 @@
  if (!$CONTACT_RECORD && $GLOBALS['_action']!='add')
    return rcube_label('contactnotfound');
  // add some labels to client
  rcube_add_label('noemailwarning');
  rcube_add_label('nonamewarning');
  list($form_start, $form_end) = get_form_tags($attrib);
  unset($attrib['form']);
  
program/steps/addressbook/save.inc
@@ -23,6 +23,15 @@
$a_save_cols = array('name', 'firstname', 'surname', 'email');
// check input
if (empty($_POST['_name']) || empty($_POST['_email']))
  {
  show_message('formincomplete', 'warning');
  rcmail_overwrite_action($_POST['_cid'] ? 'show' : 'add');
  return;
  }
// update an existing contact
if ($_POST['_cid'])
  {
@@ -34,7 +43,7 @@
    if (!isset($_POST[$fname]))
      continue;
    
    $a_write_sql[] = sprintf("%s='%s'", $col, addslashes(strip_tags($_POST[$fname])));
    $a_write_sql[] = sprintf("%s=%s", $DB->quoteIdentifier($col), $DB->quote(strip_tags($_POST[$fname])));
    }
  if (sizeof($a_write_sql))
@@ -87,7 +96,7 @@
    {
    // show error message
    show_message('errorsaving', 'error');
    $_action = 'show';
    rcmail_overwrite_action('show');
    }
  }
@@ -95,6 +104,22 @@
else
  {
  $a_insert_cols = $a_insert_values = array();
  // check for existing contacts
  $sql_result = $DB->query("SELECT 1 FROM ".get_table_name('contacts')."
                            WHERE  user_id=?
                            AND    email=?
                            AND    del<>'1'",
                           $_SESSION['user_id'],
                           $_POST['_email']);
  // show warning message
  if ($DB->num_rows($sql_result))
    {
    show_message('contactexists', 'warning');
    $_action = 'add';
    return;
    }
  foreach ($a_save_cols as $col)
    {
@@ -103,13 +128,13 @@
      continue;
    
    $a_insert_cols[] = $col;
    $a_insert_values[] = sprintf("'%s'", addslashes(strip_tags($_POST[$fname])));
    $a_insert_values[] = $DB->quote(strip_tags($_POST[$fname]));
    }
    
  if (sizeof($a_insert_cols))
    {
    $DB->query("INSERT INTO ".get_table_name('contacts')."
                (user_id, changedm ".join(', ', $a_insert_cols).")
                (user_id, changed, ".join(', ', $a_insert_cols).")
                VALUES (?, now(), ".join(', ', $a_insert_values).")",
                $_SESSION['user_id']);
                       
@@ -153,7 +178,7 @@
    {
    // show error message
    show_message('errorsaving', 'error');
    $_action = 'add';
    rcmail_overwrite_action('add');
    }
  }
program/steps/mail/compose.inc
@@ -32,6 +32,10 @@
  $_SESSION['compose'] = array('id' => uniqid(rand()));
// add some labels to client
rcube_add_label('nosubject', 'norecipientwarning', 'nosubjectwarning', 'nobodywarning', 'sendingmessage');
if ($_GET['_reply_uid'] || $_GET['_forward_uid'])
  {
  $msg_uid = $_GET['_reply_uid'] ? $_GET['_reply_uid'] : $_GET['_forward_uid'];
program/steps/mail/sendmail.inc
@@ -28,7 +28,7 @@
if (!isset($_SESSION['compose']['id']))
  {
  $_action = 'list';
  rcmail_overwrite_action('list');
  return;
  }
@@ -63,6 +63,14 @@
/****** check submission and compose message ********/
if (empty($_POST['_to']) && empty($_POST['_subject']) && $_POST['_message'])
  {
  show_message("sendingfailed", 'error');
  rcmail_overwrite_action('compose');
  return;
  }
$mailto_regexp = array('/,\s*[\r\n]+/', '/[\r\n]+/', '/,\s*$/m');
@@ -206,9 +214,8 @@
// return to compose page if sending failed
if (!$sent)
  {
  $_action = 'compose';
  $OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action));
  show_message("sendingfailed", 'error'); 
  rcmail_overwrite_action('compose');
  return;
  }
program/steps/settings/edit_identity.inc
@@ -48,6 +48,11 @@
  if (!$IDENTITY_RECORD && $GLOBALS['_action']!='add-identity')
    return rcube_label('notfound');
  // add some labels to client
  rcube_add_label('noemailwarning');
  rcube_add_label('nonamewarning');
  list($form_start, $form_end) = get_form_tags($attrib, 'save-identity', array('name' => '_iid', 'value' => $IDENTITY_RECORD['identity_id']));
  unset($attrib['form']);
program/steps/settings/func.inc
@@ -34,6 +34,9 @@
  {
  global $DB, $CONFIG, $sess_user_lang;
  // add some labels to client
  rcube_add_label('nopagesizewarning');
  list($form_start, $form_end) = get_form_tags($attrib, 'save-prefs');
  unset($attrib['form']);
program/steps/settings/save_identity.inc
@@ -22,6 +22,15 @@
$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'default');
// check input
if (empty($_POST['_name']) || empty($_POST['_email']))
  {
  show_message('formincomplete', 'warning');
  rcmail_overwrite_action('edit-identitiy');
  return;
  }
// update an existing contact
if ($_POST['_iid'])
  {
@@ -33,7 +42,7 @@
    if (!isset($_POST[$fname]))
      continue;
    $a_write_sql[] = sprintf("`%s`='%s'", $col, addslashes(strip_tags($_POST[$fname])));
    $a_write_sql[] = sprintf("%s=%s", $DB->quoteIdentifier($col), $DB->quote(strip_tags($_POST[$fname])));
    }
  if (sizeof($a_write_sql))
@@ -56,11 +65,11 @@
    // mark all other identities as 'not-default'
    $DB->query("UPDATE ".get_table_name('identities')."
                SET ".$DB->quoteIdentifier('default')."='0'
                WHERE  identity_id!=?
                AND    user_id=?
                WHERE  user_id=?
                AND    identity_id<>?
                AND    del<>'1'",
                $_POST['_iid'],
                $_SESSION['user_id']);
                $_SESSION['user_id'],
                $_POST['_iid']);
    
    if ($_POST['_framed'])
      {
@@ -71,7 +80,8 @@
  else
    {
    // show error message
    show_message('errorsaving', 'error');
    rcmail_overwrite_action('edit-identitiy');
    }
  }
@@ -87,7 +97,7 @@
      continue;
    
    $a_insert_cols[] = $DB->quoteIdentifier($col);
    $a_insert_values[] = sprintf("'%s'", addslashes(strip_tags($_POST[$fname])));
    $a_insert_values[] = $DB->quote(strip_tags($_POST[$fname]));
    }
    
  if (sizeof($a_insert_cols))
@@ -113,18 +123,13 @@
  else
    {
    // show error message
    show_message('errorsaving', 'error');
    rcmail_overwrite_action('edit-identitiy');
    }
  }
// go to next step
if ($_POST['_framed'])
  $_action = 'edit-identitiy';
else
  $_action = 'identities';
// overwrite action variable
$OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action));
rcmail_overwrite_action($_POST['_framed'] ? 'edit-identitiy' : 'identities');
?>