From 6f096812c9fd460fddd21ff1cef55542cb79a890 Mon Sep 17 00:00:00 2001 From: alecpl Date: Tue, 2 Nov 2010 09:27:03 +0000 Subject: [PATCH] - Support contact's email addresses up to 255 characters long (#1487095) - Added email format checks when saving contacts data --- CHANGELOG | 1 + SQL/mssql.initial.sql | 2 +- SQL/mssql.upgrade.sql | 4 +++- SQL/mysql.initial.sql | 2 +- SQL/mysql.update.sql | 2 ++ SQL/postgres.initial.sql | 2 +- SQL/postgres.update.sql | 1 + SQL/sqlite.initial.sql | 2 +- SQL/sqlite.update.sql | 34 ++++++++++++++++++++++++++++++ program/js/common.js | 3 +-- program/steps/addressbook/save.inc | 27 ++++++++++++++---------- program/steps/mail/addcontact.inc | 14 ++++++++++-- 12 files changed, 74 insertions(+), 20 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dbd9b5af1..f5bbc4dd6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -58,6 +58,7 @@ CHANGELOG Roundcube Webmail - Plugin API: add possibility to disable plugin in framed mode, 'noframe' property - Improve performance of setting IMAP flags using .SILENT suffix - Improve performance of message cache status checking with skip_disabled=true +- Support contact's email addresses up to 255 characters long (#1487095) RELEASE 0.4.2 ------------- diff --git a/SQL/mssql.initial.sql b/SQL/mssql.initial.sql index 6b031a256..36788585f 100644 --- a/SQL/mssql.initial.sql +++ b/SQL/mssql.initial.sql @@ -13,7 +13,7 @@ CREATE TABLE [dbo].[contacts] ( [changed] [datetime] NOT NULL , [del] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL , [name] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , - [email] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , + [email] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL , [firstname] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , [surname] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL , [vcard] [text] COLLATE Latin1_General_CI_AI NULL diff --git a/SQL/mssql.upgrade.sql b/SQL/mssql.upgrade.sql index 6b3cd6d03..cf0c17157 100644 --- a/SQL/mssql.upgrade.sql +++ b/SQL/mssql.upgrade.sql @@ -22,7 +22,7 @@ ALTER TABLE [dbo].[identities] ADD CONSTRAINT [FK_identities_user_id] ON DELETE CASCADE ON UPDATE CASCADE GO -ALTER TABLE [dbo].[identities] add [changed] [datetime] NULL +ALTER TABLE [dbo].[identities] ADD [changed] [datetime] NULL GO CREATE TABLE [dbo].[contactgroups] ( @@ -93,4 +93,6 @@ DROP INDEX [IX_users_username] GO CREATE UNIQUE INDEX [IX_users_username] ON [dbo].[users]([username],[mail_host]) ON [PRIMARY] GO +ALTER TABLE [dbo].[contacts] ALTER COLUMN [email] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL +GO diff --git a/SQL/mysql.initial.sql b/SQL/mysql.initial.sql index 456a48313..6e2c24731 100644 --- a/SQL/mysql.initial.sql +++ b/SQL/mysql.initial.sql @@ -83,7 +83,7 @@ CREATE TABLE `contacts` ( `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `del` tinyint(1) NOT NULL DEFAULT '0', `name` varchar(128) NOT NULL DEFAULT '', - `email` varchar(128) NOT NULL, + `email` varchar(255) NOT NULL, `firstname` varchar(128) NOT NULL DEFAULT '', `surname` varchar(128) NOT NULL DEFAULT '', `vcard` text NULL, diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql index b9ab59ea9..2af0a47e6 100644 --- a/SQL/mysql.update.sql +++ b/SQL/mysql.update.sql @@ -129,3 +129,5 @@ UPDATE `users` SET `last_login` = NULL WHERE `last_login` = '1000-01-01 00:00:00 ALTER TABLE `users` DROP INDEX `username_index`; ALTER TABLE `users` ADD UNIQUE `username` (`username`, `mail_host`); +ALTER TABLE `contacts` MODIFY `email` varchar(255) NOT NULL; + diff --git a/SQL/postgres.initial.sql b/SQL/postgres.initial.sql index 84a9afd40..089cae036 100644 --- a/SQL/postgres.initial.sql +++ b/SQL/postgres.initial.sql @@ -107,7 +107,7 @@ CREATE TABLE contacts ( changed timestamp with time zone DEFAULT now() NOT NULL, del smallint DEFAULT 0 NOT NULL, name varchar(128) DEFAULT '' NOT NULL, - email varchar(128) DEFAULT '' NOT NULL, + email varchar(255) DEFAULT '' NOT NULL, firstname varchar(128) DEFAULT '' NOT NULL, surname varchar(128) DEFAULT '' NOT NULL, vcard text diff --git a/SQL/postgres.update.sql b/SQL/postgres.update.sql index 99b9c0e29..444caf6f6 100644 --- a/SQL/postgres.update.sql +++ b/SQL/postgres.update.sql @@ -86,4 +86,5 @@ ALTER TABLE users ALTER last_login SET DEFAULT NULL; DROP INDEX users_username_id_idx; ALTER TABLE users ADD UNIQUE (username, mail_host); +ALTER TABLE contacts ALTER email TYPE varchar(255); diff --git a/SQL/sqlite.initial.sql b/SQL/sqlite.initial.sql index ea7650cb7..875b3cba0 100644 --- a/SQL/sqlite.initial.sql +++ b/SQL/sqlite.initial.sql @@ -28,7 +28,7 @@ CREATE TABLE contacts ( changed datetime NOT NULL default '0000-00-00 00:00:00', del tinyint NOT NULL default '0', name varchar(128) NOT NULL default '', - email varchar(128) NOT NULL default '', + email varchar(255) NOT NULL default '', firstname varchar(128) NOT NULL default '', surname varchar(128) NOT NULL default '', vcard text NOT NULL default '' diff --git a/SQL/sqlite.update.sql b/SQL/sqlite.update.sql index 78e283e2d..328693944 100644 --- a/SQL/sqlite.update.sql +++ b/SQL/sqlite.update.sql @@ -146,3 +146,37 @@ DROP TABLE tmp_users; DROP INDEX ix_users_username; CREATE UNIQUE INDEX ix_users_username ON users(username, mail_host); +CREATE TABLE contacts_tmp ( + contact_id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL default '0', + changed datetime NOT NULL default '0000-00-00 00:00:00', + del tinyint NOT NULL default '0', + name varchar(128) NOT NULL default '', + email varchar(255) NOT NULL default '', + firstname varchar(128) NOT NULL default '', + surname varchar(128) NOT NULL default '', + vcard text NOT NULL default '' +); + +INSERT INTO contacts_tmp (contact_id, user_id, changed, del, name, email, firstname, surname, vcard) + SELECT contact_id, user_id, changed, del, name, email, firstname, surname, vcard FROM contacts; + +DROP TABLE contacts; +CREATE TABLE contacts ( + contact_id integer NOT NULL PRIMARY KEY, + user_id integer NOT NULL default '0', + changed datetime NOT NULL default '0000-00-00 00:00:00', + del tinyint NOT NULL default '0', + name varchar(128) NOT NULL default '', + email varchar(255) NOT NULL default '', + firstname varchar(128) NOT NULL default '', + surname varchar(128) NOT NULL default '', + vcard text NOT NULL default '' +); + +INSERT INTO contacts (contact_id, user_id, changed, del, name, email, firstname, surname, vcard) + SELECT contact_id, user_id, changed, del, name, email, firstname, surname, vcard FROM contacts_tmp; + +CREATE INDEX ix_contacts_user_id ON contacts(user_id, email); +DROP TABLE contacts_tmp; + diff --git a/program/js/common.js b/program/js/common.js index 3a8739ba2..76ddd7269 100644 --- a/program/js/common.js +++ b/program/js/common.js @@ -491,12 +491,11 @@ function rcube_check_email(input, inline) quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22', // Use simplified domain matching, because we need to allow Unicode characters here // So, e-mail address should be validated also on server side after idn_to_ascii() use - sub_domain = '[^@]+', //domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d', //sub_domain = '('+atom+'|'+domain_literal+')', + domain = '([^@\\x2e]+\\x2e)+[a-z]{2,}', word = '('+atom+'|'+quoted_string+')', delim = '[,;\s\n]', - domain = sub_domain+'(\\x2e'+sub_domain+')*', local_part = word+'(\\x2e'+word+')*', addr_spec = local_part+'\\x40'+domain, reg1 = inline ? new RegExp('(^|<|'+delim+')'+addr_spec+'($|>|'+delim+')', 'i') : new RegExp('^'+addr_spec+'$', 'i'); diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc index f0244b4a9..f074f18a4 100644 --- a/program/steps/addressbook/save.inc +++ b/program/steps/addressbook/save.inc @@ -20,19 +20,17 @@ */ $cid = get_input_value('_cid', RCUBE_INPUT_POST); -$return_action = empty($cid) ? 'add' : 'show'; +$return_action = empty($cid) ? 'add' : 'edit'; // cannot edit record -if ($CONTACTS->readonly) -{ +if ($CONTACTS->readonly) { $OUTPUT->show_message('contactreadonly', 'error'); rcmail_overwrite_action($return_action); return; } -// check input -if ((!get_input_value('_name', RCUBE_INPUT_POST) || !get_input_value('_email', RCUBE_INPUT_POST))) -{ +// Basic input checks +if ((!get_input_value('_name', RCUBE_INPUT_POST) || !get_input_value('_email', RCUBE_INPUT_POST))) { $OUTPUT->show_message('formincomplete', 'warning'); rcmail_overwrite_action($return_action); return; @@ -44,20 +42,27 @@ $a_save_cols = array('name', 'firstname', 'surname', 'email'); $a_record = array(); // read POST values into hash array -foreach ($a_save_cols as $col) -{ +foreach ($a_save_cols as $col) { $fname = '_'.$col; if (isset($_POST[$fname])) $a_record[$col] = get_input_value($fname, RCUBE_INPUT_POST); } +// Validity checks +$_email = idn_to_ascii($a_record['email']); +if (!check_email($_email, false)) { + $OUTPUT->show_message('emailformaterror', 'warning', array('email' => $_email)); + rcmail_overwrite_action($return_action); + return; +} + // update an existing contact if (!empty($cid)) { $plugin = $RCMAIL->plugins->exec_hook('contact_update', array('id' => $cid, 'record' => $a_record, 'source' => get_input_value('_source', RCUBE_INPUT_GPC))); $a_record = $plugin['record']; - + if (!$plugin['abort']) $result = $CONTACTS->update($cid, $a_record); else @@ -70,7 +75,7 @@ if (!empty($cid)) // change cid in POST for 'show' action $_POST['_cid'] = $newcid; } - + // define list of cols to be displayed $a_js_cols = array(); $record = $CONTACTS->get_record($newcid ? $newcid : $cid, true); @@ -80,7 +85,7 @@ if (!empty($cid)) // update the changed col in list $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid); - + // show confirmation $OUTPUT->show_message('successfullysaved', 'confirmation', null, false); rcmail_overwrite_action('show'); diff --git a/program/steps/mail/addcontact.inc b/program/steps/mail/addcontact.inc index d46db8ece..613a63e39 100644 --- a/program/steps/mail/addcontact.inc +++ b/program/steps/mail/addcontact.inc @@ -29,13 +29,23 @@ $CONTACTS = $RCMAIL->get_address_book(null, true); if (!empty($_POST['_address']) && is_object($CONTACTS)) { $contact_arr = $IMAP->decode_address_list(get_input_value('_address', RCUBE_INPUT_POST, true), 1, false); - + if (!empty($contact_arr[1]['mailto'])) { $contact = array( 'email' => $contact_arr[1]['mailto'], 'name' => $contact_arr[1]['name'] ); + // Validity checks + if (empty($contact['email'])) { + $OUTPUT->show_message('errorsavingcontact', 'error'); + $OUTPUT->send(); + } + else if (!check_email($contact['email'], false)) { + $OUTPUT->show_message('emailformaterror', 'error', array('email' => $contact['email'])); + $OUTPUT->send(); + } + $contact['email'] = idn_to_utf8($contact['email']); // use email address part for name @@ -60,7 +70,7 @@ if (!empty($_POST['_address']) && is_object($CONTACTS)) } if (!$done) - $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsavingcontact', 'warning'); + $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsavingcontact', 'error'); $OUTPUT->send();