diff options
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | program/include/rcube_shared.inc | 8 | ||||
-rw-r--r-- | program/include/rcube_vcard.php | 11 | ||||
-rw-r--r-- | program/js/app.js | 101 | ||||
-rw-r--r-- | program/js/list.js | 6 | ||||
-rw-r--r-- | program/steps/addressbook/export.inc | 43 | ||||
-rw-r--r-- | program/steps/mail/get.inc | 18 | ||||
-rw-r--r-- | skins/default/templates/addcontact.html | 2 |
8 files changed, 131 insertions, 62 deletions
@@ -1,6 +1,10 @@ CHANGELOG RoundCube Webmail --------------------------- +2008/09/04 (thomasb) +---------- +- Enable export of address book contacts as vCard + 2008/09/04 (alec) ---------- - Truncate very long (above 50 characters) attachment filenames when displaying diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 0dd661ec5..5008251ad 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -37,8 +37,14 @@ function send_nocacheing_headers() header("Expires: ".gmdate("D, d M Y H:i:s")." GMT"); header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); - header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); + + // We need to set the following headers to make downloads work using IE in HTTPS mode. + if (isset($_SERVER['HTTPS'])) { + header('Pragma: '); + header('Cache-Control: '); + } } diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 560d37d17..3ad47a5cb 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -28,7 +28,10 @@ */ class rcube_vcard { - private $raw = array(); + private $raw = array( + 'FN' => array(), + 'N' => array(array('','','','','')), + ); public $business = false; public $displayname; @@ -98,7 +101,7 @@ class rcube_vcard * @param string Field value * @param string Section name */ - public function set($field, $value, $section = 'home') + public function set($field, $value, $section = 'HOME') { switch ($field) { case 'name': @@ -222,7 +225,7 @@ class rcube_vcard private static function rfc2425_fold($val) { - return preg_replace('/:([^\n]{72,})/e', '":\n ".rtrim(chunk_split("\\1", 72, "\n "))', $val) . "\n\n"; + return preg_replace('/:([^\n]{72,})/e', '":\n ".rtrim(chunk_split("\\1", 72, "\n "))', $val) . "\n"; } @@ -325,7 +328,7 @@ class rcube_vcard } } - return "BEGIN:VCARD\nVERSION:3.0\n{$vcard}END:VCARD\n"; + return "BEGIN:VCARD\nVERSION:3.0\n{$vcard}END:VCARD"; } diff --git a/program/js/app.js b/program/js/app.js index 7ba8572b3..3e49fc3b2 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -205,10 +205,7 @@ function rcube_webmail() if (this.env.messagecount) this.enable_command('select-all', 'select-none', 'expunge', true); - if (this.env.messagecount - && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox - || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) - || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))) + if (this.purge_mailbox_test()) this.enable_command('purge', true); this.set_page_buttons(); @@ -282,6 +279,9 @@ function rcube_webmail() this.enable_command('save', true); else this.enable_command('search', 'reset-search', 'moveto', 'import', true); + + if (this.contact_list && this.contact_list.rowcount > 0) + this.enable_command('export', true); this.enable_command('list', true); break; @@ -1002,7 +1002,17 @@ function rcube_webmail() } else this.goto_url('import'); - break + break; + + case 'export': + if (this.contact_list.rowcount > 0) { + var add_url = ''; + if (this.env.search_request) + add_url = '_search='+this.env.search_request; + + this.goto_url('export', add_url); + } + break; // collapse/expand folder case 'collapse-folder': @@ -1490,7 +1500,15 @@ function rcube_webmail() return true; }; - + // test if purge command is allowed + this.purge_mailbox_test = function() + { + return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox + || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) + || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))); + }; + + // move selected messages to the specified mailbox this.move_messages = function(mbox) { @@ -1900,7 +1918,8 @@ function rcube_webmail() } } }; - + + /*********************************************************/ /********* login form methods *********/ /*********************************************************/ @@ -3599,6 +3618,7 @@ function rcube_webmail() } this.contact_list.insert_row(row); + this.enable_command('export', (this.contact_list.rowcount > 0)); }; @@ -3739,53 +3759,46 @@ function rcube_webmail() eval(request_obj.get_text()); // process the response data according to the sent action - switch (request_obj.__action) - { - + switch (request_obj.__action) { case 'delete': - if (this.task == 'addressbook') - { - var uid = this.contact_list.get_selection(); - this.enable_command('compose', (uid && this.contact_list.rows[uid])); - this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); - break; - } + if (this.task == 'addressbook') { + var uid = this.contact_list.get_selection(); + this.enable_command('compose', (uid && this.contact_list.rows[uid])); + this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly)); + this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); + } + case 'moveto': - if (this.env.action=='show') + if (this.env.action == 'show') this.command('list'); else if (this.message_list) this.message_list.init(); - + break; + case 'purge': case 'expunge': - if (!this.env.messagecount && this.task == 'mail') - { - // clear preview pane content - if (this.env.contentframe) - this.show_contentframe(false); - // disable commands useless when mailbox is empty - this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', - 'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false); - } - break; - - case 'list': - this.msglist_select(this.message_list); + if (!this.env.messagecount && this.task == 'mail') { + // clear preview pane content + if (this.env.contentframe) + this.show_contentframe(false); + // disable commands useless when mailbox is empty + this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', + 'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false); + } + break; case 'check-recent': case 'getunread': - if (this.task == 'mail') - { - this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0)); - var mailboxtest = (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox - || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) - || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter))) ? true : false; - - this.enable_command('purge', (this.env.messagecount && mailboxtest)); - } - break; - - } + case 'list': + if (this.task == 'mail') { + this.msglist_select(this.message_list); + this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0)); + this.enable_command('purge', this.purge_mailbox_test()); + } + else if (this.task == 'addressbook') + this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); + break; + } request_obj.reset(); }; diff --git a/program/js/list.js b/program/js/list.js index 1986e8b25..97549f7eb 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -31,6 +31,7 @@ function rcube_list_widget(list, p) this.frame = null; this.rows = []; this.selection = []; + this.rowcount = 0; this.subject_col = -1; this.shiftkey = false; @@ -69,6 +70,7 @@ init: function() if (this.list && this.list.tBodies[0]) { this.rows = new Array(); + this.rowcount = 0; var row; for(var r=0; r<this.list.tBodies[0].childNodes.length; r++) @@ -81,6 +83,7 @@ init: function() } this.init_row(row); + this.rowcount++; } this.frame = this.list.parentNode; @@ -128,6 +131,7 @@ clear: function(sel) this.list.insertBefore(tbody, this.list.tBodies[0]); this.list.removeChild(this.list.tBodies[1]); this.rows = new Array(); + this.rowcount = 0; if (sel) this.clear_selection(); }, @@ -145,6 +149,7 @@ remove_row: function(uid, sel_next) this.select_next(); this.rows[uid] = null; + this.rowcount--; }, @@ -161,6 +166,7 @@ insert_row: function(row, attop) tbody.appendChild(row); this.init_row(row); + this.rowcount++; }, diff --git a/program/steps/addressbook/export.inc b/program/steps/addressbook/export.inc new file mode 100644 index 000000000..bfffac1f8 --- /dev/null +++ b/program/steps/addressbook/export.inc @@ -0,0 +1,43 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | program/steps/addressbook/export.inc | + | | + | This file is part of the RoundCube Webmail client | + | Copyright (C) 2008, RoundCube Dev. - Switzerland | + | Licensed under the GNU GPL | + | | + | PURPOSE: | + | Export the selected address book as vCard file | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id: $ + +*/ + +// get contacts for this user +$CONTACTS->set_pagesize(999); +$result = $CONTACTS->list_records(); + +// send downlaod headers +send_nocacheing_headers(); +header('Content-Type: text/x-vcard; charset=UTF-8'); +header('Content-Disposition: attachment; filename="rcube_contacts.vcf"'); + +while ($result && ($row = $result->next())) { + $vcard = new rcube_vcard($row['vcard']); + $vcard->set('displayname', $row['name']); + $vcard->set('firstname', $row['firstname']); + $vcard->set('surname', $row['surname']); + $vcard->set('email', $row['email']); + + echo $vcard->export(); +} + +exit; + +?> diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index b95784f19..fc3ee83ea 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -57,26 +57,20 @@ else if ($pid = get_input_value('_part', RCUBE_INPUT_GET)) { $browser = new rcube_browser; - header("Expires: 0"); - header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); - header("Cache-Control: private", false); - header("Content-Transfer-Encoding: binary"); - + send_nocacheing_headers(); + // send download headers if ($_GET['_download']) { header("Content-Type: application/octet-stream"); if ($browser->ie) header("Content-Type: application/force-download"); } - else if ($ctype_primary == 'text') + else if ($ctype_primary == 'text') { header("Content-Type: text/$ctype_secondary; charset=" . ($part->charset ? $part->charset : RCMAIL_CHARSET)); - else + } + else { header("Content-Type: $mimetype"); - - // We need to set the following headers to make downloads work using IE in HTTPS mode. - if (isset($_SERVER['HTTPS'])) { - header('Pragma: '); - header('Cache-Control: '); + header("Content-Transfer-Encoding: binary"); } // deliver part content diff --git a/skins/default/templates/addcontact.html b/skins/default/templates/addcontact.html index 70a796aa2..10a121a2f 100644 --- a/skins/default/templates/addcontact.html +++ b/skins/default/templates/addcontact.html @@ -14,7 +14,7 @@ <p><br /> <input type="button" value="<roundcube:label name="cancel" />" class="button" onclick="history.back()" /> -<roundcube:button command="save" type="input" class="button" label="save mainaction" /> +<roundcube:button command="save" type="input" class="button mainaction" label="save" /> </p> </form> |