Page MenuHomePhorge

No OneTemporary

Size
337 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/CHANGELOG b/CHANGELOG
index 4a41b8d84..ae2bae58b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,2138 +1,2139 @@
CHANGELOG Roundcube Webmail
===========================
+- Password: Allow temporarily disabling the plugin functionality with a notice
- Support more secure hashing algorithms for auth cookie - configurable by PHP's session.hash_function (#1490403)
- Require Mbstring and OpenSSL extensions (#1490415)
- Get rid of Mail_mimeDecode package dependency (#1490416)
- Add --config and --type options to moduserprefs.sh script (#1490051)
- Implemented memcache_debug and apc_debug options
- Installer: Remove system() function use (#1490139)
- Password plugin: Added 'kpasswd' driver by Peter Allgeyer
- Add initdb.sh to create database from initial.sql script with prefix support (#1490188)
- Plugin API: Added message_part_body hook
- Plugin API: Added message_ready hook
- Plugin API: Add special onload() method to execute plugin actions before startup (session and GUI initialization)
- Implemented UI element to jump to specified page of the messages list (#1485235)
- Fix so microseconds macro (u) in log_date_format works (#1490446)
- Fix so unrecognized TNEF attachments are displayed on the list of attachments (#1490351)
- Fix "Importing..." message does not hide on error (#1490422)
- Fix Compose action in addressbook for results from multiple addressbooks (#1490413)
- Fix bug where some messages in multi-folder search couldn't be viewed/printed/downloaded (#1490426)
- Fix unintentional messages list page change on page switch in compose addressbook (#1490427)
- Fix race-condition in saving user preferences and loading plugin config (#1490431)
- Fix so plain text signature field uses monospace font (#1490435)
- Fix so links with href == content aren't added to links list on html to text conversion (#1490434)
- Fix handling of non-break spaces in html to text conversion (#1490436)
- Fix self-reply detection issues (#1490439)
- Fix multi-folder search result sorting by arrival date (#1490450)
- Fix so *-request@ addresses in Sender: header are also ignored on reply-all (#1490452)
- Update to TinyMCE 4.1.10 (#1490405)
RELEASE 1.1.2
-------------
- Add new plugin hook 'identity_create_after' providing the ID of the inserted identity (#1490358)
- Add option to place signature at bottom of the quoted text even in top-posting mode [sig_below]
- Fix handling of %-encoded entities in mailto: URLs (#1490346)
- Fix zipped messages downloads after selecting all messages in a folder (#1490339)
- Fix vpopmaild driver of password plugin
- Fix PHP warning: Non-static method PEAR::setErrorHandling() should not be called statically (#1490343)
- Fix tables listing routine on mysql and postgres so it skips system or other database tables and views (#1490337)
- Fix message list header in classic skin on window resize in Internet Explorer (#1490213)
- Fix so text/calendar parts are listed as attachments even if not marked as such (#1490325)
- Fix lack of signature separator for plain text signatures in html mode (#1490352)
- Fix font artifact in Google Chrome on Windows (#1490353)
- Fix bug where forced extwin page reload could exit from the extwin mode (#1490350)
- Fix bug where some unrelated attachments in multipart/related message were not listed (#1490355)
- Fix mouseup event handling when dragging a list record (#1490359)
- Fix bug where preview_pane setting wasn't always saved into user preferences (#1490362)
- Fix bug where messages count was not updated after message move/delete with skip_deleted=false (#1490372)
- Fix security issue in contact photo handling (#1490379)
- Fix possible memcache/apc cache data consistency issues (#1490390)
- Fix bug where imap_conn_options were ignored in IMAP connection test (#1490392)
- Fix bug where some files could have "executable" extension when stored in temp folder (#1490377)
- Fix attached file path unsetting in database_attachments plugin (#1490393)
- Fix issues when using moduserprefs.sh without --user argument (#1490399)
- Fix potential info disclosure issue by protecting directory access (#1490378)
- Fix blank image in html_signature when saving identity changes (#1490412)
- Installer: Use openssl_random_pseudo_bytes() (if available) to generate des_key (#1490402)
- Fix XSS vulnerability in _mbox argument handling (#1490417)
RELEASE 1.1.1
-------------
- ACL: Allow other plugins to adjust the list of permissions and groups to edit
- Add possibility to print contact information (of a single contact)
- Add possibility to configure max_allowed_packet value for all database engines (#1490283)
- Improved handling of storage errors after message is sent
- Update to TinyMCE 4.1.9
- Unified request* event arguments handling, added support for _unlock and _action parameters
- Security: Generate random hash for the per-user local storage prefix (#1490279)
- Fix refreshing of drafts list when sending a message which was saved in meantime (#1490238)
- Fix saving/sending emoticon images when assets_dir is set
- Fix PHP fatal error when visiting Vacation interface and there's no sieve script yet (#1490292)
- Fix setting max packet size for DB caches and check packet size also in shared cache
- Fix needless security warning on BMP attachments display (#1490282)
- Fix handling of some improper constructs in format=flowed text as per the RFC3676[4.5] (#1490284)
- Fix performance of rcube_db_mysql::get_variable()
- Fix missing or not up-to-date CATEGORIES entry in vCard export (#1490277)
- Fix fatal errors on systems without mbstring extension or mb_regex_encoding() function (#1490280)
- Fix cursor position on reply below the quote in HTML mode (#1490263)
- Fix so "over quota" errors are displayed also in message compose page
- Fix duplicate entries supression in autocomplete result (#1490290)
- Fix "Non-static method PEAR::isError() should not be called statically" errors (#1490281)
- Fix parsing invalid HTML messages with BOM after <!DOCTYPE> (#1490291)
- Fix duplicate entry on timezones list in rcube_config::timezone_name_from_abbr() (#1490293)
- Fix so localized folder name is displayed in multi-folder search result (#1490243)
- Fix javascript error after creating a folder which is a subfolder of another one (#1490297)
- Fix bug where subject of sent/saved message was removed if mbstring wasn't installed (#1490295)
- Fix missing vcard_attachment icon on messages list (#1490303)
- Fix storing signatures with big images in MySQL database (#1490306)
- Fix Opera browser detection in javascript (#1490307)
- Fix so search filter, scope and fields are reset on folder change
- Fix rows count when messages search fails (#1490266)
- Fix bug where spellchecking in HTML editor do not work after switching editor type more than once (#1490311)
- Fix bug where TinyMCE area height was too small on slow network connection (#1490310)
- Fix backtick character handling in sql queries (#1490312)
- Fix redirect URL for attachments loaded in an iframe when behind a proxy (#1490191)
- Fix menu container references to point to the actual <ul> element (#1490313)
- Fix javascripts errors in IE8 - lack of Event.which, focusing a hidden element (#1490318)
RELEASE 1.1.0
-------------
- Make SMTP error log more verbose - include server response and error code
- Fix download options menu (added by zipdownload plugin) in classic skin (#1490228)
- Fix blocked.gif image usage with assets_dir set
- Fix bug where max_group_members was ignored when adding a new contact (#1490214)
- Hide MDN and DSN options in compose if disabled by admin (#1490221)
- Fix checks based on window.ActiveXObject in IE > 10
- Fix XSS issue in style attribute handling (#1490227)
- Fix bug where Drafts list wasn't updated on draft-save action in new window (#1490225)
- Fix so "set as default" option is hidden if identities_level > 1 (#1490226)
- Fix bug where search was reset after returning from compose visited for reply
- Fix javascript error in "IE 8.0/Tablet PC" browser (#1490210)
- Fix bug where Reply-To address was ignored on reply to messages sent by self (#1490233)
- Fix bug where empty fieldmap config entries caused empty results of ldap search (#1490229)
- Fix bug where drafts list wasn't refreshed after draft message was sent from another window (#1490238)
- Fix keyboard navigation and css in datepicker widget across many Firefox versions
- Fix false warning when opening attached text/plain files (#1490241)
- Fix bug where signature could have been inserted twice after plain-to-html switch (#1490239)
- Fix security issue in DBMail driver of password plugin (#1490261)
- Enable FollowSymLinks option in .htaccess file which is required by rewrite rules (#1490255)
- Fix so JSON.parse() errors on localStorage items are ignored (#1490249)
RELEASE 1.1-rc
--------------
- Update jQuery to version 2.1.3
- Allow to override any config option through env variables
- Improve system security by using optional special URL with security token - use_secure_urls
- Allow to define separate server/path for image/js/css files - assets_url/assets_dir
- Sync vendor folder if exists in source package (#1490145)
- Avoid useless reloading list when resetting search with active filter (#1490057)
- Fix invalid folder selection if clicked while busy (#1490158)
- Fix import of multiple contact email addresses from Outlook-csv format (#1490169)
- Fix drag-n-drop to folders expanded while dragging (#1490157)
- Fix import of multiple contact groups from Google-csv format (#1490159)
- Fix import of contacts with multiple email addresses from Google-csv format (#1490178)
- Fix bugs where CSRF attacks were still possible on some requests
- Fix some rcube_utils::anytodatetime() corner cases with timezone mismatches (#1490163)
- Improve move-to and contact-export button in classic skin (#1490166)
- Fix wrong icon for download button in classic skin
- Fix bug where sent message was saved in Sent folder even if disabled by user (#1490208)
RELEASE 1.1-beta
----------------
- Fix skin path handling in plugin context (#1488967)
- Prevent memory exhaustion on image resizing with GD on Windows (#1489937)
- Add plugin hook for database table name lookups as requested in #1489837
- Added Oracle database support
- Support contacts import in GMail CSV format
- Added namespace filter in Folder Manager
- Added folder searching in Folder Manager
- Fix restoring draft messages from localStorage if editor mode differs (#1490016)
- Added config option/user preference to disable saving messages in localStorage (#1489979)
- Added config option 'imap_log_session' to enable Roundcube <-> IMAP session ID logging
- Added config option 'log_session_id' to control the lengh of the session identifer in logs
- Implemented 'storage_connected' API hook after successful IMAP login (#1490025)
- Intergrate Net_LDAP3 and rcube_ldap_generic classes
- Add option (disabled_actions) to disable UI elements/actions (#1489638)
- Support password encryption using openssl extension (#1489989)
- Create/rename groups in UI dialogs (#1489951)
- Added 'contact_search_name' option to define autocompletion entry format
- Display quota information for current folder not INBOX only (#1487993)
- Support images in HTML signatures (#1488676)
- Display full quota information in popup (#1485769, #1486604)
- Mail compose: Selecting contact inserts recipient to previously focused input - to/cc/bcc accordingly (#1489684)
- Close "no subject" prompt with Enter key (#1489580)
- Password: Add option to force new users to change their password (#1486884)
- Improve support for screen readers and assistive technology using WCAG 2.0 and WAI ARIA standards
- Enable basic keyboard navigation throughout the UI (#1487845)
- Select/scroll to previously selected message when returning from message page (#1489023)
- Display a warning if popup window was blocked (#1489618)
- Remove (was: ...) from message subject on reply (#1489375)
- Update to TinyMCE 4.1 (#1489057)
- Enable autolink plugin in TinyMCE (#1488845)
- Support image operations with Imagick extension (#1489734)
- Support upload progress with session.upload_progress and PECL uploadprogress module (#1488702)
- Make identity name field optional (#1489510)
- Utility script to remove user records from the local database
- Plugin API: Added message_saved hook (#1489752)
- Plugin API: Added imap_search_before hook
- Support messages import from zip archives
- Zipdownload: Added mbox format support (#1486069)
- Drop support for IE6, move IE7/IE8 support to legacy_browser plugin
- Update to jQuery-2.1.1
- Search across multiple folders (#1485234)
- Improve UI integration of ACL settings
- Drop support for PHP < 5.3.7
- Set In-Reply-To and References for forwarded messages (#1489593)
- Removed redundant default_folders config option (#1489737)
- Implemented IMAP SPECIAL-USE extension support [RFC6154] (#1487830)
- Optimize some framed pages content for better performance (#1489792)
- Improve text messages display and conversion to HTML (#1488937)
- Don't remove links when html signature is converted to text (#1489621)
- Fix page title when using search filter (#1490023)
- Fix mbox files import
- Fix some character sets detection (#1490135)
- Fix so attachment charset is set in headers of forward/draft message (#1490109)
- Fix bug where wrong charset could be used for text attachment preview page (#1490106)
RELEASE 1.0.5
-------------
- Fix wrong icon for download button in classic skin
- Fix checks based on window.ActiveXObject in IE > 10
- Fix XSS issue in style attribute handling (#1490227)
- Fix bug where Drafts list wasn't updated on draft-save action in new window (#1490225)
- Fix so "set as default" option is hidden if identities_level > 1 (#1490226)
- Fix javascript error in "IE 8.0/Tablet PC" browser (#1490210)
- Fix bug where empty fieldmap config entries caused empty results of ldap search (#1490229)
- Fix bug where sent message was saved in Sent folder even if disabled by user (#1490208)
RELEASE 1.0.4
-------------
- Disable TinyMCE contextmenu plugin as there are more cons than pros in using it (#1490118)
- Fix bug where show_real_foldernames setting wasn't honored on compose page (#1490153)
- Fix issue where Archive folder wasn't protected in Folder Manager (#1490154)
- Fix compatibility with PHP 5.2. in rcube_imap_generic (#1490115)
- Fix setting flags on servers with no PERMANENTFLAGS response (#1490087)
- Fix regression in SHAA password generation in ldap driver of password plugin (#1490094)
- Fix displaying of HTML messages with absolutely positioned elements in Larry skin (#1490103)
- Fix font style display issue in HTML messages with styled <span> elements (#1490101)
- Fix download of attachments that are part of TNEF message (#1490091)
- Fix handling of uuencoded messages if messages_cache is enabled (#1490108)
- Fix handling of base64-encoded attachments with extra spaces (#1490111)
- Fix handling of UNKNOWN-CTE response, try do decode content client-side (#1490046)
- Fix bug where creating subfolders in shared folders wasn't possible without ACL extension (#1490113)
- Fix reply scrolling issue with text mode and start message below the quote (#1490114)
- Fix possible issues in skin/skin_path config handling (#1490125)
- Fix lack of delimiter for recipient addresses in smtp_log (#1490150)
- Fix generation of Blowfish-based password hashes (#1490184)
- Fix bugs where CSRF attacks were still possible on some requests [CVE-2014-9587]
RELEASE 1.0.3
-------------
- Initialize HTML editor before restoring a message from localStorage (#1490016)
- Add 'sig_max_lines' config option to default config file (#1490071)
- Add config option to specify IMAP connection socket parameters - imap_conn_options (#1489948)
- Add option to set default message list mode - default_list_mode (#1487312)
- Enable contextmenu plugin for TinyMCE editor (#1487014)
- Fix insert-signature command in external compose window if opened from inline compose screen (#1490074)
- Fix some mime-type to extension mapping checks in Installer (#1489983)
- Fix errors when using localStorage in Safari's private browsing mode (#1489996)
- Fix bug where $Forwarded flag was being set even if server didn't support it (#1490000)
- Fix various iCloud vCard issues, added fallback for external photos (#1489993)
- Fix invalid Content-Type header when send_format_flowed=false (#1489992)
- Fix errors when adding/updating contacts in active search (#1490015)
- Fix incorrect thumbnail rotation with GD and exif orientation data (#1490029)
- Fix contacts list update after adding/deleting/moving a contact (#1490028, #1490033)
- Fix handling of email addresses with quoted domain part (#1490040)
- Fix comm_path update on task switch (#1490041)
- Fix error in MSSQL update script 2013061000.sql (#1490061)
- Fix validation of email addresses with IDNA domains (#1490067)
RELEASE 1.0.2
-------------
- Fix storing unsaved drafts in localStorage (#1489818)
- Add configurable LDAP_OPT_DEREF option (#1489864)
- Fix so when switching editor mode original version of signature is used (#1488849)
- Fix unintentional draft autosave request if autosave is disabled (#1489882)
- Fix malformed References: header in send/saved mail (#1489891)
- Fix handling unicode characters in links (#1489898)
- Fix incorrect handling of HTML comments in messages sanitization code (#1489904)
- Fix so current page is reset on list-mode change (#1489907)
- Fix so responses menu hides on click in classic skin (#1489915)
- Fix unintentional line-height style modification in HTML messages (#1489917)
- Fix broken normalize_string(), add support for ISO-8859-2 (#1489918)
- Support csv contacts import in German localization (#1489920)
- Fix so message list and counters are updated when a message is opened in new window (#1489919)
- Fix malformed recipient name when composing a message by clicking on mailto link (#1489942)
- Fix list reload after sending message in another window (#1489931)
- Fix so address format errors are ignored when saving a draft (#1489954)
- Fix incorrect label translation in return receipt (#1489963)
- Fix security issue in delete-response action - allow only ajax request
- Fix Delete button state after deleting identity/response (#1489972)
- Fix bug where contacts with no email address were listed on compose addressbook (#1489970)
- Fix images import from various vCard formats (#1489977)
- Fix sorting messages by size on servers without SORT capability (#1489981)
RELEASE 1.0.1
-------------
- Support 'error' and 'body_file' return attribs in 'message_before_send' hook (#1489595)
- Apply user-specific replacements to group's base_dn property (#1489779)
- Fix missing email address when importing contacts from outlook csv (#1489830)
- Fix bug where "With attachment" option in search filter wasn't selected after return from mail view (#1489774)
- Fix "washing" of unicoded style attributes (#1489777)
- Fix unintentional redirect from compose page in Webkit browsers (#1489789)
- Fix messages index cache update under some conditions (e.g. proxy) (#1489756)
- Fix lack of translation of special folders in some configurations (#1489799)
- Fix XSS issue in plain text spellchecker (#1489806)
- Fix invalid page title for some folders (1489804)
- Fix redundant alert message on over-size uploads (#1489817)
- Fix next message display after removing a message (#1489800)
- Fix missing Mail-Followup-To header in sent mail (#1489829)
- Fix error when spell-checking an empty text (#1489831)
- Avoid popupmenus being closed when scrollbar is clicked (#1489832)
- Add proxy_whitelist configuration option (#1489729)
- Fix identities_level=4 handling in new_user_dialog plugin (#1489840)
- Fix various db_prefix issues (#1489839)
- Fix too small length of users.preferences column data type on MySQL
- Fix redundant warning when switching from html to text in empty editor (#1489819)
- Fix invalid host validation on login (#1489841)
- Fix IMAP connection test in installer so it is aware of imap_auth_type (#1489746)
RELEASE 1.0.0
-------------
- Added toolbar button to move message in message view
- Fix style of disabled protocol handler link on IE (#1489569)
- Fix message import dialog when no file is selected (#1489685)
- Fix opening compose screen in new window after saving as draft (#1489643)
- Fix directories check in Installer on Windows (#1489576)
- Fix issue when default_addressbook option is set to integer value (#1489407)
- Fix Opera > 15 detection (#1489562)
- Fix security issue in DomainFactory driver of Password plugin
- Fix invalid X-Draft-Info on forwarded message draft (#1489587)
- Fix regression in handling of 'attachments' result in message_compose hook (#1489627)
- Fix issue where msgexport.sh printed the message to STDOUT instead of a file (#1489634)
- Fix fatal error in database_attachments plugin under some conditions (#1489726)
RELEASE 1.0-rc
--------------
- Small CSS fix with message notice boxes in Larry skin (#1489497)
- Include groups in contacts search on mail compose (#1489082)
- Add mime-type mapping for .7z files (#1489512)
- Invoke update scripts with php to circumvent execution restrictions (#1489322)
- Fix drag & drop message/contact moving on touch device (#1489431)
- Fix canned responses in HTML mode (#1489536)
- Check/create default folders on every login not only the first (#1489423)
- Update to jQuery-1.11.0 and jQuery-UI-1.9.2
- Support SMTP socket context options via new config option 'smtp_conn_options'
- Fix compatibility with PHP 5.2 in html.php file (#1489514)
- Remove expand/collapse with plus/minus keys (on numeric keypad) (#1489513)
- Fix issue where filesystem path was added to all-attachments (zip) file (#1489507)
- Fix case-sensitivity of email addresses handling on compose (#1485499)
- Don't alter Message-ID of a draft when sending (#1489409)
- Fix issue where deprecated syntax for HTML lists was not handled properly (#1488768)
- Display different icons when Trash folder is empty or full (#1485775)
- Remember last position of more headers switch (#1488323)
- Fix so message flags modified by another client are applied on the list on refresh (#1485186)
- Fix broken text/* attachments when forwarding/editing a message (#1489426)
- Improved minified files handling, added css minification (#1486988)
- Fix handling of X-Forwarded-For header with multiple addresses (#1489481)
- Fix border issue on folders list in classic skin (#1489473)
- Implemented menu actions to copy/move messages, added folder-selector widget (#1484086)
- Fix security rules in .htaccess preventing access to base URL without the ending slash (#1489477)
- Fix regression where only first new folder was placed in correct place on the list (#1489472)
- Fix issue where children of selected and collapsed thread were skipped on various actions (#1489457)
- Fix issue where groups were not deleted when "Replace entire addressbook" option on contacts import was used (#1489420)
- Fix unreliable mimetype tests in Installer (#1489453)
- Fix performance of listing writeable folders (#1489451)
RELEASE 1.0-beta
----------------
- Fix handling of invalid closing tags in HTML messages (#1489446)
- Set real content-type for file downloads (#1489439)
- Update TinyMCE to version 3.5.10 (#1489442)
- Fix keyboard navigation in list widgets (#1489392)
- Allow plugins to grab the reference of opened windows (#1489413)
- Larry skin: Improved status message display for better visibility (#1488974)
- Fix Internet Explorer 11 detection (#1489434)
- Fix date column width to fit the widest possible date format (#1489368)
- Move certain user preference options to a collapsed "advanced" block (#1488829)
- Add file type icons for Powerpoint and Open Office presentations (#1489225)
- Fix operations on folders with trailing spaces in name (#1489419)
- Improve identity selection based on From: header (#1489378)
- Fix issue where mails with inline images of the same name contained only the first image multiple times (#1489406)
- Use left/right arrow keys to collapse/expand thread and spacebar to select a row, change Ctrl key behavior (#1489392)
- Fix an issue where using arrow keys to go up a list can result in selected message being under headers (#1489403)
- Fix an issue where Home/End keys don't focus list row properly, don't scrollTo properly (#1489396)
- Add an option to disable smart Reply-List behaviour - reply_all_mode (#1488734)
- Fix an issue where pressing minus key on contacts list was hiding list records (#1489393)
- Fix an issue where shift + arrow-up key wasn't selecting all messages in collapsed thread (#1489397)
- Added icon for priority column in messages list header (#1489234)
- New feature "Canned Responses" to save and recall boilerplate text snippets
- Fix HTML part detection when encapsulated inside multipart/signed (#1489372)
- Add spellchecker backend for the After the Deadline service
- Replace markdown-style [1] link indexes in plain text email bodies
- Improved mailto: link arguments handling (#1489363)
- Use DOMDocument LIBXML_PARSEHUGE and LIBXML_COMPACT options if possible (#1489302)
- Support HTTP_HOST, SERVER_NAME and SERVER_ADDR values in include_host_config feature
- Make default font size for HTML messages configurable (request #118)
- Fix XSS issue in addressbook group name field [CVE-2013-5646] (#1489333)
- After message is sent refresh messages list of replied message folder (#1489249)
- Add option force specified domain in user login - username_domain_forced (#1489264)
- Add option to import Vcards with group assignments
- Save groups membership in Vcard export (#1488509)
- Workaround broken PHP function timezone_name_from_abbr (#1489261)
- Make cached message size limit configurable - messages_cache_threshold (#1489317)
- Log also failed logins to userlogins log
- Add temp_dir_ttl configuration option (#1489304)
- Allow setting INBOX as Sent folder (#1489219)
- Fix replacement variables in user-specific base_dn in some LDAP requests (#1489279)
- Fix image scaling issues when image has only one dimension smaller than the limit (#1489274)
- Fix issue where uploaded photo was lost when contact form did not validate (#1489274)
- Move identity selection based on non-standard headers into (new) identity_select plugin (#1488553)
- Fix downloading binary files with (wrong) text/* content-type (#1489267)
- Respect HTTP_X_FORWARDED_FOR and HTTP_X_REAL_IP variables for session IP check
- Simplified configuration by merging it into one file + defaults (#1487311)
- Make message list header stay on top when scrolling (#1295420)
- Add support for 'enchant' spellcheck engine
- Check filetype detection in installer and update script (#1489193)
- Fix folder names truncation in Classic skin (#1489220)
- Make possible to disable some (broken) IMAP extensions with imap_disable_caps option (#1489184)
- Contacts drag-n-drop default action is to move contacts (#1488751)
- Added possibility to choose to move or copy contacts from drag-n-drop menu (#1488751)
- Fix Close link and remove About link on error pages (#1489109)
- Improved/unified attachment preview screen, added print button
- Fix lack of space between searchfiler and quicksearchbar in Larry skin (#1489158)
- Cache LDAP's user_specific search and use vlv for better performance (#1489186)
- LDAP: auto-detect and use VLV indices for all search operations
- LDAP: additional group configuration options for address books
- LDAP: separated address book implementation from a generic LDAP wrapper class
- Allow address books to browse a multi-level group hierarchy in the contacts list
- Fix session issues when local and database time differs (#1486132)
- Fix thread cache syncronization/validation (#1489028)
- Added feature to import messages to the currently selected folder
- Add option show_real_foldernames to disable localization of special folders
- Fix database cache expunge issues (#1489149)
- Fix date format issues on MS SQL Server (#1488918)
- Add imap_cache_ttl option to configure TTL of imap_cache
- Make LDAP cache engine configurable via ldap_cache and ldap_cache_ttl options
- Fix "duplicate entry" errors on inserts to imap cache tables (#1489146)
- Improved handling of Reply-To/Bcc addresses of identity in compose form (#1489016)
- Added user preference to open all popups as standard windows
- Implemented shared cache (rcube_cache_shared)
- Change Reply-All button label/title when mailing list is detected (#1488938)
- Fix SMTP connection using IPv6 address in smtp_server option (#1489024)
- Added attachment_reminder plugin
- Make PHP code eval() free, use create_function()
- Add option to display email address together with a name in mail preview (#1488732)
- Support CSV import from Atmail (#1489045)
- Add db_prefix configuration option in place of db_table_*/db_sequence_* options
- Make possible to use db_prefix for schema initialization in Installer (#1489067)
- Fix updatedb.sh script so it recognizes also table prefix for external DDL files
- Fix parsing invalid date string (#1489035)
- Add "with attachment" option to messages list filter (#1485382)
- Call resize handler in intervals to prevent lags and double onresize calls in Chrome (#1489005)
- Add rel="noreferrer" for links in displayed messages (#1484686)
- Add ability to toggle between HTML and text while viewing a message (#1486939)
- Remove "HTML message" from attachments list while viewing a message in text mode (#1486939)
- Support IMAP MOVE extension [RFC 6851]
- Add attachment menu with Open and Download options (#1488975)
- Display user-friendly message on IMAP "over quota" errors (#1484164)
- Extended archive plugin with user-configurable options to store messages into subfolders
- Fix export of selected contacts from search result (#1488905)
- Feature to export only selected contacts from addressbook (by Phil Weir)
RELEASE 0.9.5
-------------
- Fix failing vCard import when email address field contains spaces (#1489386)
- Fix default spell-check configuration after Google suspended their spell service
- Fix vulnerability in handling _session argument of utils/save-prefs [CVE-2013-6172] (#1489382)
- Fix iframe onload for upload errors handling (#1489379)
- Fix address matching in Return-Path header on identity selection (#1489374)
- Fix text wrapping issue with long unwrappable lines (#1489371)
- Fixed issues where HTML comments inside style tag would hang Internet Explorer
- Hide Delivery Status Notification option when smtp_server is unset (#1489336)
- Display full attachment name using title attribute when name is too long to display (#1489320)
- Fix attachment icon issue when rare font/language is used (#1489326)
- Fix expanded thread root message styling after refreshing messages list (#1489327)
- Fix issue where From address was removed from Cc and Bcc fields when editing a draft (#1489319)
- Fix error_reporting directive check (#1489323)
- Fix de_DE localization of "About" label in Help plugin (#1489325)
RELEASE 0.9.4
-------------
- Make identities matching case insensitive (#1485480)
- Fix issue where too big message data was stored in cache causing sql errors (#1489316)
- Fix iframe scrollbars on webkit desktop browsers (#1489306)
- Fix issue where legacy config was overriden by default config (#1489288)
- Fix newmail_notifier issue where favicon wasn't changed back to default (#1489313)
- Fix setting of Junk and NonJunk flags by markasjunk plugin (#1489285)
- Fix lack of Reply-To address in header of forwarded message body (#1489298)
- Fix bugs when invoking contact creation form when read-only addressbook is selected (#1489296)
- Fix identity selection on reply (#1489291)
- Fix so additional headers are added to all messages sent (#1489284)
- Fix display issue after moving folder in Folder Manager (#1489293)
- Fix handling of non-default date formats (#1489294)
- Fix unquoted path in PREG expression on Windows (#1489290)
- Fix wrong close tag in /template/mail.html (#1489295)
RELEASE 0.9.3
-------------
- Fix setting refresh_interval to "Never" in Preferences (#1489286)
- Fixed iframe scrolling on touch devices
- Optimized message list for touch devices
- Fix purge action in folder manager (#1489280)
- Fix base URL resolving on attribute values with no quotes (#1489275)
- Fix wrong handling of links with '|' character (#1489276)
- Fix colorspace issue on image conversion using ImageMagick (#1489270)
- Fix XSS vulnerability when editing a message "as new" or draft [CVE-2013-5645] (#1489251)
- Fix XSS vulnerability when saving HTML signatures [CVE-2013-5645] (#1489251)
- Fix rewrite rule in .htaccess (#1489240)
- Fix detecting Turkish language in ISO-8859-9 encoding (#1489252)
- Fix identity-selection using Return-Path headers (#1489241)
- Fix parsing of links with ... in URL (#1489192)
- Fix compose priority selector when opening in new window (#1489257)
- Fix bug where signature wasn't changed on identity selection when editing a draft (#1489229)
- Fix IMAP SETMETADATA parameters quoting (#1489231)
- Fix "could not load message" error on valid empty message body (#1489228)
- Fix handling of message/rfc822 attachments on message forward and edit (#1489214)
- Fix parsing of square bracket characters in IMAP response strings (#1489223)
- Don't clear References and in-Reply-To when a message is "edited as new" (#1489216)
- Fix messages list sorting with THREAD=REFS
- Remove deprecated (in PHP 5.5) PREG /e modifier usage (#1489174)
- Fix empty messages list when register_globals is enabled (#1489157)
- Fix so valid and set date.timezone is not required by installer checks (#1489180)
- Canonize boolean ini_get() results (#1489189)
- Fix so install do not fail when one of DB driver checks fails but other drivers exist (#1489178)
- Fix so exported vCard specifies encoding in v3-compatible format (#1489183)
RELEASE 0.9.2
-------------
- Fix image thumbnails display in print mode (#1489134)
- Fix height of message headers block (#1489108)
- Fix timeout issue on drag&drop uploads (#1489170)
- Fix default sorting of threaded list when THREAD=REFS isn't supported
- Fix list mode switch to 'List' after saving list settings in Larry skin (#1489164)
- Fix error when there's no writeable addressbook source (#1489162)
- Fix zipdownload plugin issue with filenames charset (#1489156)
- Fix so non-inline images aren't skipped on forward (#1489150)
- Fix "null" instead of empty string on messages list in IE10 (#1489145)
- Fix legacy options handling
- Fix so bounces addresses in Sender headers are skipped on Reply-All (#1489011)
- Fix bug where serialized strings were truncated in PDO::quote() (#1489142)
- Fix displaying messages with invalid self-closing HTML tags (#1489137)
- Fix PHP warning when responding to a message with many Return-Path headers (#1489136)
- Fix unintentional compose window resize (#1489114)
- Fix performance regression in text wrapping function (#1489133)
- Fix connection to posgtres db using unix socket (#1489132)
- Fix handling of comma when adding contact from contacts widget (#1489107)
- Fix bug where a message was opened in both preview pane and new window on double-click (#1489122)
- Fix fatal error when xdebug.max_nesting_level was exceeded in rcube_washtml (#1489110)
- Fix PHP warning in html_table::set_row_attribs() in PHP 5.4 (#1489094)
- Fix invalid option selected in default_font selector when font is unset (#1489112)
- Fix displaying contact with ID divisible by 100 in sql addressbook (#1489121)
- Fix browser warnings on PDF plugin detection (#1489118)
- Fix fatal error when parsing UUencoded messages (#1489119)
RELEASE 0.9.1
-------------
- Better German labels for from/to to avoid conflicts with 'sender' (#1489084)
- Fix problem where security warning was displayed for valid images with image/jpg type (#1489097)
- Fix handling of invalid email addresses in headers (#1489092)
- Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090)
- Fix various PHP code bugs found using static analysis (#1489086)
- Fix backslash character handling on vCard import (#1489085)
- Fix csv import from Thunderbird with French localization (#1489059)
- Fix messages list focus issue in Opera and Webkit (#1489058)
- Fix Reply-To header handling in Reply-All action (#1489037)
- Fix so Sender: address is added to Cc: field on reply to all (#1489011)
- Fix so addressbook_search_mode works also for group search (#1489079)
- Fix removal of a contact from a group in LDAP addressbook (#1489081)
- Inlcude SQL query in the log on SQL error (#1489064)
- Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074)
- Fix very small window size in Chrome (#1488931)
- Fix list page reset when viewing a message in Larry skin (#1489076)
- Fix min_refresh_interval handling on preferences save (#1489073)
- Fix PDF support detection for Firefox PDF.js (#1488972)
- Fix possible collision in generated thumbnail cache key (#1489069)
- Fix exit code on bootsrap errors in CLI mode (#1489044)
- Fix error handling in CLI mode, use STDERR and non-empty exit code (#1489043)
- Fix error when using check_referer=true
- Fix incorrect handling of some specific links (#1489060)
- Fix incorrect handling of leading spaces in text wrapping
- Fix unintentional messages list jumps on click in Internet Explorer (#1489056)
- Fix list of required configuration options (#1489055)
- Fix DB error when creating a new contact and a group is selected (#1489051)
- Fix handling of deprecated boolean value of reply_mode option (#1489052)
RELEASE 0.9.0
-------------
- Fix display of HTML entities in protected folder name (#1489042)
- Set minimal permissions to temp files (#1488996)
- Improve content check for embedded images without filename (#1489029)
- Fix handling of invalid characters in message headers and output (#1489032)
- Fix selecting collapsed rows on select-all (#1489036)
- Avoid race-conditions with concurrent attachment uploads (#1488422)
- Fix possible header duplicates when using additional headers (#1489033)
- Fix session issues with use_https=true (#1488986)
- Fix blockquote width in sent mail (#1489031)
- Fix keyboard events on list widgets in Internet Explorer (#1489025)
RELEASE 0.9-rc2
---------------
- Fix security issue in save-pref command
- Remove sig_above configuration option, use reply_mode only (#1489001)
- Refresh current folder in opener window after draft save or message sent (#1488997)
- Fix saving draft just after entering compose window (#1489012)
- Fix javascript error in IE9 when loading form with placeholders into an iframe (#1489008)
- Fix handling of some conditional comment tags in HTML message (#1489004)
- Fix so forward as attachment works if additional attachment is added by message_compose hook (#1489000)
- Better handling of session errors in ajax requests (#1488960)
- Fix HTML part detection for some specific message structures (#1488992)
- Don't show fake address - phishing prevention (#1488981)
- Fix forward as attachment bug with editormode != 1 (#1488991)
- Fix LIMIT/OFFSET queries handling on MS SQL Server (#1488984)
- Fix so task name can really contain all from a-z0-9_- characters (#1488941)
- Fix javascript errors when working in a page opened with taget="_blank"
- Mention SQLite database format change in UPGRADING file (#1488983)
- Increase maxlength to 254 chars for email input fields in addressbook (#1488987)
- Fix thumbnail size when GD extension is used for image resize (#1488985)
- Display notice that message is encrypted also for application/pkcs7-mime messages (#1488526)
RELEASE 0.9-rc
--------------
- Fix plain text spellchecker incorrect highlighting in non-ASCII text (#1488973)
- Add workaround for invalid message charset detection by IMAP servers (#1488968)
- Fix NUL characters in content-type of ms-tnef attachment (#1488964)
- Fix regression in handling LDAP contact identifiers (#1488959)
- Updated translations from Transifex
- Fix buggy error template in a frame (#1488938)
- Add addressbook widget on compose page in classic skin
- Add search box to compose address book widget (#1488381)
- Fix login in case when default_host is an array with one element (#1488928)
- Use LDAP fallback hosts on connect + bind instead of ldap_connect() only.
- Add config option for LDAP bind timeout (sets LDAP_OPT_NETWORK_TIMEOUT option)
- Submit Addressbook advanced search form with Enter key (#1488568)
- Also block remote images in HTML part view (#1488827)
- Improved database schema upgrade procedure, added updatedb.sh script
- Force autocommit mode in mysql database driver (#1488902)
RELEASE 0.9-beta
----------------
- Fix searching by date in address book (#1488888)
- Improve charset detection by prioritizing charset according to user language (#1485669)
- Fix handling of escaped separator in vCard file (#1488896)
- Add option to use envelope From address for MDN responses (#1488880)
- Add possibility to search in message body only (#1488770)
- Support "multipart/relative" as an alias for "multipart/related" type (#1488886)
- Display PGP/MIME signature attachments as "Digital Signature" (#1488570)
- Workaround UW-IMAP bug where hierarchy separator is added to the shared folder name (#1488879)
- Fix version comparisons with -stable suffix (#1488876)
- Add unsupported alternative parts to attachments list (#1488870)
- Add Compose button on message view page (#1488747)
- Display 'Sender' header in message preview
- Plugin API: Added message_before_send hook
- Fix contact copy/add-to-group operations on search result (#1488862)
- Use matching identity in MDN response (#1488864)
- Fix handling of signatures on draft edit (#1488798)
- Fix so compacting of non-empty folder is possible also when messages list is empty (#1488858)
- Allow forwarding of multiple emails (#1486854)
- Fix big memory consumption of DB layer (#1488856)
- Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836)
- Fix empty email on identities list after identity update (#1488834)
- Add new identities_level: (4) one identity with possibility to edit only signature
- Use Delivered-To and Envelope-To headers for identity selection (#1488840, #1488553)
- Fix XSS vulnerability using Flash files (#1488828)
- Always save drafts with format=flowed in order to keep original line wraps (#1488799)
- Select default_addressbook on the list in Address Book (#1488280)
- Fix so mobile phone has TYPE=CELL in exported vCard (#1488812)
- Support contacts import from CSV file (#1486399)
- Improved keep-alive action. Now the interval is based on session_lifetime (#1488507)
- Added cross-task 'refresh' request for system state updates (#1488507)
- Renamed config options: keep_alive to refresh_interval, min_keep_alive to min_refresh_interval
- Fix handling of text/enriched content on message reply/forward/edit
- Option to display attached images as thumbnails below message body
- Upgraded to jQuery 1.8.3 and jQuery UI 1.9.1
- Add config option to automatically generate LDAP attributes for new entries
- Add user settings to open message view and compose form in new windows (#1485486)
- Better client-side timezone detection using the jsTimezoneDetect library (#1488725)
- Add option to disable saving sent mail in Sent folder - no_save_sent_messages (#1488686)
- Fix handling dont_override with message_sort_col and message_sort_order settings (#1488760)
- Fix handling of URLs with asterisk characters (#1488759)
- Remove automatic to-lowercase conversion of usernames (#1488715)
- Plugin API: Add 'email_list' argument for identities data in user_create hook
- Integrated zipdownload plugin to download all attachments (#1445509)
- Fix HTML special characters handling in message list/header display (#1488523)
- List related text/html part as attachment in plain text mode (#1488677)
- Use IMAP BINARY (RFC3516) extension to fetch message/part bodies
- Fix folder creation under public namespace root (#1488665)
- Fix so "Edit as new" on draft creates a new message (#1488687)
- Fix invalid error message on deleting mail from read only folder (#1488694)
- Replace data URIs of images (pasted in HTML editor) with inline attachments (#1488502)
- Remove (too big) min-width on mail screen
- Added template object 'frame'
- Add option to enable HTML editor on forwarding (#1488517)
- Add option to not include original message on reply, rename option top_posting to reply_mode (#1485149)
- Added session_path config option and unified cookies settings in javascript
- Added "Undeleted" option to messages list filter
- Rewritten test scripts for PHPUnit
- Add new DB abstraction layer based on PHP PDO, supporting SQLite3 (#1488332)
- Removed PEAR::MDB2 package
- Removed users.alias column, added option ('user_aliases')
to use email address from identities as username (#1488581)
- Removed redundant cache.cache_id column (#1488528)
- Fix order of attachments in sent mail (#1488423)
- Fix Shift + delete button does not permanently delete messages (#1488243)
- Add Content-Length for attachments where possible (#1485478)
- Fix attachment sizes in message print page and attachment preview page (#1488515)
- Add mail attachments using drag & drop on HTML5 enabled browsers
- Add workaround for invalid BODYSTRUCTURE response - parse message with Mail_mimeDecode package (#1485585)
- Display Tiff as Jpeg in browsers without Tiff support (#1488452)
- Don't display Pdf/Tiff/Flash attachments inline without browser support (#1488452, #1487929)
- Add is_escaped attribute for html_select and html_textarea (#1488485)
- Fix issue where draft auto-save wasn't executed after some inactivity time
- Add vCard import from multiple files at once (#1488015)
- Roundcube Framework:
Add possibility to replace IMAP driver with custom class
Add IMAP auto-connection feature, improving performance with caching enabled
Replace imap_init hook with storage_init (with additional 'driver' argument)
Improved performance by caching IMAP server's capabilities in session
Unified global functions naming (rcube_ prefix)
Better classes separation
Framework files moved to lib/Roundcube
RELEASE 0.8.5
-------------
- Fix #countcontrols issue in IE<=8 when text is very long (#1488890)
- Fix unwanted horizontal scrollbar in message preview header (#1488866)
- Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844)
- Fix XSS vulnerability in vbscript: and data:text links handling [CVE-2012-6121] (#1488850)
- Fix absolute positioning in HTML messages (#1488819)
- Fix cache (in)validation after setting \Deleted flag
- Fix keybord events on messages list in opera browser (#1488823)
- Fix selection of collapsed thread rows (#1488772)
- Fix wrapping of quoted text with format=flowed (#1488177)
RELEASE 0.8.4
-------------
- Fix regression where unintentional page reload was done after request abort (#1488802)
- Fix XSS vulnerability in handling of text/enriched messages (#1488806)
- Fix handling of 'media' attribute on linked css (#1488789)
- Fix excessive LFs at the end of composed message with top_posting=true (#1488797)
- Fix bug where leading blanks were stripped from quoted lines (#1488795)
RELEASE 0.8.3
-------------
- Fix AREA links handling (#1488792)
- Fix possible HTTP DoS on error in keep-alive requests (#1488782)
- Fix compatybility with MDB2 2.5.0b4 (#1488779)
- Fix a bug where saving a message in INBOX wasn't possible
- Fix HTML part detection in messages with attachments (#1488769)
- Fix bug where wrong words were highlighted on spell-before-send check
- Fix scrolling quirk in email preview frame using Opera 12 (#1488763)
- Fix displaying of multipart/alternative messages with empty parts (#1488750)
- Fix threaded list sorting on PHP < 5.2.9 (#1488748)
- Fix Warning: htmlspecialchars(): charset `RCMAIL_CHARSET' not supported warning in Installer (#1488744)
RELEASE 0.8.2
-------------
- Fix XSS vulnerability from HTTP User-Agent header (#1488737)
- Force fonts in compose fields to be all the same (#1488690)
- Fix handling vCard entries with TEL;TYPE=CELL (#1488728)
- Fix error where session wasn't updated after folder rename/delete (#1488692)
- Fix PLAIN authentication for some IMAP servers (#1488674)
- Fix encoding vCard file when contains PHOTO;ENCODING=b (#1488683)
- Fix focus issue in IE when selecting message row (#1488620)
- Add full headers view in message preview window (#1488538)
- Fix message display page issues - unified with message preview (#1488590, #1488642)
- Fix displaying all headers when they contain malformed characters (#1488666)
- Fix decoding of HTML messages with UTF-16 charset specified (#1488654)
- Fix quota capability detection so it can be overwritten by a plugin (#1488655)
- Fix identity selection on reply (#1488101)
- Fix Larry's messages list filter in IE (#1488632)
- Fix more IE issues by disabling Compat. mode with X-UA-Compatible meta tag (#1488626)
- Fix setting locales under Solaris - use additional .UTF-8 suffix (#1488628)
- Fix email address validation for addresses with IP address in domain part
- Fix Larry skin issues in IE7 compat. mode (#1488618)
- Fix so subscribed non-existing/non-accessible shared folder can be unsubscribed
RELEASE 0.8.1
-------------
- Fix bug where domain name was converted to lower-case even with login_lc=false (#1488593)
- Fix lower-casing email address on replies (#1488598)
- Fix line separator in exported messages (#1488603)
- Fix XSS issue where plain signatures wasn't secured in HTML mode [CVE-2012-4668] (#1488613)
- Fix XSS issue where href="javascript:" wasn't secured [CVE-2012-3508] (#1488613)
- Fix impossible to create message with empty plain text part (#1488610)
- Fix stripped apostrophes when replying in plain text to HTML message (#1488606)
- Fix inactive Save search option after advanced search (#1488607)
- Fix Remove from group option is active for contact search result (#1488608)
- Disable autocapitalization in login form on iPad/iPhone (#1488609)
- Fix focus on the list when list row is clicked (#1488600)
- Added separate From and To columns apart from smart From/To column (#1486891)
- Fix fallback to Larry skin when configured skin isn't available (#1488591)
- Fix (workaround) delete operations with some versions of memcache (#1488592)
- Fix (disable) request validation for spell and spell_html actions
RELEASE 0.8.0
-------------
- Don't show product version on login screen (can be enabled by config)
- Renamed old default skin to 'classic'. Larry is the new default skin.
- Support connections to memcached socket file (#1488577)
- Enable TinyMCE inlinepopups plugin
- Update to TinyMCE 3.5.6
- Correctly escape localized labels in javascript variable (#1488567)
- Update Net_SMTP/Auth_SASL packages to fix Digest-MD5/Cram-MD5 authentication (#1488571)
- Don't add attachments content into reply/forward/draft message body (#1488557)
- Fix 'no connection' errors on page unloads (#1488547)
- Plugin API: Add 'unauthenticated' hook (#1488138)
- Show explicit error message when provided hostname is invalid (#1488550)
- Fix wrong compose screen elements focus in IE9 (#1488541)
- Fix fatal error when date.timezone isn't set (#1488546)
- Update to TinyMCE 3.5.4.1
- Better icons with distinct shapes for priority columns (#1488377)
- Show dedicated icon for multipart/report messages (#1488524)
- Properly hide text of icon links/buttons (#1488534)
- Fix handling of unitless CSS size values in HTML message (#1488535)
- Fix removing contact photo using LDAP addressbook (#1488420)
- Fix storing X-ANNIVERSARY date in vCard format (#1488527)
- Update to Mail_Mime-1.8.5 (#1488521)
- Fix XSS vulnerability in message subject handling using Larry skin [CVE-2012-3507] (#1488519)
- Fix handling of links with various URI schemes e.g. "skype:" (#1488106)
- Fix handling of links inside PRE elements on html to text conversion
- Fix indexing of links on html to text conversion
- Decode header value in rcube_mime::get() by default (#1488511)
- Fix errors with enabled PHP magic_quotes_sybase option (#1488506)
- Fix SQL query for contacts listing on MS SQL Server (#1488505)
- Fix window.resize handler on IE8 and Opera (#1488453)
- Don't let error message popups cover the login form (#1488500)
- Update to TinyMCE 3.5.2
- Don't show errors when moving contacts into groups they are already in (#1488493)
- Make folders with unread messages in subfolders bold again (#1486793)
- Abbreviate long attachment file names with ellipsis (#1488499)
- Fix html2text conversion of strong|b|a|th|h tags when used in upper case
- Add listcontrols template container in Larry skin (#1488498)
- Fix host autoselection when default_host is an array (#1488495)
- Move messages forwarding mode setting into Preferences
- Fix HTML entities handling in HTML editor (#1488483)
- Fix listing shared folders on Courier IMAP (#1488466)
RELEASE 0.8-rc
--------------
- Added new translations in Belarusian, Interlingua and Malayalam
- Flipped compose options arrow (#1488474)
- Fix handling of large uuencode attachments (#1488473)
- Fix handling of "usemap" attribute (#1488472)
- Fix handling of some HTML tags e.g. IMG (#1488471)
- Use similar language as a fallback for plugin localization (#1488401)
- Fix issue where signature wasn't re-added on draft compose (#1488322)
- Update to TinyMCE 3.5 (#1488459)
- Fixed multi-threaded autocompletion when number of threads > number of sources
- Allow to configure the number of values allowed for each LDAP attribute
- Support for serialized LDAP address values (usually delimited with a $)
- Less restrictive session auth checks, repeat keep-alive requests on failure (#1488449)
- Fix redirect to mail/compose on re-login (#1488226)
- Add IE8 hack for messages list issue (#1487821)
- Fix handling errors on draft auto-save
- Fix importing vCard photo with ENCODING param specified (#1488432)
- Support mutliple name/email pairs for Bcc and Reply-To identity settings (#1488445)
- Set flexible width to login form fields (#1488418)
- Fix re-draw bug on list columns change in IE8 (#1487822)
- Allow mass-removal of addresses from a group (#1487748)
- Fix removing all contacts on import to LDAP addressbook
- Fix so "Back" from compose/show doesn't reset search request (#1488238)
- Add option to delete messages instead of moving to Trash when in Junk folder (#1486686)
- Fix invisible cursor when replying to a html message (#1487073)
- Reset IP stored in session when destroying session data (#1488056)
- Fix bug where memory_limit = -1 wasn't handled properly
- Support LDAP RFC2256's country object class read/write (#1488123)
- Upgraded to jQuery 1.7.2
- Image resize with GD extension (#1488383)
- Fix lack of warning when switching task in compose window (#1488399)
- Fix bug where it wasn't possible to enter ( or & characters in autocomplete fields
- Request all needed fields from address book backends (#1488394)
- Unified (single) spellchecker button
- Scroll long lists on drag&drop (#1485946)
- Copy all skins in installto script (#1488376)
RELEASE 0.8-beta
----------------
- Upgraded to jQuery 1.7.1 (#1488337) and jQuery UI 1.8.18
- Add Russian to the spellchecker languages list (#1488135)
- Remember custom skin selection after logout (#1488355)
- Make sure About tab is always the last tab (#1488257)
- Fix issue with folder creation under INBOX. namespace (#1488349)
- Added mailto: protocol handler registration link in User Preferences (#1486580)
- Handle identity details box with an iframe (#1487020)
- Fix issue where some text from original message was missing on reply (#1488340)
- Fix autoselect_host() for login (#1488297)
- Changed license to GNU GPLv3+ with exceptions for skins & plugins
- Added address book widget on compose screen
- Use proper timezones from PHP's internal timezonedb (#1485592)
- Add separate pagesize setting for mail messages and contacts (#1488269)
- Deprecate $DB, $USER, $IMAP global variables, Use $RCMAIL instead
- Add option to set default font for HTML message (#1484137)
- Fix issues with big memory allocation of IMAP results
- Prevent from memory_limit exceeding when trying to parse big messages bodies (#1487424)
- Add possibility to add SASL mechanisms for SMTP in smtp_connect hook (#1487937)
- Mark (with different color) folders with recent messages (#1486234)
- Added About tab in Settings
- TinyMCE updated to 3.4.6
RELEASE 0.7.2
-------------
- Fix encoding of attachment with comma in name (#1488389)
- Fix handling of % character in IMAP protocol (#1488382)
- Fix duplicate names handling in addressbook searches (#1488375)
- Fix displaying of HTML messages from Disqus (#1488372)
- Disable E_STRICT warnings on PHP 5.4
- Prevent from folder selection on virtual folder collapsing (#1488346)
- Fix automatic unsubscribe of non-existent folders
- Fix double-quotes handling in recipient names
- User configurable setting how to display contact names in list
- Make contacts list sorting configurable for the admin/user
- Fix parse errors in DDL files for MS SQL Server
- Revert SORT=DISPLAY support, removed by mistake (#1488327)
- Add lost translation label in de_DE (#1488315)
- Fix drafts update issues when edited from preview pane (#1488314)
- Fix wrong variable name in rcube_ldap.php (#1488302)
- Make mime type detection based on filename extension to be case-insensitive
- Fix failure on MySQL database upgrade from 0.7 - text column can't have default value (#1488300)
RELEASE 0.7.1
-------------
- Fix bug in handling of base href and inline content (#1488290)
- Fix SQL Error when saving a contact with many email addresses (#1488286)
- Fix strict email address searching if contact has more than one address
- Remove duplicated 'organization' label (#1488287)
- Fix so editor selector is hidden when 'htmleditor' is listed in 'dont_override'
- Fix wrong (long) label usage (#1488283)
- Fix handling of INBOX's subfolders in special folders config (#1488279)
- Add ifModule statement for setting Options -Indexes in .htaccess file (#1488274)
- Fix crashes with eAccelerator (#1488256)
- Fix searching on IMAP servers without CHARSET specifier support (#1488271)
- Fix expanding folders during drag&drop (#1488260)
- Fix wrong postgres sequence name in upgrade from 0.6
- Fix broken CREATE INDEX queries in SQLite DDL files (#1488255)
RELEASE 0.7
-----------
- Make Roundcube render the Email Standards Project Acid Test correctly
- Replace prompt() with jQuery UI dialog (#1485135)
- Fix navigation in messages search results
- Improved handling of some malformed values encoded with quoted-printable (#1488232)
- Add possibility to do LDAP bind before searching for bind DN
- Fix handling of empty <U> tags in HTML messages (#1488225)
- Add content filter for embedded attachments to protect from XSS on IE [CVE-2012-1253] (#1487895)
- Use strpos() instead of strstr() when possible (#1488211)
- Fix handling HTML entities when converting HTML to text (#1488212)
- Fix fit_string_to_size() renders browser and ui unresponsive (#1488207)
- Fix handling of invalid characters in request (#1488124)
- Fix merging some configuration options in update.sh script (#1485864)
- Fix so TEXT key will remove all HEADER keys in IMAP SEARCH (#1488208)
- Fix handling contact photo url with https:// prefix (#1488202)
- Fix possible infinite redirect on attachment preview (#1488199)
- Improved clickjacking protection for browsers which don't support X-Frame-Options headers
- Fixed bug where similar folder names were highlighted wrong (#1487860)
- Fixed bug in handling link with '!' character in it (#1488195)
- Fixed bug where session ID's length was limited to 40 characters (#1488196)
- TinyMCE security issue: removed moxieplayer (embedding flv and mp4 is not supported anymore)
RELEASE 0.7-beta
----------------
- Fix handling of HTML form elements in messages (#1485137)
- Fix regression in setting recipient to self when replying to a Sent message (#1487074)
- Fix listing of folders in hidden namespaces (#1486796)
- Don't consider \Noselect flag when building folders tree (#1488004)
- Fix sorting autocomplete results (#1488084)
- Add option to set session name (#1486433)
- Add option to skip alternative email addresses in autocompletion
- Fix inconsistent behaviour of Compose button in Drafts folder, add Edit button for drafts
- Fix problem with parsing HTML message body with non-unicode characters (#1487813)
- Add option to define matching method for addressbook search (#1486564, #1487907)
- Make email recipients separator configurable
- Fix so folders with \Noinferiors attribute aren't listed in parent selector
- Fix handling of curly brackets in URLs (#1488168)
- Fix handling of dates (birthday/anniversary) in contact data (#1488147)
- Fix error on opening searched LDAP contact (#1488144)
- Fix redundant line break in flowed format (#1488146)
- Fix IDN address validation issue (#1488137)
- Fix JS error when dst_active checkbox doesn't exist (#1488133)
- Autocomplete LDAP records when adding contacts from mail (#1488073)
- Plugin API: added 'ready' hook (#1488063)
- Ignore DSN request when it isn't supported by SMTP server (#1487800)
- Make sure LDAP name fields aren't arrays (#1488108)
- Fixed imap test to non-default port when using ssl (#1488118)
- Force all files to be overwritten when updating (#1488117)
- Fix issue where it wasn't possible to change list view mode in folder manager for INBOX (#1488107)
- Fix namespace handling in special folders settings (#1488112)
- Disable time limit for CLI scripts (#1488109)
- Fix misleading display when chaning editor type (#1488104)
- Add loading indicator on contact delete
- Fix bug where after delete message rows can be added to the list of another folder (#1487752)
- Add notice on autocompletion that not all records were displayed
- Add option 'searchonly' for LDAP address books
- Add Priority filter to the messages list
- Cache synchronization using QRESYNC/CONDSTORE
- Trigger 'new_messages' hook for all checked folders (#1488083)
- Make date/time format user configurable; drop 'date_today' config option
- Fix setting title for truncated subject in IE (#1487128)
- Fix displaying multipart/alternative messages with only one part (#1487938)
- Rewritten messages caching:
Indexes are stored in a separate table, so there's no need to store all messages in a folder
Added threads data caching
Flags are stored separately, so flag change doesn't cause DELETE+INSERT, just UPDATE
- Improved FETCH response handling
- Improvements in response tokenization method
- Use 'From' and 'To' labels instead of 'Sender' and 'Recipient'
- Fix username case-insensitivity issue in MySQL (#1488021)
- Addressbook Saved Searches
- Added spellchecker exceptions dictionary (shared or per-user)
- Added possibility to ignore words containing caps, numbers, symbols (spellcheck_ignore_* options)
- Added 'priority' column on messages list (#1486782)
- Localize forwarded message header (#1488058)
RELEASE 0.6
-----------
- Fix bug where the last identity is used on reply (#1488101)
- Fix locked folder rename option on servers supporting RFC2086 only (#1488089)
- Fix session race conditions when composing new messages
- Fix encoding of LDAP contacts identifiers (#1488079)
- jQuery 1.6.4
- Fix handling of binary attachments encoded with quoted-printable (#1488065)
- Fix text-overflow:ellipsis issues on messages list in FF7 and Webkit (#1488061)
- Fix handling of links with IP address
- Fix compacting folder resets message list filter (#1488076)
RELEASE 0.6-rc
----------------
- Send X-Frame-Options headers to protect from clickjacking (#1487037)
- Fallback to mail_domain in LDAP variable replacements; added 'host' to 'user_create' hook arguments (#1488024)
- Fixed wrong vCard type parameter mobile (#1488067)
- Fixed vCard WORKFAX issue (#1488046)
- Add vCard's Profile URL support (#1488062)
- jQuery 1.6.3
- Fix imap_cache setting to values other than 'db' (#1488060)
- Fix handling of attachments inside message/rfc822 parts (#1488026)
- Make list of mimetypes that open in preview window configurable (#1487625)
- Added plugin hook 'message_part_get' for attachment downloads
- Added unique connection identifier to IMAP debug messages
- Fix image type check for contact photo uploads
RELEASE 0.6-beta
----------------
- Fixed selecting identity on reply/forward (#1487981)
- Add option to hide selected LDAP addressbook on the list
- Add client-side checking of uploaded files size
- Add newlines between organization, department, jobtitle (#1488028)
- Recalculate date when replying to a message and localize the cite header (#1487675)
- Fix handling of email addresses with quoted local part (#1487939)
- Fix EOL character in vCard exports (#1487873)
- Added optional "multithreading" autocomplete feature
- Plugin API: Added 'config_get' hook
- Fixed new_user_identity plugin to work with updated rcube_ldap class (#1487994)
- Plugin API: added folder_delete and folder_rename hooks
- Added possibility to undo last contact delete operation
- Fix sorting of contact groups after group create (#1487747)
- Add optional textual upload progress indicator (#1486039)
- Fix parsing URLs containing commas (#1487970)
- Added vertical splitter for books/groups list in addressbook (#1487923)
- Improved namespace roots handling in folder manager
- Added searching in all addressbook sources
- Added addressbook source selection in contacts import
- Implement LDAPv3 Virtual List View (VLV) for paged results listing
- Use 'address_template' config option when adding a new address block (#1487944)
- Added addressbook advanced search
- Add popup with basic fields selection for addressbook search
- Case-insensitive matching in autocompletion (#1487933)
- Added option to force spellchecking before sending a message (#1485458)
- Fix handling of "<" character in contact data, search fields and folder names (#1487864)
- Fix saving "<" character in identity name and organization fields (#1487864)
- Added option to specify to which address book add new contacts
- Added plugin hook for keep-alive requests
- Store user preferences in session when write-master is not available and session is stored in memcache, write them later
- Improve performence of folder manager operations
- Fix default_port option handling in Installer when config.inc.php file exists (#1487925)
- Removed option focus_on_new_message, added newmail_notifier plugin
- Added general rcube_cache class with Memcache and APC support
- Improved caching performance by skipping writes of unchanged data
- Option enable_caching replaced by imap_cache and messages_cache options
- Fix WORKFAX saving in address book (#1487910)
- Add forward-as-attachment feature
- jQuery-1.6.2 (#1487913, #1487144)
- Improve display name composition when saving contacts (#1487143)
- Fix problems with subfolders of INBOX folder on some IMAP servers (#1487725)
- Fix handling of folders that doesn't belong to any namespace (#1487637)
- Enable multiselection for attachments uploading in capable browsers (#1485969)
- Add possibility to change HTML editor configuration by skin
- Fix a bug where selecting too many contacts would produce too large URI request (#1487892)
- Improve performance by including files with absolute path (#1487849)
- Move folder name truncation to client/skin (#1485412)
- Added plugin hook for request token creation
- Replace LDAP vars in group queries (#1487837)
- Fix vcard folding with uncode characters (#1487868)
- Keep all submitted data if contact form validation fails (#1487865)
- Handle uncode strings in rcube_addressbook::normalize_string() (#1487866)
- Fix handling of debug_level=4 in ajax requests (#1487831)
- Enable TinyMCE's contextmenu (#1487014)
- Allow multiple concurrent compose sessions
- New config option for custom logo
- Allow skins to define/override texts with <roundcube:label />
- Add simple ACL rights/namespace handling in folder manager
- Force IE to send referers (#1487806)
- Better display of vcard import results (#1485457)
- Improved vcard import
- Interactive update script with improved DB schema check
- Fix problem with contactgroupmembers table creation on MySQL 4.x, add index on contact_id column
- Add LDAP SASL bind and proxy authentication (#1486692)
- Replying to a sent message puts the old recipient as the new recipient (#1487074)
- Fulltext search over (almost) all data for contacts
- Extend address book with rich contact information
RELEASE 0.5.4
-------------
- Fix XSS vulnerability in UI messages [CVE-2011-2937] (#1488030)
RELEASE 0.5.3
-------------
- Fix identities "reply-to" and "bcc" fields have a bogus value when left empty (#1487943)
- Fix issue which cases IMAP disconnection when encrypt() method was used (#1487900)
- Fix some CSS issues in Settings for Internet Explorer
- Fixed handling of folder with name "0" in folder selector
- Fix bug where messages were deleted instead moved to trash folder after Shift key was used (#1487902)
- Fix relative URLs handling according to a <base> in HTML (#1487889)
- Fix handling of top-level domains with more than 5 chars or unicode chars (#1487883)
- Fix usage of non-standard HTTP error codes (#1487797)
- Fix PHP warning on mistaken in_array() usage (#1487901)
RELEASE 0.5.2
-------------
- TinyMCE 3.4.2 now compatible with IE9
- PEAR::Net_SMTP 1.5.2, fixed timeout issue (#1487843)
- Fix bug where template name without plugin prefix was used in render_page hook
- Support 'abort' and 'result' response in 'preferences_save' hook, add error handling
- Fix bug where some content would cause hang on html2text conversion (#1487863)
- Improve space-stuffing handling in format=flowed messages (#1487861)
- Fix bug where some dates would produce SQL error in MySQL (#1487856)
- Added workaround for some IMAP server with broken STATUS response (#1487859)
- Fix bug where default_charset was not used for text messages (#1487836)
- Stateless request tokens. No keep-alive necessary on login page (#1487829)
- Force names of unique constraints in PostgreSQL DDL
- Add code for prevention from IMAP connection hangs when server closes socket unexpectedly
- Remove redundant DELETE query (for old session deletion) on login
- Get around unreliable rand() and mt_rand() in session ID generation (#1486281)
- Fix some emails are not shown using Cyrus IMAP (#1487820)
- Fix handling of mime-encoded words with non-integral number of octets in a word (#1487801)
- Fix parsing links with non-printable characters inside (#1487805)
- Fixed de_CH Localization bugs (#1487773)
- Add variable for 'Today' label in date_today option (#1486120)
- Fix dont_override setting does not override existing user preferences (#1487664)
- Use only one from IMAP authentication methods to prevent login delays (1487784)
- Support strftime format in date_today option
- Fix SQL query in rcube_user::query() so it uses index on MySQL again
- Removed redundant </form> tags from contact add/edit pages
- Fix CSS error in contact details screen on IE7 (#1487775)
RELEASE 0.5.1
-------------
- Fix handling of attachments with invalid content type (#1487767)
- Add workaround for DBMail's bug http://www.dbmail.org/mantis/view.php?id=881 (#1487766)
- Use IMAP's ID extension (RFC2971) to print more info into debug log
- Security: add optional referer check to prevent CSRF in GET requests
- Fix email_dns_check setting not used for identities/contacts (#1487740)
- Fix ICANN example addresses doesn't validate (#1487742)
- Security: protect login form submission from CSRF [CVE-2011-1491]
- Security: prevent from relaying malicious requests through modcss.inc [CVE-2011-1492]
- Fix handling of non-image attachments in multipart/related messages (#1487750)
- Fix IDNA support when IDN/INTL modules are in use (#1487742)
- Fix handling of invalid HTML comments in messages (#1487759)
- Fix parsing FETCH response for very long headers (#1487753)
- Fix add/remove columns in message list when message_sort_order isn't set (#1487751)
- Check mime headers before attempt to parse them (#1487745)
- Quote header values in show_additional_headers plugin (#1487744)
- Fix settings UI on IE 6 (#1487724)
- Remove double borders in folder listing (#1487713)
- Separate full message headers UI element from headers table (#1487715)
- Add part MIME ID to message_part_* hooks (#1487718)
- Improve parsing of MS Outlook vCards (#1487716)
- Updated PEAR::Net_Socket to 1.0.10
- Updated PEAR::Net_IDNA2 to 0.1.1
- Fix handling of comments inside an email address spec. (#1487673)
- Show full mail subject as title when hovering a cut subject link (#1487128)
- Fix randomly disappearing folders list in IE (#1487704)
- Fix list column add/removal in IE (#1487703)
- Fix login redirect issues (#1487686)
- Require PHP 5.2.1 or greater
- Fix %h/%z variables in username_domain option (#1487701)
- Workaround for setting charset in case of malformed bodystructure response (#1487700)
- Fix impossible to subscribe to protected folders (#1487656)
- Fix setting timezone in Preferences (#1487705)
RELEASE 0.5
-----------
- Fix double-login/session issue (#1487104)
- Wrap HTML parts with <html><body> and add Doctype declaration (#1487098)
- Make rcube_autoload silently skip unknown classes (#1487109)
- Fix charset detection in vcards with encoded values (#1485542)
- Better CSS cursors for splitters (#1486874)
- Show the same message only once (#1487641)
- Fix namespaces handling (#1487649)
- Add handling of multifolder METADATA/ANNOTATION responses
- Fix handling of INBOX when personal namespace prefix is non-empty (#1487657)
- Fix handling square brackets in links (#1487672)
- Add description of 'use_https' option in main.inc.php.dist file
RELEASE 0.5-RC
--------------
- Plugin API: Add 'pass' argument in 'authenticate' hook (#1487134)
- Fix attachments of type message/rfc822 are not listed on attachments list
- Add 'login_lc' config option for case-insensitive authentication (#1487113)
- Fix window is blur'ed in IE when selecting a message (#1487316)
- Fix cursor position on compose form in Webkit browsers (#1486674)
- Fix setting charset of attachment filenames (#1487122)
- Allow setting autocomplete attribute for all inputs separately (#1487313)
- New Folder Manager UI
- Fix invalid Request when creating a folder (#1487443)
- Add folder size and quota indicator in folder manager (#1485780)
- Add possibility to move a subfolder into root folder (#1486791)
- Fix copying all messages in a folder copies only messages from current page
- Improve performance of moving or copying of all messages in a folder
- Fix plaintext versions of HTML messages don't contain placeholders for emotions (#1485206)
- Improve performance of folder rename and delete actions
- Better support for READ-ONLY and NOPERM responses handling (#1487083)
- Add confirmation message on purge/expunge command response
- Fix handling of untagged responses for AUTHENTICATE command (#1487450)
- Add username and IP address to log message on unsuccessful login (#1487626)
- Improved Mail-Followup-To and Mail-Reply-To headers handling
- Fix charset conversion for text attachments without charset specification (#1487634)
RELEASE 0.5-BETA
----------------
- Make session data storage more robust against garbage session data (#1487136)
- Config option for autocomplete on login screen
- Allow plugin templates to include local files (#1487133)
- List groups in address detail view and allow to subscribe/unsubscribe from there (#1486753)
- Messages caching: performance improvements, fixed syncing, fixes related with #1486748
- Add link to identities in compose window (#1486729)
- Add Internationalized Domain Name (IDNA) support (#1483894)
- Add option to automatically send read notifications for known senders (#1485883)
- Add option to "Return receipt" will be always checked (#1486352)
- Fix HTML to plain text conversion doesn't handle citation blocks (#1486921)
- Use custom sorting when SORT is disabled by IMAP admin (#1486959)
- Allow setting some washtml options from plugin (#1486578)
- Add option do bind for an individual LDAP address book (#1486997)
- Change reply prefix to display email address only if sender name doesn't exist (#1486550)
- Plugin API: improved 'abort' flag handling, added 'result' item in some hooks (#1486914)
- Fix mailto optional params in plain text messages aren't handled (#1487026)
- Add Reply-to-List feature (#1484252)
- Add Mail-Followup-To/Mail-Reply-To support (#1485547)
- Fix confirmation message isn't displayed after sending mail on Chrome (#1486177)
- Fix keyboard doesn't work with autocomplete list with Chrome (#1487029)
- Improve tabs to fixed width and add tabs in identities info (#1486974)
- Add unique index on users.username+users.mail_host
- Make htmleditor option more consistent and add option to use HTML on reply to HTML message (#1485840)
- Use empty envelope sender address for message disposition notifications (RFC 2298.3)
- Support SMTP Delivery Status Notifications - RFC 3461 (#1486142)
- Use css sprite image for messages list
- Add (different) attachment icon for messages of type multipart/report (#1486165)
- Prevent from inserting empty link when composing HTML message (#1486944)
- Add caching support in id2uid and uid2id functions (#1487019)
- Add SASL proxy authentication for SMTP (#1486693)
- Improve displaying of UI messages (#1486977)
- Fix double e-mail filed in identity form (#1487054)
- Display IMAP errors for LIST/THREAD/SEARCH commands (#1486905)
- Add LITERAL+ (IMAP4 non-synchronizing literals) support (RFC 2088)
- Add separate column for message status icon (#1486665)
- Add ACL extension support into IMAP classes (RFC 4314)
- Add ANNOTATEMORE extension support into IMAP classes (draft-daboo-imap-annotatemore)
- Add METADATA extension support into IMAP classes (RFC 5464)
- Fix decoding of e-mail address strings in message headers (#1487068)
- Fix handling of attachments when Content-Disposition is not inline nor attachment (#1487051)
- Improve performance of unseen messages counting (#1487058)
- Improve performance of messages counting using ESEARCH extension (RFC4731)
- Add LIST-STATUS support in rcube_imap_generic class (RFC 5819)
- Add SASL-IR support in IMAP (RFC 4959)
- Add LOGINDISABLED support (RFC 2595)
- Add support for AUTH=PLAIN in IMAP authentication
- Re-implemented SMTP proxy authentication support
- Add support for IMAP proxy authentication (#1486690)
- Add support for AUTH=DIGEST-MD5 in IMAP (RFC 2831)
- Fix parent folder with unread subfolder not bold when message is open (#1487078)
- Add basic IMAP LIST's \Noselect option support
- Add support for selection options from LIST-EXTENDED extension (RFC 5258)
- Don't list subscribed but non-existent folders (#1486225)
- Fix handling of URLs with tilde (~) or semicolon (;) character (#1487087, #1487088)
- Plugin API: added 'contact_form' hook
- Add SORT=DISPLAY support (RFC 5957)
- Plugin API: add possibility to disable plugin in AJAX mode, 'noajax' property
- 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)
- Add option to place replies in the folder of the message being replied to (#1485945)
- Add missing confirmation/error messages on contact/group/message actions (#1486845)
- Add 'loading' message on message move/copy/delete/mark actions
- Improve responsiveness of messages displaying (#1486986)
- Add option for minimum length of autocomplete's string (#1486428)
- Fix operations on messages in unsubscribed folder (#1487107)
- Add support for shared folders (#1403507)
- Fix handling of folders with name "0" (#1487119)
- Fix handling of folders with "<>" characters in name
- jQuery 1.4.4
- Fix handling of HTML entity strings in plain text messages
- Fix focused elements aren't unfocused when clicking on the list (#1487123)
- Fix error in MSSQL DDL scripts (#1487112)
- Lock submit button in onsubmit event on login page (#1487036)
- Don't set attachment's charset in Content-type header (#1487122)
- Fix handling of message bodies (quoted-printable encoded) with NULL characters (#1486189)
- Add workaround for MSOE's multipart/related messages with non-related attachments
RELEASE 0.4.2
-------------
- Fix handling of backslash as IMAP delimiter
- Fix charset replacement in HTML message bodies (#1487021)
- Fix: contact group input is empty when using rename action more than once on the same group record
- Fix "Server Error! (Not Found)" when using utils/save-pref action (#1487023)
- Fix handling of Thunderbird's vCards (#1487024)
RELEASE 0.4.1
-------------
- Fix space-stuffing in format=flowed messages (#1487018)
- Fix msgexport.sh now using the new imap wrapper
- Avoid displaying password on shell (#1486947)
- Only lower-case user name if first login attempt failed (#1486393)
- Make alias setting in squirrelmail_usercopy plugin configurable (patch by pommi, #1487007)
- Prevent from saving a non-existing skin path in user prefs (#1486936)
- Improve handling of single-part messages with bogus BODYSTRUCTURE (#1486898)
- Fix path to SQL files when using pgsql/mysqli/sqlsrv drivers (#1486902)
- Fix upgrade script for SQLite (#1486903)
- Fixes in SQL init script + added update script for MSSQL database
- Remove redundant date in syslog messages (#1486945)
- Fix contacts list page controls when a group is selected (#1486946)
- Fix SMTP test in Installer (#1486952)
- Fix "Select all" causes message to be opened in folder with exactly one message (#1486913)
- Fix Tab key doesn't work in HTML editor in Google Chrome (#1486925)
- Fix TinyMCE uses zh_CN when zh_TW locale is set (#1486929)
- Fix TinyMCE buttons are hidden in Opera (#1486922)
- Fix JS error on IE when trying to send HTML message with enabled spellchecker (#1486940)
- Display inline images with known extensions and non-image content-type (#1486934)
- Fix "Threaded" checkbox after subfolder creation (#1486928)
- Fix timezone string in sent mail (#1486961)
- Show disabled checkboxes for protected folders instead of dots (#1485498)
- Added fieldsets in Identity form, added 'identity_form' hook
- Re-added 'Close' button in upload form (#1486930, #1486823)
- Fix handling of charsets with LATIN-* label
- Fix messages background image handling in some cases (#1486990)
- Fix format=flowed handling (#1486989)
- Fix when IMAP connection fails in 'get' action session shouldn't be destroyed (#1486995)
- Fix list_cols is not updated after column dragging (#1486999)
- Support %z variable in host configuration options (#1487003)
RELEASE 0.4
-----------
- Fix disapearing upload form disapears when user selects a file on Safari (#1486823)
- Don't replace error messages with loading info (#1486300)
- Fix JS errors on compose mode switch (#1486870)
- Fix message structure parsing when it lacks optional fields (#1486881)
- Include all recipients in sendmail log
- Support HTTP_X_FORWARDED_PROTO header for HTTPS detecting (#1486866)
- Fix default IMAP port configuration (#1486864)
- Create Sent folder when starting to compose a new message (#1486802)
- Fix handling of messages with Content-Type: application/* and no filename (#1484050)
- Improved compose screen: resizable body and attachments list, vertical splitter, options menu
- Fix RC forgets search results (#1483883)
- TinyMCE 3.3.7
- Improve parsing of styled empty tags in HTML messages (#1486812)
- Add %dc variable support in base_dn/bind_dn config (#1486779)
- Add button to hide/unhide the preview pane (#1484215)
- Fix no-cache headers on https to prevent content caching by proxies (#1486798)
- Fix attachment filenames broken with TNEF decoder using long filenames (#1486795)
- Use user's timezone in Date header, not server's timezone (#1486119)
- Add option to set separate footer for HTML messages (#1486660)
- Add real SMTP error description to displayed error messages (#1485927)
- Fix some IMAP errors handling when opening the message (#1485443)
- Fix related parts aren't displayed when got mimetype other than image/* (#1486432)
- Multiple identity and database support for squirrelmail_usercopy plugin (#1486517)
- Support dynamic hostname (%d/%n) variables in configuration options (#1485438)
- Add 'messages_list' hook (#1486266)
- Add request* event triggers in http_post/http_request (#1486054)
- Fix use RFC-compliant line-delimiter when saving messages on IMAP (#1486712)
- Add 'imap_timeout' option (#1486760)
- Fix forwarding of messages with winmail attachments
- Fix handling of uuencoded attachments in message body (#1485839)
- Added list_mailboxes hook in rcube_imap::list_unsubscribed() (#1486668)
- Fix wrong message on file upload error (#1486725)
- Add support for data URI scheme [RFC2397] (#1486740)
- Added 'actionbefore', 'actionafter', 'responsebefore', 'responseafter' events
- Fix double-addition of e-mail domain to content ID in HTML images
- Read and send messages with format=flowed (#1484370), fixes word wrapping issues (#1486543)
- Fix duplicated attachments when forwarding a message (#1486487)
- Fix message/rfc822 attachments containing only attachments are not parsed properly (#1486743)
- Fix %00 character in winmail.dat attachments names (#1486738)
- Fix handling errors of folder deletion (#1486705)
- Parse untagged CAPABILITY response for LOGIN command (#1486742)
- Renamed all php-cli scripts to use .sh extension
- Some files from /bin + spellchecking actions moved to the new 'utils' task
- Added thread tree icons
- Extend contact groups support (#1486682)
- Fix check-recent action issues and performance (#1486526)
- Fix messages order after checking for recent (#1484664)
- Fix autocomplete shows entries without email (#1486452)
- Fix listupdate event doesn't trigger on search response (#1486708)
- Fix select_all_mode value after selecting a message (#1486720)
- Set focus to editor on reply in HTML mode (#1486632)
- Fix composing in HTML jumps cursor to body instead of recipients (#1486674)
- Allow columns order change per user - drag&drop (#1485795)
- Add References header in read receipt (#1486681)
- Fix database constraint violation when opening a message (#1486696)
- Add 'loading' message while login is in progress (#1486667)
- Fix quota_zero_as_unlimited (#1486662)
- Fix folder subscription checking (#1486684)
- Fix INBOX appears (sometimes) twice in mailbox list (#1486672)
- Fix listing of attachments of some types e.g. "x-epoc/x-sisx-app" (#1486653)
- Fix DB Schema checking when some db_table_* options are not set (#1486654)
RELEASE 0.4-beta
----------------
- Add sizelimit and timelimit variables in LDAP config (#1486544)
- Hide IMAP host dropdown when single host is defined (#1486326)
- Add images pre-loading on login page (#1451160)
- Add HTTP_X_REAL_IP and HTTP_X_FORWARDED_FOR to successful logins log (#1486441)
- Fix setting spellcheck languages with extended codes (#1486605)
- Fix messages list scrolling in FF3.6 (#1486472)
- Fix quicksearch input focus (#1486637)
- Always set changed date when flagging a DB record as deleted + provide a cleanup script
- Fix address book/group selection (#1486619)
- Assign newly created contacts to the active group (#1486626)
- Added option not to mark messages as read when viewed in preview pane (#1485012)
- Allow plugins modify the Sent folder when composing (#1486548)
- Added optional (max_recipients) support to restrict total number of recipients per message (#1484542)
- Re-organize editor buttons, add blockquote and search buttons
- Make possible to write inside or after a quoted html message (#1485476)
- Fix bugs on unexpected IMAP connection close (#1486190, #1486270)
- Iloha's imap.inc rewritten into rcube_imap_generic class
- Added contact groups in address book (not finished yet)
- Added PageUp/PageDown/Home/End keys support on lists (#1486430)
- Added possibility to select all messages in a folder (#1484756)
- Added 'imap_force_caps' option for after-login CAPABILITY checking (#1485750)
- Password: Support dovecotpw encryption
- TinyMCE 3.3.1
- Implemented messages copying using drag&drop + SHIFT (#1484086)
- Improved performance of folders operations (#1486525)
- Fix blocked.gif attachment is not attached to the message (#1486516)
- Managesieve: import from Horde-INGO
- Managesieve: support for more than one match (#1486078)
- Managesieve: support for selectively disabling rules within a single sieve script (#1485882)
- Threaded message listing now available
- Added sorting by ARRIVAL and CC
- Message list columns configurable by the user
- Removed 'index_sort' option, now we're using empty 'message_sort_col' for this
- virtuser_query: support other identity data (#1486148)
- Options virtuser_* replaced with virtuser_* plugins
- Plugin API: Implemented 'email2user' and 'user2email' hooks
- Fix forwarding message omits CC header (#1486305)
- Add 'default_charset' option to user preferences (#1485451)
- Add 'delete_always' option to user preferences
- Support/Require tls:// prefix in 'smtp_server' option for TLS connections
- Fix inconsistent behaviour of 'delete_always' option (#1486299)
- Fix deleting all messages from last list page (#1486293)
- Flag original messages when sending a draft (#1486203)
- Changed signature separator when top-posting (#1486330)
- Let the admin define defaults for search modifiers (#1485897)
- Fix long e-mail addresses validation (#1486453)
- Remember search modifiers in user prefs (#1486146)
- Added force_7bit option to force MIME encoding of plain/text messages (#1486510)
- Use case sensitive check when checking for default folders (#1486346)
- Fix checking for new mail: now checks unseen count of inbox (#1485794)
- Improve performance by avoiding unnecessary updates to the session table (#1486325)
- Fix invalid <font> tags which cause HTML message rendering problems (#1486521)
- Fix CVE-2010-0464: Disable DNS prefetching (#1486449)
- Fix Received headers to behave better with SpamAssassin (#1486513)
- Password: Make passwords encoding consistent with core, add 'password_charset' global option (#1486473)
- Fix adding contacts SQL error on mysql (#1486459)
- Squirrelmail_usercopy: support reply-to field (#1486506)
- Fix IE spellcheck suggestion popup issue (#1486471)
- Fix email address auto-completion shows regexp pattern (#1486258)
- Fix merging of configuration parameters: user prefs always survive (#1486368)
- Fix quota indicator value after folder purge/expunge (#1486488)
- Fix external mailto links support for use as protocol handler (#1486037)
- Fix attachment excessive memory use, support messages of any size (#1484660)
- Fix setting task name according to auth state
- Password: fix vpopmaild driver (#1486478)
- Add workaround for MySQL bug [http://bugs.mysql.com/bug.php?id=46293] (#1486474)
- Fix quoted text wrapping when replying to an HTML email in plain text (#1484141)
- Fix handling of extended mailto links (with params) (#1486354)
- Fix sorting by date of messages without date header on servers without SORT (#1486286)
- Fix inconsistency when not using default table names (#1486467)
- Fix folder rename/delete buttons do not appear on creation of first folder (#1486468)
- Fix character set conversion fails on systems where iconv doesn't accept //IGNORE (#1486375)
- Log in performance: Create default folders on first login only
- Import contacts into the selected address book (by Phil Weir)
- Add support for MDB2's 'sqlsrv' driver (#1486395)
- Use jQuery-1.4
- Removed problematic browser-caching of messages
- Fix incompatybility with suhosin.executor.disable_emodifier (#1486321)
- Use PLAIN auth when CRAM fails and imap_auth_type='check' (#1486371)
- Fix removal of <title> tag from HTML messages (#1486432)
- Fix 'force_https' to specified port when URL contains a port number (#1486411)
- Fix to-text converting of HTML entities inside b/strong/th/hX tags (#1486422)
- Bug in spellchecker suggestions when server charset != UTF8 (#1486406)
- Managesieve: Fix requires generation for multiple actions (#1486397)
- Fix LDAP problem with special characters in RDN (#1486320)
- Improved handling of message parts of type message/rfc822
- Plugin API: added 'quota' hook
- Fix parsing conditional comments in HTML messages (#1486350)
- Use built-in json_encode() for proper JSON format in AJAX replies
- Allow setting only selected params in 'message_compose' hook (#1486312)
- Plugin API: added 'message_compose_body' hook (#1486285)
- Fix counters of all folders are checked in 'getunread' action with check_all_folders disabled (#1486128)
- Fix displaying alternative parts in messages of type message/rfc822 (#1486246)
- Fix possible messages exposure when using Roundcube behind a proxy (#1486281)
- Fix unicode para and line separators in javascript response (#1486310)
- Additional_message_headers: allow unsetting headers, support plugin's config file (#1486268)
- Fix displaying of hidden directories in skins list (#1486301)
- Fix open_basedir restriction error when reading skins list (#1486304)
- Fix pasting from Office apps into html editor (#1486271)
- Fix empty <a> tags parsing (#1486272)
- Don't cut off attachment names when using non-RFC2231 encoding (#1485515)
- Allow inserting signatures above replied message body (#1484272)
- Managesieve 2.0: multi-script support
- Fix imap_auth_type regression (#1486263)
RELEASE 0.3.1
------------------
- Specify toolbar container in compose template (#1486247)
- Fix $_SERVER['HTTPS'] check for SSL forcing on IIS (#1486243)
- Avoid unnecessary page loads for selected tab (#1486032)
- Fix quota indicator issues by content generation on client-size (#1486197, #1486220)
- Don't display disabled sections in Settings (#1486099)
- Added server-side e-mail address validation with 'email_dns_check' option (#1485857)
- Fix login page loading into an iframe when session expires (#1485952)
- Allow setting port number in 'force_https' option (#1486091)
- Option 'force_https' replaced by 'force_https' plugin
- Fix IE issue with non-UTF-8 characters in AJAX response (#1486159)
- Partially fixed "empty body" issue by showing raw body of malformed message (#1486166)
- Fix importing/sending to email address with whitespace (#1486214)
- Added XIMSS (CommuniGate) driver for Password plugin
- Fix newly attached files are not saved in drafts w/o editing any text (#1486202)
- Added attachment upload indicator with parallel upload (#1486058)
- Use default_charset for bodies of messages without charset definition (#1486187)
- Password: added cPanel driver
- Fix return to first page from e-mail screen (#1486105)
- Fix handling HTML comments in HTML messages (#1486189)
- Fix folder/messagelist controls alignment - icons used (#1486072)
- Fix LDAP addressbook shows 'Contact not found' error sometimes (#1486178)
- Fix cache status checking + improve cache operations performance (#1486104)
- Prevent from setting INBOX as any of special folders (#1486114)
- Fix regular expression for e-mail address (#1486152)
- Fix Received header format
- Implemented sorting by message index - added 'index_sort' option (#1485936)
- Fix dl() use in installer (#1486150)
- Added 'ldap_debug' option
- Fix "Empty startup greeting" bug (#1486085)
- Fix setting user name in 'new_user_identity' plugin (#1486137)
- Fix incorrect count of new messages in folder list when using multiple IMAP clients (#1485995)
- Fix all folders checking for new messages with disabled caching (#1486128)
- Support skins in 'archive' and 'markasjunk' plugins
- Added 'html_editor' hook (#1486068)
- Fix DB constraint violation when populating messages cache (#1486052)
- Password: added password strength options (#1486062)
- Fix LDAP partial result warning (#1485536)
- Fix delete in message view deletes permanently with flag_for_deletion=true (#1486101)
- Use faster/secure mt_rand() (#1486094)
- Fix roundcube hangs on empty inbox with bincimapd (#1486093)
- Fix wrong headers for IE on servers without $_SERVER['HTTPS'] (#1485926)
- Force IE style headers for attachments in non-HTTPS session, 'use_https' option (#1485655)
- Check 'post_max_size' for upload max filesize (#1486089)
- Password Plugin: Fix %d inserts username instead of domain (#1486088)
- Fix rcube_mdb2::affected_rows() (#1486082)
RELEASE 0.3-stable
------------------
- Fix gn and givenName should be synonymous in LDAP addressbook (#1485892)
- Add mail_domain to LDAP email entries without @ sign (#1485201)
- Fix saving empty values in LDAP contact data (#1485781)
- Fix LDAP contact update when RDN field is changed (#1485788)
- Fix LDAP attributes case senitivity problems (#1485830)
- Fix LDAP addressbook browsing when only one directory is used (#1486022)
- Fix endless loop on error response for APPEND command (#1486060)
- Don't require date.timezone setting in installer (#1485989)
- Fix date sorting problem with Courier IMAP server (#1486065)
- Unselect pressed buttons on mouse up (#1485987)
- Don't set php_value error_log in .htaccess but mention in INSTALL (#1485924)
- Fix too small status/flag/attachment columns in Safari 4 (#1486063)
- Fix selection disabling while dragging splitter in webkit browsers (#1486056)
- Added 'new_messages' plugin hook (#1486005)
- Added 'logout_after' plugin hook (#1486042)
- Added 'message_compose' hook
- Added 'imap_connect' hook (#1485956)
- Fix vcard_attachments plugin (#1486035)
- Updated PEAR::Auth_SASL to 1.0.3 version
- Use sequence names only with PostgreSQL (#1486018)
- Re-designed User Preferences interface
- Fix MS SQL DDL (#1486020)
- Fix rcube_mdb2.php: call to setCharset not implemented in mssql driver (#1486019)
- Added 'display_next' option
- Fix rcube_mdb2::unixtimestamp for MS SQL (#1486015)
- Fix HTML washing to respect character encoding
- Fix endless loop in iil_C_Login() with Courier IMAP (#1486010)
- Fix #messagemenu display on IE (#1486006)
- Speedup UI by using sprites for (toolbar) buttons
- Fix charset names with X- prefix handling
- Fix displaying of HTML messages with unknown/malformed tags (#1486003)
RELEASE 0.3-RC1
---------------
- Fix import of vCard entries with params (#1485453)
- Fix HTML messages output with empty block elements (#1485974)
- Use request tokens to protect POST requests from CSRF [CVE-2009-4076, CVE-2009-4077]
- Added hook when killing a session
- Added hook to write_log function (#1485971)
- Performance improvements by use UID commands (#1485690)
- Fix HTML editor tabIndex setting (#1485972)
- Added 'imap_debug' and 'smtp_debug' options
- Support strftime's format modifiers in date_* options (#1484806)
- Support %h variable in 'smtp_server' option (#1485766)
- Show SMTP errors in browser (#1485927)
- Allow WBR tag in HTML message (#1485960)
- Use spl_autoload_register() instead of __autoload (#1485947)
- Add hook for identities listing (#1485958)
- Trigger hook 'smtp_connect' when opening an SMTP connection (#1485954)
- Added config option to enforce HTTPS connections
- Fix non-unicode characters caching in unicode database (#1484608)
- Performance improvements of messages caching
- Fix empty Date header issue (#1485923)
- Open collapsed folders during drag & drop (#1485914)
- Fixed link text replacements (#1485789)
- Also trigger 'insertrow' events on page load (#1485826)
- No link on subject in IE browsers (#1484913)
- Fixed filename encoding according to RFC2231 (#1485875)
- Added message Edit feature (#1483891, #1484440)
- Fix message Etag generation for counter issues (#1485623)
- Fix messages searching on MailEnable IMAP (#1485762)
- Fixed many 'skip_deleted' issues (#1485634)
- Fixed messages list sorting on servers without SORT capability
- Colorized signatures in plain text messages
- Reviewed/fixed skip_deleted/read_when_deleted/flag_for_deletion options handling in UI
- Fix displaying of big maximum upload filesize (#1485889)
- Added possibility to invert messages selection
- After move/delete from 'show' action display next message instead of messages list (#1485887)
- Fixed problem with double quote at the end of folder name (#1485884)
- Speedup UI by using CSS sprites and etags/expires/deflate in Apache config (#1484858,#1485800)
- Support UID EXPUNGE: remove only moved/deleted messages
- Add drag cancelling with ESC key (#1484344)
- Support initial identity name from virtuser_query (#1484003)
- Added message menu, removed Print and Source buttons
- Added possibility to save message as .eml file (#1485861)
- Added 1 minute interval in autosave options (#1485854)
- Support UTF-7 encoding in messages (#1485832)
- Better support for malformed character names (#1485758)
RELEASE 0.3-BETA
----------------
- Plugin API + jQuery engine
- Added possibility to encrypt received header, option 'http_received_header_encrypt',
added some more logic in encrypt/decrypt functions for security
- Fix Answered/Forwarded flag setting for messages in subfolders
- Fix autocomplete problem with capital letters (#1485792)
- Support UUencode content encoding (#1485839)
- Minimize chance of race condition in session handling (#1485659, #1484678)
- Fix session handling on non-session SQL query error (#1485734)
- Fix html editor mode setting when reopening draft message (#1485834)
- Added quick search box menu (#1484304)
- Fix wrong column sort order icons (#1485823)
- Updated TinyMCE to 3.2.3 version
- Fix attachment names encoding when charset isn't specified in attachment part (#1484969)
- Fix message normal priority problem (#1485820)
- Fix autocomplete spinning wheel does not disappear (#1485804)
- Added log_date_format option (#1485709)
- Fix text wrapping in HTML editor after switching from plain text to HTML (#1485521)
- Fix auto-complete function hangs with plus sign (#1485815)
- Fix AJAX requests errors handler (#1485000)
- Speed up message list displaying on IE
- Fix read/write database recognition (#1485811)
RELEASE 0.2.2
-------------
- Fix quicksearchbox look in Chrome and Konqueror (#1484841)
- Fix UTF-8 byte-order mark removing (#1485514)
- Fix folders subscribtions on Konqueror (#1484841)
- Fix debug console on Konqueror and Safari
- Fix messagelist focus issue when modifying status of selected messages (#1485807)
- Support STARTTLS in IMAP connection (#1485284)
- Fix DEL key problem in search boxes (#1485528)
- Support several e-mail addresses per user from virtuser_file (#1485678)
- Fix drag&drop with scrolling on IE (#1485786)
- Fix adding signature separator in html mode (#1485350)
- Fix opening attachment marks message as read (#1485803)
- Fix 'temp_dir' does not support relative path under Windows (#1484529)
- Fix "Initialize Database" button missing from installer (#1485802)
- Fix compose window doesn't fit 1024x768 window (#1485396)
- Fix service not available error when pressing back from compose dialog (#1485552)
- Fix using mail() on Windows (#1485779)
- Fix word wrapping in message-part's <PRE>s for printing (#1485787)
- Fix incorrect word wrapping in outgoing plaintext multibyte messages (#1485714)
- Fix double footer in HTML message with embedded images
- Fix TNEF implementation bug (#1485773)
- Fix incorrect row id parsing for LDAP contacts list (#1485784)
- Fix 'mode' parameter in sqlite DSN (#1485772)
RELEASE 0.2.1
------------------
- Use US-ASCII as failover when Unicode searching fails (#1485762)
- Fix errors handling in IMAP command continuations (#1485762)
- Fix FETCH result parsing for servers returning flags at the end of result (#1485763)
- Fix datetime columns defaults in mysql's DDL (#1485641)
- Fix attaching more than nine inline images (#1485759)
- Support 'UNICODE-1-1-UTF-7' alias for UTF-7 encoding (#1485758)
- Fix mime-type detection using a hard-coded map (#1485311)
- Don't return empty string if charset conversion failed (#1485757)
- Disable concurrent autocomplete query results display (#1485743)
- Fix new lines stripped from message footer (#1485751)
- Fix IE problem with mouse click autocomplete (#1485739)
- Fix html body washing on reply/forward + fix attachments handling (#1485676)
- Fix multiple recipients input parsing (#1485733)
- Fix replying to message with html attachment (#1485676)
- Use default_charset for messages without specified charset (#1485661, #1484961)
- Support non-standard "GMT-XXXX" literal in date header (#1485729)
- Added TNEF support to decode MS Outlook attachments (winmail.dat)
- Fix "value continuation" MIME headers by adding required semicolon (#1485727)
- Fix pressing select all/unread multiple times (#1485723)
- Fix selecting all unread does not honor new messages (#1485724)
- Fix some base64 encoded attachments handling (#1485725)
- Support NGINX as IMAP backend: better BAD response handling (#1485720)
- Performance fix: don't fetch attachment parts headers twice to parse filename
- Fix checking for recent messages on various IMAP servers (#1485702)
- Performance fix: Don't fetch quota and recent messages in "message view" mode
- Fix displaying of alternative-inside-alternative messages (#1485713)
- Fix MDNSent flag checking, use arbitrary keywords (asterisk) flag (#1485706)
- Fix creation of folders with '&' sign in name
- Fix parsing of email addresses without angle brackets (#1485693)
- Save spellcheck corrections when switching from plain to html editor (and spellchecking is on)
- Fix large search results on server without SORT capability (#1485668)
- Get rid of preg_replace() with eval modifier and create_function usage (#1485686)
- Bring back <base> and <link> tags in HTML messages
- Fix XSS vulnerability through background attributes [CVE-2009-0413]
- Fix problems with backslash as IMAP hierarchy delimiter (#1484467)
- Secure vcard export by getting rid of preg's 'e' modifier use (#1485689)
- Fix authentication when submitting form with existing session (#1485679)
- Allow absolute URLs to images in HTML messages/sigs (#1485666)
- Fix message body which contains both inline attachments and emotions
- Fix SQL query execution errors handling in rcube_mdb2 class (#1485509)
- Fix address names with '@' sign handling (#1485654)
- Improve messages display performance
- Fix messages searching with 'to:' modifier
RELEASE 0.2-STABLE
------------------
- Fix mark popup in IE 7 (#1485369)
- Fix line-break issue when copy & paste in Firefox (#1485425)
- Fix autocomplete "unknown server error" (#1485637)
- Fix STARTTLS before AUTH in SMTP connection (#1484883)
- Support multiple quota values in QUOTAROOT resonse (#1485626)
- Only abbreviate file name for IE < 7 browsers (#1485063)
- Performance: allow setting imap rootdir and delimiter before connect (#1485172)
- Fix sorting of folders with more than 2 levels (#1485569)
- Fix search results page jumps in LDAP addressbook (#1485253)
- Fix empty line before the signature in IE (#1485351)
- Fix horizontal scrollbar in preview pane on IE (#1484633)
- Add Robots meta tag in login page and installer (#1484846)
- Added 'show_images' option, removed 'addrbook_show_images' (#1485597)
- Option to check for new mails in all folders (#1484374)
- Don't set client busy when checking for new messages (#1485276)
- Allow UTF-8 folder names in config (#1485579)
- Add junk_mbox option configuration in installer (#1485579)
- Do serverside addressbook queries for autocompletion (#1485531)
- Allow setting attachment col position in 'list_cols' option
- Allow override 'list_cols' via skin (#1485577)
- Fix 'cache' table cleanup on session destroy (#1485516)
- Increase speed of session destroy and garbage clean up
- Fix session timeout when DB server got clock skew (#1485490)
- Fix handling of some malformed messages (#1484438)
- Speed up raw message body handling
- Better HTML entities conversion in html2text (#1485519)
- Fix big memory consumption and speed up searching on servers without SORT capability
- Fix setting locale to tr_TR, ku and az_AZ (#1485470)
- Use SORT for searching on servers with SORT capability
- Added message status filter
- Fix empty file sending (#1485389)
- Improved searching with many criterias (calling one SEARCH command)
- Fix HTML editor initialization on IE (#1485304)
- Add warning when switching editor mode from html to plain (#1485488)
- Make identities list scrollable (#1485538)
- Fix problem with numeric folder names (#1485527)
- Added BYE response simple support to prevent from endless loops in imap.inc (#1483956)
- Fix unread message unintentionally marked as read if read_when_deleted=true (#1485409)
- Remove port number from SERVER_NAME in smtp_helo_host (#1485518)
- Don't send disposition notification receipts for messages marked as 'read' (#1485523)
- Added 'keep_alive' and 'min_keep_alive' options (#1485360)
- Added option 'identities_level', removed 'multiple_identities'
- Allow deleting identities when multiple_identities=false (#1485435)
- Added option focus_on_new_message (#1485374)
- Fix html2text class autoloading on Windows (#1485505)
- Fix html signature formatting when identity save error occurred (#1485426)
- Add feedback and set busy when moving folder (#1485497)
- Fix 'Empty' link visibility for some languages e.g. Slovak (#1485489)
- Fix messages count bar overlapping (#1485270)
- Fix adding signature in drafts compose mode (#1485484)
- Fix iil_C_Sort() to support very long and/or divided responses (#1485283)
- Fix matching case sensitivity when setting identity on reply (#1485480)
- Prefer default identity on reply
- Fix imap searching on ISMail server (#1485466)
- Add css class for flagged messages (#1485464)
- Write username instead of id in sendmail log (#1485477)
- Fix htmlspecialchars() use for PHP version < 5.2.3 (#1485475)
- Fix js keywords escaping in json_serialize() for IE/Opera (#1485472)
- Added bin/killcache.php script (#1485434)
- Add support for SJIS, GB2312, BIG5 in rc_detect_encoding()
- Fix vCard file encoding detection for non-UTF-8 strings (#1485410)
- Add 'skip_deleted' option in User Preferences (#1485445)
- Minimize "inline" javascript scripts use (#1485433)
- Fix css class setting for folders with names matching defined classes names (#1485355)
- Fix race conditions when changing mailbox
- Fix spellchecking when switching to html editor (#1485362)
- Fix compose window width/height (#1485396)
- Allow calling msgimport.sh/msgexport.sh from any directory (#1485431)
- Localized filesize units (#1485340)
- Better handling of "no identity" and "no email in identity" situations (#1485117)
- Added 'mime_param_folding' option with possibility to choose long/non-ascii attachment names encoding eg. to be readable in MS Outlook/OE (#1485320)
- Added "advanced options" feature in User Preferences
- Fix unread counter when displaying cached massage in preview panel (#1485290)
- Fix htmleditor spellchecking on MS Windows (#1485397)
- Fix problem with non-ascii attachment names in Mail_mime (#1485267, #1485096)
- Fix language autodetection (#1485401)
- Fix button label in folders management (#1485405)
- Fix collapsed folder not indicating unread msgs count of all subfolders (#1485403)
- Fix handling of apostrophes in filenames decoded according to rfc2231
RELEASE 0.2-BETA
----------------
- Made config files location configurable (#1485215)
- Reduced memory footprint when forwarding attachments (#1485345)
- Allow and use spellcheck attribute for input/textarea fields (#1485060)
- Added icons for forwarded/forwarded+replied messages (#1485257)
- Added Reply-To to forwarded emails (#1485315)
- Display progress message for folders create/delete/rename (#1485357)
- Smart Tags and NOBR tag support in html messages (#1485363, #1485327)
- Redesign of the identities settings (#1484042)
- Add config option to disable creation/deletion of identities (#1484498)
- Added 'sendmail_delay' option to restrict messages sending interval (#1484491)
- Added vertical splitter for folders list resizing
- Added possibility to view all headers in message view
- Fixed splitter drag/resize on Opera (#1485170)
- Fixed quota img height/width setting from template (#1484857)
- Refactor drag & drop functionality. Don't rely on browser events anymore (#1484453)
- Insert "virtual" folders in subscription list (#1484779)
- Added link to open message in new window
- Enable export of address book contacts as vCard
- Add feature to import contacts from vcard files (#1326103)
- Respect Content-Location headers in multipart/related messages according to RFC2110 (#1484946)
- Allowed max. attachment size now indicated in compose screen (#1485030)
- Also capture backspace key in list mode (#1484566)
- Allow application/pgp parts to be displayed (#1484753)
- Correctly handle options in mailto-links (#1485228)
- Immediately save sort_col/sort_order in user prefs (#1485265)
- Truncate very long (above 50 characters) attachment filenames when displaying
- Allow to auto-detect client language if none set (#1484434)
- Auto-detect the client timezone (user configurable)
- Add RFC2231 header value continuations support for attachment filenames + hack for servers that not support that feature
- Fix Reply-To header displaying (#1485314)
- Mark form buttons that provide the most obvious operation (mainaction)
- Added option 'quota_zero_as_unlimited' (#1484604)
- Added PRE handling in html2text class (#1484740)
- Added folder hierarchy collapsing
- Added options to use syslog instead of log file (#1484850)
- Added Logging & Debugging section in Installer
- Fix In-Reply-To and References headers when composing saved draft message (#1485288)
- Fix html message charset conversion for charsets with underline (#1485287)
- Fix buttons status after contacts deletion (#1485233)
- Fix escaping of To: and From: fields when building message body for reply or forward in the HTML editor (#1484904)
- Use current mailbox name in template (#1485256)
- Better fix for skipping untagged responses (#1485261)
- Added pspell support patch by Kris Steinhoff (#1483960)
- Enable spellchecker for HTML editor (#1485114)
- Respect spellcheck_uri in tinyMCE spellchecker (#1484196)
- Case insensitive contacts searching using PostgreSQL (#1485259)
- Make default imap folders configurable for each user (#1485075)
- Save outgoing mail to selectable folder (#1324581)
- Fix hiding of mark menu when clicking th button again (#1484944)
- Use long date format in print mode (#1485191)
- Updated TinyMCE to version 3.1.0.1
- Re-enable autocomplete attribute for login form (#1485211)
- Check PERMANENTFLAGS before saving $MDNSent flag (#1484963, #1485163)
- Added flag column on messages list (#1484623)
- Patched Mail/MimePart.php (http://pear.php.net/bugs/bug.php?id=14232)
- Allow trash/junk subfolders to be purged (#1485085)
- Store compose parameters in session and redirect to a unique URL
- Fixed CRAM-MD5 authentication (#1484819)
- Fixed forwarding messages with one HTML attachment (#1484442)
- Fixed encoding of message/rfc822 attachments and image/pjpeg handling (#1484914)
- Added option to select skin in user preferences
- Added option to configure displaying of attached images below the message body
- Added option to display images in messages from known senders (#1484601)
- User preferences grouped in more fieldsets
- Fix corrupted MIME headers of messages in Sent folder (#1485111)
- Fixed bug in MDB2 package: http://pear.php.net/bugs/bug.php?id=14124
- Use keypress instead of keydown to select list's row (#1484816)
- Don't call expunge and don't remove message row after message move if flag_for_deletion is set to true (#1485002)
RELEASE 0.2-ALPHA
-----------------
- Added option to disable autocompletion from selected LDAP address books (#1484922)
- TLS support in LDAP connections: 'use_tls' property (#1485104)
- Fixed removing messages from search set after deleting them (#1485106)
- imap.inc: Fixed iil_C_FetchStructureString() to handle many
literal strings in response (#1484969)
- Support for subfolders in default/protected folders (#1484665)
- Disallowed delimiter in folder name (#1484803)
- Support " and \ in folder names
- Escape \ in login (#1484614)
- Better HTML sanitization with the DOM-based washtml script (#1484701)
- Fixed sorting of folders with non-ascii characters
- Fixed Mysql DDL for default identities creation (#1485070)
- In Preferences added possibility to configure 'read_when_deleted',
'mdn_requests', 'flag_for_deletion' options
- Made IMAP auth type configurable (#1483825)
- Fixed empty values with FROM_UNIXTIME() in rcube_mdb2 (#1485055)
- Fixed attachment list on IE 6/7 (#1484807)
- Fixed JavaScript in compose.html that shows cc/bcc fields if populated
- Make password input fields of type password in installer (#1484886)
- Don't attempt to delete cache entries if enable_caching is FALSE (#1485051)
- Optimized messages sorting on servers without sort capability (#1485049)
- Corrected message headers decoding when charset isn't specified and improved
support for native languages (#1485050, #1485048)
- Expanded LDAP configuration options to support LDAP server writes.
- Installer: encode special characters in DB username/password (#1485042)
- Fixed management of folders with national characters in names (#1485036, #1485001)
- Fixed identities saving when using MDB2 pgsql driver (#1485032)
- Fixed BCC header reset (#1484997)
- Improved messages list performance - patch from Justin Heesemann
- Append skin_path to images location only when it starts with '/' sign (#1484859)
- Fix IMAP response in message body when message has no body (#1484964)
- Fixed non-RFC dates formatting (#1484901)
- Fixed typo in set_charset() (#1484991)
- Decode entities when inserting HTML signature to plain text message (#1484990)
- HTML editing is now working with PHP5 updates and TinyMCE v3.0.6
- Fixed signature loading on Windows (#1484545)
- Added language support to HTML editing (#1484862)
- Fixed remove signature when replying (#1333167)
- Fixed problem with line with a space at the end (#1484916)
- Fixed <!DOCTYPE> tag filtering (#1484391)
- Fixed <?xml> tag filtering (#1484403)
- Added sections (fieldset+label) in Settings interface
- Mark as read in one action with message preview (#1484972)
- Deleted redundant quota reads (#1484972)
- Added options for empty trash and expunge inbox on logout (#1483863)
- Removed lines wrapping when displaying message
- Fixed month localization
- Changed codebase to PHP5 with autoloader
RELEASE 0.1.1
-------------
- Clear selection when selecting single item (#1484942)
- Remove hard-coded image size in skin templates (#1484893)
- Database schema improvements (dropped unnecessary indexes)
- Fixed creating a new folder with a comma in its name (#1484681)
- Fixed sorting of messages when default mailbox is empty (#1484317)
- Improve message previewpane - less loading (#1484316)
- Fixed login form autoompletion (#1484839)
- Fixed virtuser_query option for mdb2 backend (#1484874)
- Fixed attachment resoting from Drafts when message body was empty (#1484506)
- Fixed usage of ob_gzhandler (#1484851)
- Fixed message part window in IE6 (#1484610)
- Fixed decoding of mime-encoded strings (#1484191)
- Fixed some iconv/mb_string problems (#1484598)
- Correctly quote mailbox name when using in URL (#1484313)
- Fixed "headers already sent" errors (#1484860)
RELEASE 0.1-STABLE
------------------
- Added interactive installer script
- Fix folder adding/renaming inspired by #1484800
- Localize folder name in page title (#1484785)
- Fix code using wrong variable name (#1484018)
- Allow to send mail with BCC recipients only
- condense TinyMCE toolbar down to one line, removing table buttons (#1484747)
- Add function to mark the selected messages as read/unread (#1457360)
- Also do charset decoding as suggested in RFC 2231 (fix #1484321)
- Show message count in folder list and hint when creating a subfolder
- Distinguish ssl and tls for imap connections (#1484667)
- Added some charset aliases to fix typical mis-labelling (#1484565)
- Remember decision to display images for a certain message during session (#1484754)
- Truncate attachment filenames to 55 characters due to an IE bug (#1484757)
- Make sending of read receipts configurable
- Respect config when localize folder names (#1484707)
- Also respect receipt and priority settings when re-opening a draft message
- Remember search results (closes #1483883), patch by the_glu
- Add Received header on outgoing mail
- Upgrade to TinyMCE 2.1.3
- Allow inserting image attachments into HTML messages while composing (#1484557)
- Implement Message-Disposition-Notification (Receipts)
- Fix overriding of session vars when register_globals is on (#1484670)
- Fix bug with case-sensitive folder names (#1484245)
- Don't create default folders by default
- Fixed some potential security risks (audited by Andris)
- Only show new messages if they match the current search (#1484176)
- Switch to/from when searcing in Sent folder (#1484555)
- Correctly read the References header (#1484646)
- Unset old cookie before sending a new value (#1484639)
- Correctly decode attachments when downloading them (#1484645 and #1484642)
- Suppress IE errors when clearing attachments form (#1484356)
- Log error when login fails due to auto_create_user turned off
- Filter linked/imported CSS files (closes #1484056)
- Improve message compose screen (closes #1484383)
- Select next row after removing one from list (#1484387)
RELEASE 0.1-RC2
---------------
- Enable drag-&-dropping of folders to a new parent and allow to create subfolders (#1457344)
- Suppress IE errors when clearing attachments form (#1484356)
- Set preferences field in user table to NULL (#1484386)
- Log error when login fails due to auto_create_user turned off
- Filter linked/imported CSS files (closes #1484056)
- Improve message compose screen (closes #1484383)
- Select next row after removing one from list (#1484387)
- Make smtp HELO/EHLO hostname configurable (#1484067)
- IPv6 Compatability (#1484322), Patch #1484373
- Unlock interface when message sending fails (#1484570)
- Eval PHP code in template includes (if configured)
- Show message when folder is empty. Mo more static text in table (#1484395)
- Only display unread count in page title when new messages arrived
- Fixed wrong delete button tooltip (#1483965)
- Fixed charset encoding bug (#1484429)
- Applied patch for LDAP version (#1484552)
- Improved XHTML validation
- Fix message list selection (#1484550)
- Better fix lowercased usernames (#1484473)
- Update pngbehavior Script as suggested in #1484490
- Fixed moving/deleting messages when more than 1 is selected
- Applied patch for LDAP contacts listing by Glen Ogilvie
- Applied patch for more address fields in LDAP contacts (#1484402)
- Add alternative for getallheaders() (fix #1484508)
- Identify mailboxes case-sensitive
- Sort mailbox list case-insensitive (closes #1484338)
- Fix display of multipart messages from Apple Mail (closes #1484027)
- Protect AJAX request from being fetched by a foreign site (XSS)
- Make autocomplete for loginform configurable by the skin template
- Fix compose function from address book (closes #1484426)
- Added //IGNORE to iconv call (patch #1484420, closes #1484023)
- Check if mbstring supports charset (#1484290 and #1484292)
- Prefer iconv over mbstring (as suggested in #1484292)
- Check filesize of template includes (#1484409)
- Fixed bug with buttons not dimming/enabling properly after switching folders
- Fixed compose window becoming unresponsive after saving a draft (#1484487)
- Re-enabled "Back" button in compose window now that bug #1484487 is fixed
- Fixed unresponsive interface issue when downloading attachments (#1484496)
- Lowered status message time from 5 to 3 seconds to improve responsiveness
- Raised .htaccess upload_max_filesize from 2M to 5M to differ from default php.ini
- Increased "mailboxcontrols" mail.css width from 160 to 170px to fix non-english languages (#1484499)
- Fix status message bug #1484464 with regard to #1484353
- Fix address adding bug reported by David Koblas
- Applied socket error patch by Thomas Mangin
- Pass-by-reference workarround for PHP5 in sendmail.inc
- Fixed buggy imap_root settings (closes #1484379)
- Prevent default events on subject links (#1484399)
- Use HTTP-POST requests for actions that change state
RELEASE 0.1-RC1
---------------
- Use global filters and bind username/ for Ldap searches (#1484159)
- Hide quota display if imap server does not support it
- Hide address groups if no LDAP servers configured
- Add link to message subjects (closes #1484257)
- Better SQL query for contact listing/search (closes #1484369)
- Fixed marking as read in preview pane (closes #1484364)
- CSS hack to display attachments correctly in IE6
- Wrap message body text (closes #1484148)
- LDAP access is back in address book (closes #1484087)
- Added search function for contacts
- New Template parsing and output encoding
- Fixed bugs #1484119 and #1483978
- Fixed message moving procedure (closes #1484308)
- Fixed display of multiple attachments (closes #1466563)
- Fixed check for new messages (closes #1484310)
- List attachments without filename
- New session authentication: Change sessid cookie when login, authentication with sessauth cookie is now configurable.
Should close bugs #1483951 and #1484299
- Correctly translate mailbox names (closes #1484276)
- Quote e-mail address links (closes #1484300)
- Updated PEAR::Mail_mime package
- Accept single quotes for HTML attributes when modifying message body (thanks Jason)
- Sanitize input for new users/identities (thanks Colin Alston)
- Don't download HTML message parts
- Convert HTML parts to plaintext if 'prefer_html' is off
- Correctly parse message/rfc822 parts (closes #1484045)
- Also use user_id for unique key in messages table (closes #1484074)
- Hide contacts drop down on blur (closes #1484203)
- Make entries in contacts drop down clickable
- Turn off browser autocompletion on login page
- Quote <? in text/html message parts
- Hide border around radio buttons
- Applied patch for attachment download by crichardson (closes #1484198)
- Fixed bug in Postgres DB handling (closes #1484068)
- Fixed bug of invalid calls to fetchRow() in rcube_db.inc (closes #1484280)
- Fixed array_merge bug (closes #1484281)
- Fixed flag for deletion in list view (closes #1484264)
- Finally support semicolons as recipient separator (closes ##1484251)
- Fixed message headers (subject) encoding
- check if safe mode is on or not (closes #1484269)
- Show "no subject" in message list if subject is missing (closes #1484243)
- Solved page caching of message preview (closes #1484153)
- Only use gzip compression if configured (closes #1484236)
- Fixed priority selector issue (#1484150)
- Fixed some CSS issues in default skin (closes #1484210 and #1484161)
- Prevent from double quoting of numeric HTML character references (closes #1484253)
- Fixed display of HTML message attachments (closes #1484178)
- Applied patch for preview caching (closes #1484186)
- Added error handling for attachment uploads
- Use multibyte safe string functions where necessary (closes #1483988)
- Applied security patch to validate the submitted host value (by Kees Cook)
- Applied security patch to validate input values when deleting contacts (by Kees Cook)
- Applied security patch that sanitizes emoticon paths when attaching them (by Kees Cook)
- Applied a patch to more aggressively sanitize a HTML message
- Visualize blocked images in HTML messages
- Fixed wrong message listing when showing search results (closes #1484131)
- Show remote images when opening HTML message part as attachment
- Improve memory usage when sending mail (closes #1484098)
- Mark messages as read once the preview is loaded (closes #1484132)
- Include smtp final response in log (closes #1484081)
- Corrected date string in sent message header (closes #1484125)
- Correclty choose "To" column in sent and draft mailboxes (closes #1483943)
- Changed srong tooltips for message browse buttons (closes #1483930)
- Fixed signature delimeter character to be standard (Bug #1484035)
- Fixed XSS vulnerability (Bug #1484109)
- Remove newlines from mail headers (Bug #1484031)
- Selection issues when moving/deleting (Bug #1484044)
- Applied patch of Clement Moulin for imap host auto-selection
- ISO-encode IMAP password for plaintext login (Bugs #1483977 & #1483886)
- Fixed folder name encoding in subscription list (Bug #1484113)
- Fixed JS errors in identity list (Bug #1484120)
- Translate foldernames in folder form (closes #1484113)
- Added first and last buttons to message list, address book
and message detail
- Pressing Shift-Del bypasses Trash folder
- Enable purge command for Junk folder
- Fetch all aliases if virtuser_query is used instead
- Re-enabled multi select of contacts (Bug #1484017)
- Enable contact editing right after creation (Bug #1459641)
- Correct UTF-7 to UTF-8 conversion if mbstring is not available
- Fixed IMAP fetch of message body (Bug #1484019)
- Fixed safe_mode problems (Bug #1418381)
- Fixed wrong header encoding (Bug #1483976)
- Made automatic draft saving configurable
- Fixed JS bug when renaming folders (Bug #1483989)
- Added quota display as image (by Brett Patterson)
- Corrected creation of a message-id
- New indentation for quoted message text
- Improved HTML validity
- Fixed URL character set (Ticket #1445501)
- Fixed saving of contact into MySQL from LDAP query results (Ticket #1483820)
- Fixed folder renaming: unsubscribe before rename (Bug #1483920)
- Finalized new message parsing (+ chaching)
- Fixed wrong usage of mbstring (Bug #1462439)
- Set default spelling language (Ticket #1483938)
- Added support for Nox Spell Server
- Re-built message parsing (Bug #1327068)
Now based on the message structure delivered by the IMAP server.
- Fixed some XSS and SQL injection issues
- Fixed charset problems with folder renaming
diff --git a/plugins/password/composer.json b/plugins/password/composer.json
index 743d15e10..8c6848ca7 100644
--- a/plugins/password/composer.json
+++ b/plugins/password/composer.json
@@ -1,24 +1,24 @@
{
"name": "roundcube/password",
"type": "roundcube-plugin",
"description": "Password Change for Roundcube. Plugin adds a possibility to change user password using many methods (drivers) via Settings/Password tab.",
"license": "GPLv3+",
- "version": "4.0",
+ "version": "4.1",
"authors": [
{
"name": "Aleksander Machniak",
"email": "alec@alec.pl",
"role": "Lead"
}
],
"repositories": [
{
"type": "composer",
"url": "http://plugins.roundcube.net"
}
],
"require": {
"php": ">=5.3.0",
"roundcube/plugin-installer": ">=0.1.3"
}
}
diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist
index d1067e796..8624c5606 100644
--- a/plugins/password/config.inc.php.dist
+++ b/plugins/password/config.inc.php.dist
@@ -1,421 +1,426 @@
<?php
// Password Plugin options
// -----------------------
// A driver to use for password change. Default: "sql".
// See README file for list of supported driver names.
$config['password_driver'] = 'sql';
// Determine whether current password is required to change password.
// Default: false.
$config['password_confirm_current'] = true;
// Require the new password to be a certain length.
// set to blank to allow passwords of any length
$config['password_minimum_length'] = 0;
// Require the new password to contain a letter and punctuation character
// Change to false to remove this check.
$config['password_require_nonalpha'] = false;
// Enables logging of password changes into logs/password
$config['password_log'] = false;
// Comma-separated list of login exceptions for which password change
// will be not available (no Password tab in Settings)
$config['password_login_exceptions'] = null;
// Array of hosts that support password changing. Default is NULL.
// Listed hosts will feature a Password option in Settings; others will not.
// Example: array('mail.example.com', 'mail2.example.org');
$config['password_hosts'] = null;
// Enables saving the new password even if it matches the old password. Useful
// for upgrading the stored passwords after the encryption scheme has changed.
$config['password_force_save'] = false;
// Enables forcing new users to change their password at their first login.
$config['password_force_new_user'] = false;
// Default password hashing/crypting algorithm.
// Possible options: des-crypt, ext-des-crypt, md5-crypt, blowfish-crypt,
// sha256-crypt, sha512-crypt, md5, sha, smd5, ssha, samba, ad, dovecot, clear.
// For details see password::hash_password() method.
$config['password_algorithm'] = 'clear';
// Password prefix (e.g. {CRYPT}, {SHA}) for passwords generated
// using password_algorithm above. Default: empty.
$config['password_algorithm_prefix'] = '';
// Path for dovecotpw/doveadm-pw (if not in the $PATH).
// Used for password_algorithm = 'dovecot'.
// $config['password_dovecotpw'] = '/usr/local/sbin/doveadm pw'; // for dovecot-2.x
$config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw'; // for dovecot-1.x
// Dovecot password scheme.
// Used for password_algorithm = 'dovecot'.
$config['password_dovecotpw_method'] = 'CRAM-MD5';
// Iteration count parameter for Blowfish-based hashing algo.
// It must be between 4 and 31. Default: 12.
// Be aware, the higher the value, the longer it takes to generate the password hashes.
$config['password_blowfish_cost'] = 12;
+// This option temporarily disables the password change functionality.
+// Use it when the users database server is in maintenance mode or sth like that.
+// You can set it to TRUE/FALSE or a text describing the reason
+// which will replace the default.
+$config['password_disabled'] = false;
// SQL Driver options
// ------------------
// PEAR database DSN for performing the query. By default
// Roundcube DB settings are used.
$config['password_db_dsn'] = '';
// The SQL query used to change the password.
// The query can contain the following macros that will be expanded as follows:
// %p is replaced with the plaintext new password
// %P is replaced with the crypted/hashed new password
// according to configured password_method
// %o is replaced with the old (current) password
// %O is replaced with the crypted/hashed old (current) password
// according to configured password_method
// %h is replaced with the imap host (from the session info)
// %u is replaced with the username (from the session info)
// %l is replaced with the local part of the username
// (in case the username is an email address)
// %d is replaced with the domain part of the username
// (in case the username is an email address)
// Deprecated macros:
// %c is replaced with the crypt version of the new password, MD5 if available
// otherwise DES. More hash function can be enabled using the password_crypt_hash
// configuration parameter.
// %D is replaced with the dovecotpw-crypted version of the new password
// %n is replaced with the hashed version of the new password
// %q is replaced with the hashed password before the change
// Escaping of macros is handled by this module.
// Default: "SELECT update_passwd(%c, %u)"
$config['password_query'] = 'SELECT update_passwd(%c, %u)';
// By default the crypt() function which is used to create the %c
// parameter uses the md5 algorithm (deprecated, use %P).
// You can choose between: des, md5, blowfish, sha256, sha512.
$config['password_crypt_hash'] = 'md5';
// By default domains in variables are using unicode.
// Enable this option to use punycoded names
$config['password_idn_ascii'] = false;
// Enables use of password with crypt method prefix in %D, e.g. {MD5}$1$LUiMYWqx$fEkg/ggr/L6Mb2X7be4i1/
// when using the %D macro (deprecated, use %P)
$config['password_dovecotpw_with_method'] = false;
// Using a password hash for %n and %q variables (deprecated, use %P).
// Determine which hashing algorithm should be used to generate
// the hashed new and current password for using them within the
// SQL query. Requires PHP's 'hash' extension.
$config['password_hash_algorithm'] = 'sha1';
// You can also decide whether the hash should be provided
// as hex string or in base64 encoded format.
$config['password_hash_base64'] = false;
// Poppassd Driver options
// -----------------------
// The host which changes the password
$config['password_pop_host'] = 'localhost';
// TCP port used for poppassd connections
$config['password_pop_port'] = 106;
// SASL Driver options
// -------------------
// Additional arguments for the saslpasswd2 call
$config['password_saslpasswd_args'] = '';
// LDAP and LDAP_SIMPLE Driver options
// -----------------------------------
// LDAP server name to connect to.
// You can provide one or several hosts in an array in which case the hosts are tried from left to right.
// Exemple: array('ldap1.exemple.com', 'ldap2.exemple.com');
// Default: 'localhost'
$config['password_ldap_host'] = 'localhost';
// LDAP server port to connect to
// Default: '389'
$config['password_ldap_port'] = '389';
// TLS is started after connecting
// Using TLS for password modification is recommanded.
// Default: false
$config['password_ldap_starttls'] = false;
// LDAP version
// Default: '3'
$config['password_ldap_version'] = '3';
// LDAP base name (root directory)
// Exemple: 'dc=exemple,dc=com'
$config['password_ldap_basedn'] = 'dc=exemple,dc=com';
// LDAP connection method
// There is two connection method for changing a user's LDAP password.
// 'user': use user credential (recommanded, require password_confirm_current=true)
// 'admin': use admin credential (this mode require password_ldap_adminDN and password_ldap_adminPW)
// Default: 'user'
$config['password_ldap_method'] = 'user';
// LDAP Admin DN
// Used only in admin connection mode
// Default: null
$config['password_ldap_adminDN'] = null;
// LDAP Admin Password
// Used only in admin connection mode
// Default: null
$config['password_ldap_adminPW'] = null;
// LDAP user DN mask
// The user's DN is mandatory and as we only have his login,
// we need to re-create his DN using a mask
// '%login' will be replaced by the current roundcube user's login
// '%name' will be replaced by the current roundcube user's name part
// '%domain' will be replaced by the current roundcube user's domain part
// '%dc' will be replaced by domain name hierarchal string e.g. "dc=test,dc=domain,dc=com"
// Exemple: 'uid=%login,ou=people,dc=exemple,dc=com'
$config['password_ldap_userDN_mask'] = 'uid=%login,ou=people,dc=exemple,dc=com';
// LDAP search DN
// The DN roundcube should bind with to find out user's DN
// based on his login. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// Use this if you cannot specify a general template for user DN with
// password_ldap_userDN_mask. You need to perform a search based on
// users login to find his DN instead. A common reason might be that
// your users are placed under different ou's like engineering or
// sales which cannot be derived from their login only.
$config['password_ldap_searchDN'] = 'cn=roundcube,ou=services,dc=example,dc=com';
// LDAP search password
// If password_ldap_searchDN is set, the password to use for
// binding to search for user's DN. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// Warning: Be sure to set approperiate permissions on this file so this password
// is only accesible to roundcube and don't forget to restrict roundcube's access to
// your directory as much as possible using ACLs. Should this password be compromised
// you want to minimize the damage.
$config['password_ldap_searchPW'] = 'secret';
// LDAP search base
// If password_ldap_searchDN is set, the base to search in using the filter below.
// Note that you should comment out the default password_ldap_userDN_mask setting
// for this to take effect.
$config['password_ldap_search_base'] = 'ou=people,dc=example,dc=com';
// LDAP search filter
// If password_ldap_searchDN is set, the filter to use when
// searching for user's DN. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// '%login' will be replaced by the current roundcube user's login
// '%name' will be replaced by the current roundcube user's name part
// '%domain' will be replaced by the current roundcube user's domain part
// '%dc' will be replaced by domain name hierarchal string e.g. "dc=test,dc=domain,dc=com"
// Example: '(uid=%login)'
// Example: '(&(objectClass=posixAccount)(uid=%login))'
$config['password_ldap_search_filter'] = '(uid=%login)';
// LDAP password hash type
// Standard LDAP encryption type which must be one of: crypt,
// ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, ad, cram-md5 (dovecot style) or clear.
// Set to 'default' if you want to use method specified in password_algorithm option above.
// Multiple password Values can be generated by concatenating encodings with a +. E.g. 'cram-md5+crypt'
// Default: 'crypt'.
$config['password_ldap_encodage'] = 'crypt';
// LDAP password attribute
// Name of the ldap's attribute used for storing user password
// Default: 'userPassword'
$config['password_ldap_pwattr'] = 'userPassword';
// LDAP password force replace
// Force LDAP replace in cases where ACL allows only replace not read
// See http://pear.php.net/package/Net_LDAP2/docs/latest/Net_LDAP2/Net_LDAP2_Entry.html#methodreplace
// Default: true
$config['password_ldap_force_replace'] = true;
// LDAP Password Last Change Date
// Some places use an attribute to store the date of the last password change
// The date is meassured in "days since epoch" (an integer value)
// Whenever the password is changed, the attribute will be updated if set (e.g. shadowLastChange)
$config['password_ldap_lchattr'] = '';
// LDAP Samba password attribute, e.g. sambaNTPassword
// Name of the LDAP's Samba attribute used for storing user password
$config['password_ldap_samba_pwattr'] = '';
// LDAP Samba Password Last Change Date attribute, e.g. sambaPwdLastSet
// Some places use an attribute to store the date of the last password change
// The date is meassured in "seconds since epoch" (an integer value)
// Whenever the password is changed, the attribute will be updated if set
$config['password_ldap_samba_lchattr'] = '';
// DirectAdmin Driver options
// --------------------------
// The host which changes the password
// Use 'ssl://host' instead of 'tcp://host' when running DirectAdmin over SSL.
// The host can contain the following macros that will be expanded as follows:
// %h is replaced with the imap host (from the session info)
// %d is replaced with the domain part of the username (if the username is an email)
$config['password_directadmin_host'] = 'tcp://localhost';
// TCP port used for DirectAdmin connections
$config['password_directadmin_port'] = 2222;
// vpopmaild Driver options
// -----------------------
// The host which changes the password
$config['password_vpopmaild_host'] = 'localhost';
// TCP port used for vpopmaild connections
$config['password_vpopmaild_port'] = 89;
// Timout used for the connection to vpopmaild (in seconds)
$config['password_vpopmaild_timeout'] = 10;
// cPanel Driver options
// --------------------------
// The cPanel Host name
$config['password_cpanel_host'] = 'host.domain.com';
// The cPanel admin username
$config['password_cpanel_username'] = 'username';
// The cPanel admin password
$config['password_cpanel_password'] = 'password';
// The cPanel port to use
$config['password_cpanel_port'] = 2087;
// XIMSS (Communigate server) Driver options
// -----------------------------------------
// Host name of the Communigate server
$config['password_ximss_host'] = 'mail.example.com';
// XIMSS port on Communigate server
$config['password_ximss_port'] = 11024;
// chpasswd Driver options
// ---------------------
// Command to use (see "Sudo setup" in README)
$config['password_chpasswd_cmd'] = 'sudo /usr/sbin/chpasswd 2> /dev/null';
// XMail Driver options
// ---------------------
$config['xmail_host'] = 'localhost';
$config['xmail_user'] = 'YourXmailControlUser';
$config['xmail_pass'] = 'YourXmailControlPass';
$config['xmail_port'] = 6017;
// hMail Driver options
// -----------------------
// Remote hMailServer configuration
// true: HMailserver is on a remote box (php.ini: com.allow_dcom = true)
// false: Hmailserver is on same box as PHP
$config['hmailserver_remote_dcom'] = false;
// Windows credentials
$config['hmailserver_server'] = array(
'Server' => 'localhost', // hostname or ip address
'Username' => 'administrator', // windows username
'Password' => 'password' // windows user password
);
// Virtualmin Driver options
// -------------------------
// Username format:
// 0: username@domain
// 1: username%domain
// 2: username.domain
// 3: domain.username
// 4: username-domain
// 5: domain-username
// 6: username_domain
// 7: domain_username
$config['password_virtualmin_format'] = 0;
// pw_usermod Driver options
// --------------------------
// Use comma delimited exlist to disable password change for users.
// See "Sudo setup" in README file.
$config['password_pw_usermod_cmd'] = 'sudo /usr/sbin/pw usermod -h 0 -n';
// DBMail Driver options
// -------------------
// Additional arguments for the dbmail-users call
$config['password_dbmail_args'] = '-p sha512';
// Expect Driver options
// ---------------------
// Location of expect binary
$config['password_expect_bin'] = '/usr/bin/expect';
// Location of expect script (see helpers/passwd-expect)
$config['password_expect_script'] = '';
// Arguments for the expect script. See the helpers/passwd-expect file for details.
// This is probably a good starting default:
// -telent -host localhost -output /tmp/passwd.log -log /tmp/passwd.log
$config['password_expect_params'] = '';
// smb Driver options
// ---------------------
// Samba host (default: localhost)
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
$config['password_smb_host'] = 'localhost';
// Location of smbpasswd binary
$config['password_smb_cmd'] = '/usr/bin/smbpasswd';
// gearman driver options
// ---------------------
// Gearman host (default: localhost)
$config['password_gearman_host'] = 'localhost';
// Plesk/PPA Driver options
// --------------------
// You need to allow RCP for IP of roundcube-server in Plesk/PPA Panel
// Plesk RCP Host
$config['password_plesk_host'] = '10.0.0.5';
// Plesk RPC Username
$config['password_plesk_user'] = 'admin';
// Plesk RPC Password
$config['password_plesk_pass'] = 'password';
// Plesk RPC Port
$config['password_plesk_rpc_port'] = '8443';
// Plesk RPC Path
$config['password_plesk_rpc_path'] = 'enterprise/control/agent.php';
// kasswd Driver options
// ---------------------
// Command to use
$config['password_kpasswd_cmd'] = '/usr/bin/kpasswd';
diff --git a/plugins/password/localization/en_US.inc b/plugins/password/localization/en_US.inc
index 278a20374..d115b4d28 100644
--- a/plugins/password/localization/en_US.inc
+++ b/plugins/password/localization/en_US.inc
@@ -1,38 +1,37 @@
<?php
/*
+-----------------------------------------------------------------------+
| plugins/password/localization/<lang>.inc |
| |
| Localization file of the Roundcube Webmail Password plugin |
| Copyright (C) 2012-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
+-----------------------------------------------------------------------+
For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-password/
*/
$labels = array();
$labels['changepasswd'] = 'Change password';
$labels['curpasswd'] = 'Current Password:';
$labels['newpasswd'] = 'New Password:';
$labels['confpasswd'] = 'Confirm New Password:';
$messages = array();
$messages['nopassword'] = 'Please input new password.';
$messages['nocurpassword'] = 'Please input current password.';
$messages['passwordincorrect'] = 'Current password incorrect.';
$messages['passwordinconsistency'] = 'Passwords do not match, please try again.';
$messages['crypterror'] = 'Could not save new password. Encryption function missing.';
$messages['connecterror'] = 'Could not save new password. Connection error.';
$messages['internalerror'] = 'Could not save new password.';
$messages['passwordshort'] = 'Password must be at least $length characters long.';
$messages['passwordweak'] = 'Password must include at least one number and one punctuation character.';
$messages['passwordforbidden'] = 'Password contains forbidden characters.';
$messages['firstloginchange'] = 'This is your first login. Please change your password.';
-
-?>
+$messages['disablednotice'] = 'The system is currently under maintenance and password change is not possible at the moment. Everything should be back to normal soon. We apologize for any inconvenience.';
diff --git a/plugins/password/password.js b/plugins/password/password.js
index d0fd75a11..75448ec5d 100644
--- a/plugins/password/password.js
+++ b/plugins/password/password.js
@@ -1,47 +1,54 @@
/**
* Password plugin script
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (c) 2012-2014, The Roundcube Dev Team
*
* The JavaScript code in this page is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
window.rcmail && rcmail.addEventListener('init', function(evt) {
+ if (rcmail.env.password_disabled) {
+ $('#password-form input').prop('disabled', true);
+ // reload page after ca. 3 minutes
+ rcmail.reload(3 * 60 * 1000 - 2000);
+ return;
+ }
+
// register command handler
rcmail.register_command('plugin.password-save', function() {
var input_curpasswd = rcube_find_object('_curpasswd'),
input_newpasswd = rcube_find_object('_newpasswd'),
input_confpasswd = rcube_find_object('_confpasswd');
if (input_curpasswd && input_curpasswd.value == '') {
alert(rcmail.gettext('nocurpassword', 'password'));
input_curpasswd.focus();
}
else if (input_newpasswd && input_newpasswd.value == '') {
alert(rcmail.gettext('nopassword', 'password'));
input_newpasswd.focus();
}
else if (input_confpasswd && input_confpasswd.value == '') {
alert(rcmail.gettext('nopassword', 'password'));
input_confpasswd.focus();
}
else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) {
alert(rcmail.gettext('passwordinconsistency', 'password'));
input_newpasswd.focus();
}
else {
rcmail.gui_objects.passform.submit();
}
}, true);
$('input:not(:hidden):first').focus();
});
diff --git a/plugins/password/password.php b/plugins/password/password.php
index 476e9eac8..4dc5909d9 100644
--- a/plugins/password/password.php
+++ b/plugins/password/password.php
@@ -1,636 +1,655 @@
<?php
/**
* Password Plugin for Roundcube
*
* @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*
- * Copyright (C) 2005-2013, The Roundcube Dev Team
+ * Copyright (C) 2005-2015, The Roundcube Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
define('PASSWORD_CRYPT_ERROR', 1);
define('PASSWORD_ERROR', 2);
define('PASSWORD_CONNECT_ERROR', 3);
define('PASSWORD_SUCCESS', 0);
/**
* Change password plugin
*
* Plugin that adds functionality to change a users password.
* It provides common functionality and user interface and supports
* several backends to finally update the password.
*
* For installation and configuration instructions please read the README file.
*
* @author Aleksander Machniak
*/
class password extends rcube_plugin
{
public $task = 'settings|login';
public $noframe = true;
public $noajax = true;
private $newuser = false;
function init()
{
$rcmail = rcmail::get_instance();
$this->load_config();
if ($rcmail->task == 'settings') {
if (!$this->check_host_login_exceptions()) {
return;
}
$this->add_texts('localization/');
$this->add_hook('settings_actions', array($this, 'settings_actions'));
$this->register_action('plugin.password', array($this, 'password_init'));
$this->register_action('plugin.password-save', array($this, 'password_save'));
-
- if (strpos($rcmail->action, 'plugin.password') === 0) {
- $this->include_script('password.js');
- }
}
else if ($rcmail->config->get('password_force_new_user')) {
$this->add_hook('user_create', array($this, 'user_create'));
$this->add_hook('login_after', array($this, 'login_after'));
}
}
function settings_actions($args)
{
// register as settings action
$args['actions'][] = array(
'action' => 'plugin.password',
'class' => 'password',
'label' => 'password',
'title' => 'changepasswd',
'domain' => 'password',
);
return $args;
}
function password_init()
{
$this->register_handler('plugin.body', array($this, 'password_form'));
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($this->gettext('changepasswd'));
if (rcube_utils::get_input_value('_first', rcube_utils::INPUT_GET)) {
$rcmail->output->command('display_message', $this->gettext('firstloginchange'), 'notice');
}
$rcmail->output->send('plugin');
}
function password_save()
{
$this->register_handler('plugin.body', array($this, 'password_form'));
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($this->gettext('changepasswd'));
- $confirm = $rcmail->config->get('password_confirm_current');
+ $form_disabled = $rcmail->config->get('password_disabled');
+ $confirm = $rcmail->config->get('password_confirm_current');
$required_length = intval($rcmail->config->get('password_minimum_length'));
$check_strength = $rcmail->config->get('password_require_nonalpha');
if (($confirm && !isset($_POST['_curpasswd'])) || !isset($_POST['_newpasswd'])) {
$rcmail->output->command('display_message', $this->gettext('nopassword'), 'error');
}
else {
$charset = strtoupper($rcmail->config->get('password_charset', 'ISO-8859-1'));
$rc_charset = strtoupper($rcmail->output->get_charset());
$sespwd = $rcmail->decrypt($_SESSION['password']);
$curpwd = $confirm ? rcube_utils::get_input_value('_curpasswd', rcube_utils::INPUT_POST, true, $charset) : $sespwd;
$newpwd = rcube_utils::get_input_value('_newpasswd', rcube_utils::INPUT_POST, true);
$conpwd = rcube_utils::get_input_value('_confpasswd', rcube_utils::INPUT_POST, true);
// check allowed characters according to the configured 'password_charset' option
// by converting the password entered by the user to this charset and back to UTF-8
$orig_pwd = $newpwd;
$chk_pwd = rcube_charset::convert($orig_pwd, $rc_charset, $charset);
$chk_pwd = rcube_charset::convert($chk_pwd, $charset, $rc_charset);
// WARNING: Default password_charset is ISO-8859-1, so conversion will
// change national characters. This may disable possibility of using
// the same password in other MUA's.
// We're doing this for consistence with Roundcube core
$newpwd = rcube_charset::convert($newpwd, $rc_charset, $charset);
$conpwd = rcube_charset::convert($conpwd, $rc_charset, $charset);
if ($chk_pwd != $orig_pwd) {
$rcmail->output->command('display_message', $this->gettext('passwordforbidden'), 'error');
}
// other passwords validity checks
else if ($conpwd != $newpwd) {
$rcmail->output->command('display_message', $this->gettext('passwordinconsistency'), 'error');
}
else if ($confirm && $sespwd != $curpwd) {
$rcmail->output->command('display_message', $this->gettext('passwordincorrect'), 'error');
}
else if ($required_length && strlen($newpwd) < $required_length) {
$rcmail->output->command('display_message', $this->gettext(
array('name' => 'passwordshort', 'vars' => array('length' => $required_length))), 'error');
}
else if ($check_strength && (!preg_match("/[0-9]/", $newpwd) || !preg_match("/[^A-Za-z0-9]/", $newpwd))) {
$rcmail->output->command('display_message', $this->gettext('passwordweak'), 'error');
}
// password is the same as the old one, do nothing, return success
else if ($sespwd == $newpwd && !$rcmail->config->get('password_force_save')) {
$rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation');
}
// try to save the password
else if (!($res = $this->_save($curpwd, $newpwd))) {
$rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation');
// allow additional actions after password change (e.g. reset some backends)
$plugin = $rcmail->plugins->exec_hook('password_change', array(
'old_pass' => $curpwd, 'new_pass' => $newpwd));
// Reset session password
$_SESSION['password'] = $rcmail->encrypt($plugin['new_pass']);
// Log password change
if ($rcmail->config->get('password_log')) {
rcube::write_log('password', sprintf('Password changed for user %s (ID: %d) from %s',
$rcmail->get_user_name(), $rcmail->user->ID, rcube_utils::remote_ip()));
}
}
else {
$rcmail->output->command('display_message', $res, 'error');
}
}
$rcmail->overwrite_action('plugin.password');
$rcmail->output->send('plugin');
}
function password_form()
{
$rcmail = rcmail::get_instance();
// add some labels to client
$rcmail->output->add_label(
'password.nopassword',
'password.nocurpassword',
'password.passwordinconsistency'
);
+ $form_disabled = $rcmail->config->get('password_disabled');
+
$rcmail->output->set_env('product_name', $rcmail->config->get('product_name'));
+ $rcmail->output->set_env('password_disabled', !empty($form_disabled));
$table = new html_table(array('cols' => 2));
if ($rcmail->config->get('password_confirm_current')) {
// show current password selection
$field_id = 'curpasswd';
- $input_curpasswd = new html_passwordfield(array('name' => '_curpasswd', 'id' => $field_id,
- 'size' => 20, 'autocomplete' => 'off'));
+ $input_curpasswd = new html_passwordfield(array(
+ 'name' => '_curpasswd',
+ 'id' => $field_id,
+ 'size' => 20,
+ 'autocomplete' => 'off',
+ ));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('curpasswd'))));
$table->add(null, $input_curpasswd->show());
}
// show new password selection
$field_id = 'newpasswd';
- $input_newpasswd = new html_passwordfield(array('name' => '_newpasswd', 'id' => $field_id,
- 'size' => 20, 'autocomplete' => 'off'));
+ $input_newpasswd = new html_passwordfield(array(
+ 'name' => '_newpasswd',
+ 'id' => $field_id,
+ 'size' => 20,
+ 'autocomplete' => 'off',
+ ));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('newpasswd'))));
$table->add(null, $input_newpasswd->show());
// show confirm password selection
$field_id = 'confpasswd';
- $input_confpasswd = new html_passwordfield(array('name' => '_confpasswd', 'id' => $field_id,
- 'size' => 20, 'autocomplete' => 'off'));
+ $input_confpasswd = new html_passwordfield(array(
+ 'name' => '_confpasswd',
+ 'id' => $field_id,
+ 'size' => 20,
+ 'autocomplete' => 'off',
+ ));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('confpasswd'))));
$table->add(null, $input_confpasswd->show());
$rules = '';
$required_length = intval($rcmail->config->get('password_minimum_length'));
if ($required_length > 0) {
$rules .= html::tag('li', array('id' => 'required-length'), $this->gettext(array(
'name' => 'passwordshort',
'vars' => array('length' => $required_length)
)));
}
if ($rcmail->config->get('password_require_nonalpha')) {
$rules .= html::tag('li', array('id' => 'require-nonalpha'), $this->gettext('passwordweak'));
}
if (!empty($rules)) {
$rules = html::tag('ul', array('id' => 'ruleslist'), $rules);
}
+ if ($form_disabled) {
+ $disabled_msg = is_string($form_disabled) ? $form_disabled : $this->gettext('disablednotice');
+ $disabled_msg = html::div(array('class' => 'boxwarning', 'id' => 'password-notice'), $disabled_msg);
+ }
+
+ $submit_button = $rcmail->output->button(array(
+ 'command' => 'plugin.password-save',
+ 'type' => 'input',
+ 'class' => 'button mainaction',
+ 'label' => 'save',
+ ));
+
$out = html::div(array('class' => 'box'),
- html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd')) .
- html::div(array('class' => 'boxcontent'), $table->show() .
- $rules .
- html::p(null,
- $rcmail->output->button(array(
- 'command' => 'plugin.password-save',
- 'type' => 'input',
- 'class' => 'button mainaction',
- 'label' => 'save'
- )))));
+ html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd'))
+ . html::div(array('class' => 'boxcontent'),
+ $disabled_msg . $table->show() . $rules . html::p(null, $submit_button)));
$rcmail->output->add_gui_object('passform', 'password-form');
+ $this->include_script('password.js');
+
return $rcmail->output->form_tag(array(
'id' => 'password-form',
'name' => 'password-form',
'method' => 'post',
'action' => './?_task=settings&_action=plugin.password-save',
), $out);
}
private function _save($curpass, $passwd)
{
$config = rcmail::get_instance()->config;
$driver = $config->get('password_driver', 'sql');
$class = "rcube_{$driver}_password";
$file = $this->home . "/drivers/$driver.php";
if (!file_exists($file)) {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Unable to open driver file ($file)"
), true, false);
return $this->gettext('internalerror');
}
include_once $file;
if (!class_exists($class, false) || !method_exists($class, 'save')) {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Broken driver $driver"
), true, false);
return $this->gettext('internalerror');
}
$object = new $class;
$result = $object->save($curpass, $passwd);
if (is_array($result)) {
$message = $result['message'];
$result = $result['code'];
}
switch ($result) {
case PASSWORD_SUCCESS:
return;
case PASSWORD_CRYPT_ERROR:
$reason = $this->gettext('crypterror');
break;
case PASSWORD_CONNECT_ERROR:
$reason = $this->gettext('connecterror');
break;
case PASSWORD_ERROR:
default:
$reason = $this->gettext('internalerror');
}
if ($message) {
$reason .= ' ' . $message;
}
return $reason;
}
function user_create($args)
{
$this->newuser = true;
return $args;
}
function login_after($args)
{
if ($this->newuser && $this->check_host_login_exceptions()) {
$args['_task'] = 'settings';
$args['_action'] = 'plugin.password';
$args['_first'] = 'true';
}
return $args;
}
// Check if host and login is allowed to change the password, false = not allowed, true = not allowed
private function check_host_login_exceptions()
{
$rcmail = rcmail::get_instance();
// Host exceptions
$hosts = $rcmail->config->get('password_hosts');
if (!empty($hosts) && !in_array($_SESSION['storage_host'], $hosts)) {
return false;
}
// Login exceptions
if ($exceptions = $rcmail->config->get('password_login_exceptions')) {
$exceptions = array_map('trim', (array) $exceptions);
$exceptions = array_filter($exceptions);
$username = $_SESSION['username'];
foreach ($exceptions as $ec) {
if ($username === $ec) {
return false;
}
}
}
return true;
}
/**
* Hashes a password and returns the hash based on the specified method
*
* Parts of the code originally from the phpLDAPadmin development team
* http://phpldapadmin.sourceforge.net/
*
* @param string Clear password
* @param string Hashing method
* @param bool|string Prefix string or TRUE to add a default prefix
*
* @return string Hashed password
*/
static function hash_password($password, $method = '', $prefixed = true)
{
$method = strtolower($method);
$rcmail = rcmail::get_instance();
if (empty($method) || $method == 'default') {
$method = $rcmail->config->get('password_algorithm');
$prefixed = $rcmail->config->get('password_algorithm_prefix');
$default = true;
}
else if ($method == 'crypt') { // deprecated
if (!($method = $rcmail->config->get('password_crypt_hash'))) {
$method = 'md5';
}
if (!strpos($method, '-crypt')) {
$method .= '-crypt';
}
}
switch ($method) {
case 'des':
case 'des-crypt':
$crypted = crypt($password, self::random_salt(2));
$prefix = '{CRYPT}';
break;
case 'ext_des': // for BC
case 'ext-des-crypt':
$crypted = crypt($password, '_' . self::random_salt(8));
$prefix = '{CRYPT}';
break;
case 'md5crypt': // for BC
case 'md5-crypt':
$crypted = crypt($password, '$1$' . self::random_salt(9));
$prefix = '{CRYPT}';
break;
case 'sha256-crypt':
$crypted = crypt($password, '$5$' . self::random_salt(16));
$prefix = '{CRYPT}';
break;
case 'sha512-crypt':
$crypted = crypt($password, '$6$' . self::random_salt(16));
$prefix = '{CRYPT}';
break;
case 'blowfish': // for BC
case 'blowfish-crypt':
$cost = (int) $rcmail->config->get('password_blowfish_cost');
$cost = $cost < 4 || $cost > 31 ? 12 : $cost;
$prefix = sprintf('$2a$%02d$', $cost);
$crypted = crypt($password, $prefix . self::random_salt(22));
$prefix = '{CRYPT}';
break;
case 'md5':
$crypted = base64_encode(pack('H*', md5($password)));
$prefix = '{MD5}';
break;
case 'sha':
if (function_exists('sha1')) {
$crypted = pack('H*', sha1($password));
}
else if (function_exists('hash')) {
$crypted = hash('sha1', $password, true);
}
else if (function_exists('mhash')) {
$crypted = mhash(MHASH_SHA1, $password);
}
else {
rcube::raise_error(array(
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Your PHP install does not have the mhash()/hash() nor sha1() function"
), true, true);
}
$crypted = base64_encode($crypted);
$prefix = '{SHA}';
break;
case 'ssha':
$salt = substr(pack('h*', md5(mt_rand())), 0, 8);
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
$salt = mhash_keygen_s2k(MHASH_SHA1, $password, $salt, 4);
$crypted = mhash(MHASH_SHA1, $password . $salt);
}
else if (function_exists('sha1')) {
$salt = substr(pack("H*", sha1($salt . $password)), 0, 4);
$crypted = sha1($password . $salt, true);
}
else if (function_exists('hash')) {
$salt = substr(pack("H*", hash('sha1', $salt . $password)), 0, 4);
$crypted = hash('sha1', $password . $salt, true);
}
else {
rcube::raise_error(array(
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Your PHP install does not have the mhash()/hash() nor sha1() function"
), true, true);
}
$crypted = base64_encode($crypted . $salt);
$prefix = '{SSHA}';
break;
case 'smd5':
$salt = substr(pack('h*', md5(mt_rand())), 0, 8);
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
$salt = mhash_keygen_s2k(MHASH_MD5, $password, $salt, 4);
$crypted = mhash(MHASH_MD5, $password . $salt);
}
else if (function_exists('hash')) {
$salt = substr(pack("H*", hash('md5', $salt . $password)), 0, 4);
$crypted = hash('md5', $password . $salt, true);
}
else {
$salt = substr(pack("H*", md5($salt . $password)), 0, 4);
$crypted = md5($password . $salt, true);
}
$crypted = base64_encode($crypted . $salt);
$prefix = '{SMD5}';
break;
case 'samba':
if (function_exists('hash')) {
$crypted = hash('md4', rcube_charset::convert($password, RCUBE_CHARSET, 'UTF-16LE'));
$crypted = strtoupper($crypted_password);
}
else {
rcube::raise_error(array(
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Your PHP install does not have hash() function"
), true, true);
}
break;
case 'ad':
$crypted = rcube_charset::convert('"' . $password . '"', RCUBE_CHARSET, 'UTF-16LE');
break;
case 'cram-md5': // deprecated
require_once __DIR__ . '/../helpers/dovecot_hmacmd5.php';
$crypted = dovecot_hmacmd5($password);
$prefix = '{CRAM-MD5}';
break;
case 'dovecot':
if (!($dovecotpw = $rcmail->config->get('password_dovecotpw'))) {
$dovecotpw = 'dovecotpw';
}
if (!($method = $rcmail->config->get('password_dovecotpw_method'))) {
$method = 'CRAM-MD5';
}
// use common temp dir
$tmp_dir = $rcmail->config->get('temp_dir');
$tmpfile = tempnam($tmp_dir, 'roundcube-');
$pipe = popen("$dovecotpw -s '$method' > '$tmpfile'", "w");
if (!$pipe) {
unlink($tmpfile);
return false;
}
else {
fwrite($pipe, $passwd . "\n", 1+strlen($passwd)); usleep(1000);
fwrite($pipe, $passwd . "\n", 1+strlen($passwd));
pclose($pipe);
$crypted = trim(file_get_contents($tmpfile), "\n");
unlink($tmpfile);
if (!preg_match('/^\{' . $method . '\}/', $newpass)) {
return false;
}
if (!$default) {
$prefixed = (bool) $rcmail->config->get('password_dovecotpw_with_method');
}
if (!$prefixed) {
$crypted = trim(str_replace('{' . $method . '}', '', $crypted));
}
$prefixed = false;
}
break;
case 'hash': // deprecated
if (!extension_loaded('hash')) {
rcube::raise_error(array(
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: 'hash' extension not loaded!"
), true, true);
}
if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) {
$hash_algo = 'sha1';
}
$crypted = hash($hash_algo, $password);
if ($rcmail->config->get('password_hash_base64')) {
$crypted = base64_encode(pack('H*', $crypted));
}
break;
case 'clear':
$crypted = $password;
}
if ($crypted === null || $crypted === false) {
return false;
}
if ($prefixed && $prefixed !== true) {
$prefix = $prefixed;
$prefixed = true;
}
if ($prefixed === true && $prefix) {
$crypted = $prefix . $crypted;
}
return $crypted;
}
/**
* Used to generate a random salt for crypt-style passwords
*
* Code originaly from the phpLDAPadmin development team
* http://phpldapadmin.sourceforge.net/
*/
static function random_salt($length)
{
$possible = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./';
$str = '';
while (strlen($str) < $length) {
$str .= substr($possible, (rand() % strlen($possible)), 1);
}
return $str;
}
}
diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php
index 72b7e6ba1..26bb91d78 100644
--- a/program/include/rcmail_output_html.php
+++ b/program/include/rcmail_output_html.php
@@ -1,2037 +1,2036 @@
<?php
/**
+-----------------------------------------------------------------------+
| program/include/rcmail_output_html.php |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2006-2014, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Class to handle HTML page output using a skin template. |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
/**
* Class to create HTML page output using a skin template
*
* @package Webmail
* @subpackage View
*/
class rcmail_output_html extends rcmail_output
{
public $type = 'html';
protected $message;
protected $template_name;
protected $js_env = array();
protected $js_labels = array();
protected $js_commands = array();
protected $skin_paths = array();
protected $scripts_path = '';
protected $script_files = array();
protected $css_files = array();
protected $scripts = array();
protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
protected $header = '';
protected $footer = '';
protected $body = '';
protected $base_path = '';
protected $assets_path;
protected $assets_dir = RCUBE_INSTALL_PATH;
protected $devel_mode = false;
// deprecated names of templates used before 0.5
protected $deprecated_templates = array(
'contact' => 'showcontact',
'contactadd' => 'addcontact',
'contactedit' => 'editcontact',
'identityedit' => 'editidentity',
'messageprint' => 'printmessage',
);
/**
* Constructor
*/
public function __construct($task = null, $framed = false)
{
parent::__construct();
$this->devel_mode = $this->config->get('devel_mode');
$this->set_env('task', $task);
$this->set_env('x_frame_options', $this->config->get('x_frame_options', 'sameorigin'));
$this->set_env('standard_windows', (bool) $this->config->get('standard_windows'));
$this->set_env('locale', $_SESSION['language']);
// add cookie info
$this->set_env('cookie_domain', ini_get('session.cookie_domain'));
$this->set_env('cookie_path', ini_get('session.cookie_path'));
$this->set_env('cookie_secure', filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN));
// load the correct skin (in case user-defined)
$skin = $this->config->get('skin');
$this->set_skin($skin);
$this->set_env('skin', $skin);
$this->set_assets_path($this->config->get('assets_path'), $this->config->get('assets_dir'));
if (!empty($_REQUEST['_extwin']))
$this->set_env('extwin', 1);
if ($this->framed || $framed)
$this->set_env('framed', 1);
$lic = <<<EOF
/*
@licstart The following is the entire license notice for the
JavaScript code in this page.
Copyright (C) 2005-2014 The Roundcube Dev Team
The JavaScript code in this page is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
The code is distributed WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU GPL for more details.
@licend The above is the entire license notice
for the JavaScript code in this page.
*/
EOF;
// add common javascripts
$this->add_script($lic, 'head_top');
$this->add_script('var '.self::JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top');
// don't wait for page onload. Call init at the bottom of the page (delayed)
$this->add_script(self::JS_OBJECT_NAME.'.init();', 'docready');
$this->scripts_path = 'program/js/';
$this->include_script('jquery.min.js');
$this->include_script('common.js');
$this->include_script('app.js');
// register common UI objects
$this->add_handlers(array(
'loginform' => array($this, 'login_form'),
'preloader' => array($this, 'preloader'),
'username' => array($this, 'current_username'),
'message' => array($this, 'message_container'),
'charsetselector' => array($this, 'charset_selector'),
'aboutcontent' => array($this, 'about_content'),
));
}
/**
* Set environment variable
*
* @param string Property name
* @param mixed Property value
* @param boolean True if this property should be added to client environment
*/
public function set_env($name, $value, $addtojs = true)
{
$this->env[$name] = $value;
if ($addtojs || isset($this->js_env[$name])) {
$this->js_env[$name] = $value;
}
}
/**
* Parse and set assets path
*
* @param string Assets path (relative or absolute URL)
*/
public function set_assets_path($path, $fs_dir = null)
{
if (empty($path)) {
return;
}
$path = rtrim($path, '/') . '/';
// handle relative assets path
if (!preg_match('|^https?://|', $path) && $path[0] != '/') {
// save the path to search for asset files later
$this->assets_dir = $path;
$base = preg_replace('/[?#&].*$/', '', $_SERVER['REQUEST_URI']);
$base = rtrim($base, '/');
// remove url token if exists
if ($len = intval($this->config->get('use_secure_urls'))) {
$_base = explode('/', $base);
$last = count($_base) - 1;
$length = $len > 1 ? $len : 16; // as in rcube::get_secure_url_token()
// we can't use real token here because it
// does not exists in unauthenticated state,
// hope this will not produce false-positive matches
if ($last > -1 && preg_match('/^[a-f0-9]{' . $length . '}$/', $_base[$last])) {
$path = '../' . $path;
}
}
}
// set filesystem path for assets
if ($fs_dir) {
if ($fs_dir[0] != '/') {
$fs_dir = realpath(RCUBE_INSTALL_PATH . $fs_dir);
}
// ensure the path ends with a slash
$this->assets_dir = rtrim($fs_dir, '/') . '/';
}
$this->assets_path = $path;
$this->set_env('assets_path', $path);
}
/**
* Getter for the current page title
*
* @return string The page title
*/
protected function get_pagetitle()
{
if (!empty($this->pagetitle)) {
$title = $this->pagetitle;
}
else if ($this->env['task'] == 'login') {
$title = $this->app->gettext(array(
'name' => 'welcome',
'vars' => array('product' => $this->config->get('product_name')
)));
}
else {
$title = ucfirst($this->env['task']);
}
return $title;
}
/**
* Set skin
*/
public function set_skin($skin)
{
$valid = false;
$path = RCUBE_INSTALL_PATH . 'skins/';
if (!empty($skin) && is_dir($path . $skin) && is_readable($path . $skin)) {
$skin_path = 'skins/' . $skin;
$valid = true;
}
else {
$skin_path = $this->config->get('skin_path');
if (!$skin_path) {
$skin_path = 'skins/' . rcube_config::DEFAULT_SKIN;
}
$valid = !$skin;
}
$skin_path = rtrim($skin_path, '/');
$this->config->set('skin_path', $skin_path);
$this->base_path = $skin_path;
// register skin path(s)
$this->skin_paths = array();
$this->load_skin($skin_path);
return $valid;
}
/**
* Helper method to recursively read skin meta files and register search paths
*/
private function load_skin($skin_path)
{
$this->skin_paths[] = $skin_path;
// read meta file and check for dependecies
$meta = @file_get_contents(RCUBE_INSTALL_PATH . $skin_path . '/meta.json');
$meta = @json_decode($meta, true);
$meta['path'] = $skin_path;
$skin_id = end(explode('/', $skin_path));
if (!$meta['name']) {
$meta['name'] = $skin_id;
}
$this->skins[$skin_id] = $meta;
if ($meta['extends']) {
$path = RCUBE_INSTALL_PATH . 'skins/';
if (is_dir($path . $meta['extends']) && is_readable($path . $meta['extends'])) {
$this->load_skin('skins/' . $meta['extends']);
}
}
}
/**
* Check if a specific template exists
*
* @param string Template name
* @return boolean True if template exists
*/
public function template_exists($name)
{
foreach ($this->skin_paths as $skin_path) {
$filename = RCUBE_INSTALL_PATH . $skin_path . '/templates/' . $name . '.html';
if ((is_file($filename) && is_readable($filename))
|| ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name]))
) {
return true;
}
}
return false;
}
/**
* Find the given file in the current skin path stack
*
* @param string File name/path to resolve (starting with /)
* @param string Reference to the base path of the matching skin
* @param string Additional path to search in
*
* @return mixed Relative path to the requested file or False if not found
*/
public function get_skin_file($file, &$skin_path = null, $add_path = null)
{
$skin_paths = $this->skin_paths;
if ($add_path) {
array_unshift($skin_paths, $add_path);
}
foreach ($skin_paths as $skin_path) {
$path = realpath(RCUBE_INSTALL_PATH . $skin_path . $file);
if ($path && is_file($path)) {
return $skin_path . $file;
}
if ($this->assets_dir != RCUBE_INSTALL_PATH) {
$path = realpath($this->assets_dir . $skin_path . $file);
if ($path && is_file($path)) {
return $skin_path . $file;
}
}
}
return false;
}
/**
* Register a GUI object to the client script
*
* @param string Object name
* @param string Object ID
* @return void
*/
public function add_gui_object($obj, $id)
{
$this->add_script(self::JS_OBJECT_NAME.".gui_object('$obj', '$id');");
}
/**
* Call a client method
*
* @param string Method to call
* @param ... Additional arguments
*/
public function command()
{
$cmd = func_get_args();
if (strpos($cmd[0], 'plugin.') !== false)
$this->js_commands[] = array('triggerEvent', $cmd[0], $cmd[1]);
else
$this->js_commands[] = $cmd;
}
/**
* Add a localized label to the client environment
*/
public function add_label()
{
$args = func_get_args();
if (count($args) == 1 && is_array($args[0]))
$args = $args[0];
foreach ($args as $name) {
$this->js_labels[$name] = $this->app->gettext($name);
}
}
/**
* Invoke display_message command
*
* @param string $message Message to display
* @param string $type Message type [notice|confirm|error]
* @param array $vars Key-value pairs to be replaced in localized text
* @param boolean $override Override last set message
* @param int $timeout Message display time in seconds
* @uses self::command()
*/
public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
{
if ($override || !$this->message) {
if ($this->app->text_exists($message)) {
if (!empty($vars))
$vars = array_map('Q', $vars);
$msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
}
else
$msgtext = $message;
$this->message = $message;
$this->command('display_message', $msgtext, $type, $timeout * 1000);
}
}
/**
* Delete all stored env variables and commands
*
* @param bool $all Reset all env variables (including internal)
*/
public function reset($all = false)
{
$framed = $this->framed;
$env = $all ? null : array_intersect_key($this->env, array('extwin'=>1, 'framed'=>1));
parent::reset();
// let some env variables survive
$this->env = $this->js_env = $env;
$this->framed = $framed || $this->env['framed'];
$this->js_labels = array();
$this->js_commands = array();
$this->script_files = array();
$this->scripts = array();
$this->header = '';
$this->footer = '';
$this->body = '';
// load defaults
if (!$all) {
$this->__construct();
}
}
/**
* Redirect to a certain url
*
* @param mixed $p Either a string with the action or url parameters as key-value pairs
* @param int $delay Delay in seconds
* @param bool $secure Redirect to secure location (see rcmail::url())
*/
public function redirect($p = array(), $delay = 1, $secure = false)
{
if ($this->env['extwin'])
$p['extwin'] = 1;
$location = $this->app->url($p, false, false, $secure);
header('Location: ' . $location);
exit;
}
/**
* Send the request output to the client.
* This will either parse a skin tempalte or send an AJAX response
*
* @param string Template name
* @param boolean True if script should terminate (default)
*/
public function send($templ = null, $exit = true)
{
if ($templ != 'iframe') {
// prevent from endless loops
if ($exit != 'recur' && $this->app->plugins->is_processing('render_page')) {
rcube::raise_error(array('code' => 505, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => 'Recursion alert: ignoring output->send()'), true, false);
return;
}
$this->parse($templ, false);
}
else {
$this->framed = true;
$this->write();
}
// set output asap
ob_flush();
flush();
if ($exit) {
exit;
}
}
/**
* Process template and write to stdOut
*
* @param string $template HTML template content
*/
public function write($template = '')
{
if (!empty($this->script_files)) {
$this->set_env('request_token', $this->app->get_request_token());
}
$commands = $this->get_js_commands($framed);
// if all js commands go to parent window we can ignore all
// script files and skip rcube_webmail initialization (#1489792)
if ($framed) {
$this->scripts = array();
$this->script_files = array();
$this->header = '';
$this->footer = '';
}
// write all javascript commands
$this->add_script($commands, 'head_top');
// send clickjacking protection headers
$iframe = $this->framed || $this->env['framed'];
if (!headers_sent() && ($xframe = $this->app->config->get('x_frame_options', 'sameorigin'))) {
header('X-Frame-Options: ' . ($iframe && $xframe == 'deny' ? 'sameorigin' : $xframe));
}
// call super method
$this->_write($template, $this->config->get('skin_path'));
}
/**
* Parse a specific skin template and deliver to stdout (or return)
*
* @param string Template name
* @param boolean Exit script
* @param boolean Don't write to stdout, return parsed content instead
*
* @link http://php.net/manual/en/function.exit.php
*/
function parse($name = 'main', $exit = true, $write = true)
{
$plugin = false;
$realname = $name;
$plugin_skin_paths = array();
$this->template_name = $realname;
$temp = explode('.', $name, 2);
if (count($temp) > 1) {
$plugin = $temp[0];
$name = $temp[1];
$skin_dir = $plugin . '/skins/' . $this->config->get('skin');
// apply skin search escalation list to plugin directory
foreach ($this->skin_paths as $skin_path) {
$plugin_skin_paths[] = $this->app->plugins->url . $plugin . '/' . $skin_path;
}
// add fallback to default skin
if (is_dir($this->app->plugins->dir . $plugin . '/skins/default')) {
$skin_dir = $plugin . '/skins/default';
$plugin_skin_paths[] = $this->app->plugins->url . $skin_dir;
}
// prepend plugin skin paths to search list
$this->skin_paths = array_merge($plugin_skin_paths, $this->skin_paths);
}
// find skin template
$path = false;
foreach ($this->skin_paths as $skin_path) {
$path = RCUBE_INSTALL_PATH . "$skin_path/templates/$name.html";
// fallback to deprecated template names
if (!is_readable($path) && $this->deprecated_templates[$realname]) {
$path = RCUBE_INSTALL_PATH . "$skin_path/templates/" . $this->deprecated_templates[$realname] . ".html";
if (is_readable($path)) {
rcube::raise_error(array(
'code' => 502, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Using deprecated template '" . $this->deprecated_templates[$realname]
. "' in $skin_path/templates. Please rename to '$realname'"),
true, false);
}
}
if (is_readable($path)) {
$this->config->set('skin_path', $skin_path);
$this->base_path = preg_replace('!plugins/\w+/!', '', $skin_path); // set base_path to core skin directory (not plugin's skin)
$skin_dir = preg_replace('!^plugins/!', '', $skin_path);
break;
}
else {
$path = false;
}
}
// read template file
if (!$path || ($templ = @file_get_contents($path)) === false) {
rcube::raise_error(array(
'code' => 404,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => 'Error loading template for '.$realname
), true, $write);
$this->skin_paths = array_slice($this->skin_paths, count($plugin_skin_paths));
return false;
}
// replace all path references to plugins/... with the configured plugins dir
// and /this/ to the current plugin skin directory
if ($plugin) {
$templ = preg_replace(array('/\bplugins\//', '/(["\']?)\/this\//'), array($this->app->plugins->url, '\\1'.$this->app->plugins->url.$skin_dir.'/'), $templ);
}
// parse for specialtags
$output = $this->parse_conditions($templ);
$output = $this->parse_xml($output);
// trigger generic hook where plugins can put additional content to the page
$hook = $this->app->plugins->exec_hook("render_page", array('template' => $realname, 'content' => $output));
// save some memory
$output = $hook['content'];
unset($hook['content']);
// make sure all <form> tags have a valid request token
$output = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $output);
$this->footer = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $this->footer);
// remove plugin skin paths from current context
$this->skin_paths = array_slice($this->skin_paths, count($plugin_skin_paths));
if (!$write) {
return $output;
}
$this->write(trim($output));
if ($exit) {
exit;
}
}
/**
* Return executable javascript code for all registered commands
*
* @return string $out
*/
protected function get_js_commands(&$framed = null)
{
$out = '';
$parent_commands = 0;
$top_commands = array();
// these should be always on top,
// e.g. hide_message() below depends on env.framed
if (!$this->framed && !empty($this->js_env)) {
$top_commands[] = array('set_env', $this->js_env);
}
if (!empty($this->js_labels)) {
$top_commands[] = array('add_label', $this->js_labels);
}
// unlock interface after iframe load
$unlock = preg_replace('/[^a-z0-9]/i', '', $_REQUEST['_unlock']);
if ($this->framed) {
$top_commands[] = array('iframe_loaded', $unlock);
}
else if ($unlock) {
$top_commands[] = array('hide_message', $unlock);
}
$commands = array_merge($top_commands, $this->js_commands);
foreach ($commands as $i => $args) {
$method = array_shift($args);
$parent = $this->framed || preg_match('/^parent\./', $method);
foreach ($args as $i => $arg) {
$args[$i] = self::json_serialize($arg);
}
if ($parent) {
$parent_commands++;
$method = preg_replace('/^parent\./', '', $method);
$parent_prefix = 'if (window.parent && parent.' . self::JS_OBJECT_NAME . ') parent.';
$method = $parent_prefix . self::JS_OBJECT_NAME . '.' . $method;
}
else {
$method = self::JS_OBJECT_NAME . '.' . $method;
}
$out .= sprintf("%s(%s);\n", $method, implode(',', $args));
}
$framed = $parent_prefix && $parent_commands == count($commands);
// make the output more compact if all commands go to parent window
if ($framed) {
$out = "if (window.parent && parent." . self::JS_OBJECT_NAME . ") {\n"
. str_replace($parent_prefix, "\tparent.", $out)
. "}\n";
}
return $out;
}
/**
* Make URLs starting with a slash point to skin directory
*
* @param string Input string
* @param boolean True if URL should be resolved using the current skin path stack
* @return string
*/
public function abs_url($str, $search_path = false)
{
if ($str[0] == '/') {
if ($search_path && ($file_url = $this->get_skin_file($str, $skin_path))) {
return $file_url;
}
return $this->base_path . $str;
}
return $str;
}
/**
* Show error page and terminate script execution
*
* @param int $code Error code
* @param string $message Error message
*/
public function raise_error($code, $message)
{
global $__page_content, $ERROR_CODE, $ERROR_MESSAGE;
$ERROR_CODE = $code;
$ERROR_MESSAGE = $message;
include RCUBE_INSTALL_PATH . 'program/steps/utils/error.inc';
exit;
}
/**
* Modify path by adding URL prefix if configured
*/
public function asset_url($path)
{
// iframe content can't be in a different domain
// @TODO: check if assests are on a different domain
if (!$this->assets_path || in_array($path[0], array('?', '/', '.')) || strpos($path, '://')) {
return $path;
}
return $this->assets_path . $path;
}
/***** Template parsing methods *****/
/**
* Replace all strings ($varname)
* with the content of the according global variable.
*/
protected function parse_with_globals($input)
{
$GLOBALS['__version'] = html::quote(RCMAIL_VERSION);
$GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
$GLOBALS['__skin_path'] = html::quote($this->base_path);
return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
array($this, 'globals_callback'), $input);
}
/**
* Callback funtion for preg_replace_callback() in parse_with_globals()
*/
protected function globals_callback($matches)
{
return $GLOBALS[$matches[1]];
}
/**
* Correct absolute paths in images and other tags
* add timestamp to .js and .css filename
*/
protected function fix_paths($output)
{
return preg_replace_callback(
'!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
array($this, 'file_callback'), $output);
}
/**
* Callback function for preg_replace_callback in fix_paths()
*
* @return string Parsed string
*/
protected function file_callback($matches)
{
$file = $matches[3];
$file = preg_replace('!^/this/!', '/', $file);
// correct absolute paths
if ($file[0] == '/') {
$file = $this->base_path . $file;
}
// add file modification timestamp
if (preg_match('/\.(js|css)$/', $file, $m)) {
$file = $this->file_mod($file);
}
return $matches[1] . '=' . $matches[2] . $file . $matches[4];
}
/**
* Correct paths of asset files according to assets_path
*/
protected function fix_assets_paths($output)
{
return preg_replace_callback(
'!(src|href|background)=(["\']?)([a-z0-9/_.?=-]+)(["\'\s>])!i',
array($this, 'assets_callback'), $output);
}
/**
* Callback function for preg_replace_callback in fix_assets_paths()
*
* @return string Parsed string
*/
protected function assets_callback($matches)
{
$file = $this->asset_url($matches[3]);
return $matches[1] . '=' . $matches[2] . $file . $matches[4];
}
/**
* Modify file by adding mtime indicator
*/
protected function file_mod($file)
{
$fs = false;
$ext = substr($file, strrpos($file, '.') + 1);
// use minified file if exists (not in development mode)
if (!$this->devel_mode && !preg_match('/\.min\.' . $ext . '$/', $file)) {
$minified_file = substr($file, 0, strlen($ext) * -1) . 'min.' . $ext;
if ($fs = @filemtime($this->assets_dir . $minified_file)) {
return $minified_file . '?s=' . $fs;
}
}
if ($fs = @filemtime($this->assets_dir . $file)) {
$file .= '?s=' . $fs;
}
return $file;
}
/**
* Public wrapper to dipp into template parsing.
*
* @param string $input
* @return string
* @uses rcmail_output_html::parse_xml()
* @since 0.1-rc1
*/
public function just_parse($input)
{
$input = $this->parse_conditions($input);
$input = $this->parse_xml($input);
return $input;
}
/**
* Parse for conditional tags
*
* @param string $input
* @return string
*/
protected function parse_conditions($input)
{
$matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>\n?/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE);
if ($matches && count($matches) == 4) {
if (preg_match('/^(else|endif)$/i', $matches[1])) {
return $matches[0] . $this->parse_conditions($matches[3]);
}
$attrib = html::parse_attrib_string($matches[2]);
if (isset($attrib['condition'])) {
$condmet = $this->check_condition($attrib['condition']);
$submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>\n?/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
if ($condmet) {
$result = $submatches[0];
$result.= ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>\n?/Uis', '', $submatches[3], 1) : $submatches[3]);
}
else {
$result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
}
return $matches[0] . $this->parse_conditions($result);
}
rcube::raise_error(array(
'code' => 500,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Unable to parse conditional tag " . $matches[2]
), true, false);
}
return $input;
}
/**
* Determines if a given condition is met
*
* @todo Extend this to allow real conditions, not just "set"
* @param string Condition statement
* @return boolean True if condition is met, False if not
*/
protected function check_condition($condition)
{
return $this->eval_expression($condition);
}
/**
* Inserts hidden field with CSRF-prevention-token into POST forms
*/
protected function alter_form_tag($matches)
{
$out = $matches[0];
$attrib = html::parse_attrib_string($matches[1]);
if (strtolower($attrib['method']) == 'post') {
$hidden = new html_hiddenfield(array('name' => '_token', 'value' => $this->app->get_request_token()));
$out .= "\n" . $hidden->show();
}
return $out;
}
/**
* Parse & evaluate a given expression and return its result.
*
* @param string Expression statement
*
* @return mixed Expression result
*/
protected function eval_expression ($expression)
{
$expression = preg_replace(
array(
'/session:([a-z0-9_]+)/i',
'/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i',
'/env:([a-z0-9_]+)/i',
'/request:([a-z0-9_]+)/i',
'/cookie:([a-z0-9_]+)/i',
'/browser:([a-z0-9_]+)/i',
'/template:name/i',
),
array(
"\$_SESSION['\\1']",
"\$app->config->get('\\1',rcube_utils::get_boolean('\\3'))",
"\$env['\\1']",
"rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)",
"\$_COOKIE['\\1']",
"\$browser->{'\\1'}",
$this->template_name,
),
$expression
);
$fn = create_function('$app,$browser,$env', "return ($expression);");
if (!$fn) {
rcube::raise_error(array(
'code' => 505,
'type' => 'php',
'file' => __FILE__,
'line' => __LINE__,
'message' => "Expression parse error on: ($expression)"), true, false);
return null;
}
return $fn($this->app, $this->browser, $this->env);
}
/**
* Search for special tags in input and replace them
* with the appropriate content
*
* @param string Input string to parse
* @return string Altered input string
* @todo Use DOM-parser to traverse template HTML
* @todo Maybe a cache.
*/
protected function parse_xml($input)
{
return preg_replace_callback('/<roundcube:([-_a-z]+)\s+((?:[^>]|\\\\>)+)(?<!\\\\)>/Ui', array($this, 'xml_command'), $input);
}
/**
* Callback function for parsing an xml command tag
* and turn it into real html content
*
* @param array Matches array of preg_replace_callback
* @return string Tag/Object content
*/
protected function xml_command($matches)
{
$command = strtolower($matches[1]);
$attrib = html::parse_attrib_string($matches[2]);
// empty output if required condition is not met
if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
return '';
}
// localize title and summary attributes
if ($command != 'button' && !empty($attrib['title']) && $this->app->text_exists($attrib['title'])) {
$attrib['title'] = $this->app->gettext($attrib['title']);
}
if ($command != 'button' && !empty($attrib['summary']) && $this->app->text_exists($attrib['summary'])) {
$attrib['summary'] = $this->app->gettext($attrib['summary']);
}
// execute command
switch ($command) {
// return a button
case 'button':
if ($attrib['name'] || $attrib['command']) {
return $this->button($attrib);
}
break;
// frame
case 'frame':
return $this->frame($attrib);
break;
// show a label
case 'label':
if ($attrib['expression'])
$attrib['name'] = $this->eval_expression($attrib['expression']);
if ($attrib['name'] || $attrib['command']) {
$vars = $attrib + array('product' => $this->config->get('product_name'));
unset($vars['name'], $vars['command']);
$label = $this->app->gettext($attrib + array('vars' => $vars));
$quoting = !empty($attrib['quoting']) ? strtolower($attrib['quoting']) : (rcube_utils::get_boolean((string)$attrib['html']) ? 'no' : '');
// 'noshow' can be used in skins to define new labels
if ($attrib['noshow']) {
return '';
}
switch ($quoting) {
case 'no':
case 'raw':
break;
case 'javascript':
case 'js':
$label = rcube::JQ($label);
break;
default:
$label = html::quote($label);
break;
}
return $label;
}
break;
// include a file
case 'include':
$old_base_path = $this->base_path;
if (!empty($attrib['skin_path'])) $attrib['skinpath'] = $attrib['skin_path'];
if ($path = $this->get_skin_file($attrib['file'], $skin_path, $attrib['skinpath'])) {
$this->base_path = preg_replace('!plugins/\w+/!', '', $skin_path); // set base_path to core skin directory (not plugin's skin)
$path = realpath(RCUBE_INSTALL_PATH . $path);
}
if (is_readable($path)) {
if ($this->config->get('skin_include_php')) {
$incl = $this->include_php($path);
}
else {
$incl = file_get_contents($path);
}
$incl = $this->parse_conditions($incl);
$incl = $this->parse_xml($incl);
$incl = $this->fix_paths($incl);
$this->base_path = $old_base_path;
return $incl;
}
break;
case 'plugin.include':
$hook = $this->app->plugins->exec_hook("template_plugin_include", $attrib);
return $hook['content'];
// define a container block
case 'container':
if ($attrib['name'] && $attrib['id']) {
$this->command('gui_container', $attrib['name'], $attrib['id']);
// let plugins insert some content here
$hook = $this->app->plugins->exec_hook("template_container", $attrib);
return $hook['content'];
}
break;
// return code for a specific application object
case 'object':
$object = strtolower($attrib['name']);
$content = '';
// we are calling a class/method
if (($handler = $this->object_handlers[$object]) && is_array($handler)) {
if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) ||
(is_string($handler[0]) && class_exists($handler[0])))
$content = call_user_func($handler, $attrib);
}
// execute object handler function
else if (function_exists($handler)) {
$content = call_user_func($handler, $attrib);
}
else if ($object == 'doctype') {
$content = html::doctype($attrib['value']);
}
else if ($object == 'logo') {
$attrib += array('alt' => $this->xml_command(array('', 'object', 'name="productname"')));
if ($logo = $this->config->get('skin_logo')) {
if (is_array($logo)) {
if ($template_logo = $logo[$this->template_name]) {
$attrib['src'] = $template_logo;
}
elseif ($template_logo = $logo['*']) {
$attrib['src'] = $template_logo;
}
}
else {
$attrib['src'] = $logo;
}
}
$content = html::img($attrib);
}
else if ($object == 'productname') {
$name = $this->config->get('product_name', 'Roundcube Webmail');
$content = html::quote($name);
}
else if ($object == 'version') {
$ver = (string)RCMAIL_VERSION;
if (is_file(RCUBE_INSTALL_PATH . '.svn/entries')) {
if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
$ver .= ' [SVN r'.$regs[1].']';
}
else if (is_file(RCUBE_INSTALL_PATH . '.git/index')) {
if (preg_match('/Date:\s+([^\n]+)/', @shell_exec('git log -1'), $regs)) {
if ($date = date('Ymd.Hi', strtotime($regs[1]))) {
$ver .= ' [GIT '.$date.']';
}
}
}
$content = html::quote($ver);
}
else if ($object == 'steptitle') {
$content = html::quote($this->get_pagetitle());
}
else if ($object == 'pagetitle') {
if ($this->devel_mode && !empty($_SESSION['username']))
$title = $_SESSION['username'].' :: ';
else if ($prod_name = $this->config->get('product_name'))
$title = $prod_name . ' :: ';
else
$title = '';
$title .= $this->get_pagetitle();
$content = html::quote($title);
}
// exec plugin hooks for this template object
$hook = $this->app->plugins->exec_hook("template_object_$object", $attrib + array('content' => $content));
return $hook['content'];
// return code for a specified eval expression
case 'exp':
return html::quote($this->eval_expression($attrib['expression']));
// return variable
case 'var':
$var = explode(':', $attrib['name']);
$name = $var[1];
$value = '';
switch ($var[0]) {
case 'env':
$value = $this->env[$name];
break;
case 'config':
$value = $this->config->get($name);
if (is_array($value) && $value[$_SESSION['storage_host']]) {
$value = $value[$_SESSION['storage_host']];
}
break;
case 'request':
$value = rcube_utils::get_input_value($name, rcube_utils::INPUT_GPC);
break;
case 'session':
$value = $_SESSION[$name];
break;
case 'cookie':
$value = htmlspecialchars($_COOKIE[$name]);
break;
case 'browser':
$value = $this->browser->{$name};
break;
}
if (is_array($value)) {
$value = implode(', ', $value);
}
return html::quote($value);
case 'form':
return $this->form_tag($attrib);
}
return '';
}
/**
* Include a specific file and return it's contents
*
* @param string File path
* @return string Contents of the processed file
*/
protected function include_php($file)
{
ob_start();
include $file;
$out = ob_get_contents();
ob_end_clean();
return $out;
}
/**
* Create and register a button
*
* @param array Named button attributes
* @return string HTML button
* @todo Remove all inline JS calls and use jQuery instead.
* @todo Remove all sprintf()'s - they are pretty, but also slow.
*/
public function button($attrib)
{
static $s_button_count = 100;
static $disabled_actions = null;
// these commands can be called directly via url
$a_static_commands = array('compose', 'list', 'preferences', 'folders', 'identities');
if (!($attrib['command'] || $attrib['name'] || $attrib['href'])) {
return '';
}
-
// try to find out the button type
if ($attrib['type']) {
$attrib['type'] = strtolower($attrib['type']);
if ($pos = strpos($attrib['type'], '-menuitem')) {
$attrib['type'] = substr($attrib['type'], 0, -9);
$menuitem = true;
}
}
else {
$attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
}
$command = $attrib['command'];
if ($attrib['task']) {
$element = $command = $attrib['task'] . '.' . $command;
}
else {
$element = ($this->env['task'] ? $this->env['task'] . '.' : '') . $command;
}
if ($disabled_actions === null) {
$disabled_actions = (array) $this->config->get('disabled_actions');
}
// remove buttons for disabled actions
if (in_array($element, $disabled_actions)) {
return '';
}
if (!$attrib['image']) {
$attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
}
if (!$attrib['id']) {
$attrib['id'] = sprintf('rcmbtn%d', $s_button_count++);
}
// get localized text for labels and titles
if ($attrib['title']) {
$attrib['title'] = html::quote($this->app->gettext($attrib['title'], $attrib['domain']));
}
if ($attrib['label']) {
$attrib['label'] = html::quote($this->app->gettext($attrib['label'], $attrib['domain']));
}
if ($attrib['alt']) {
$attrib['alt'] = html::quote($this->app->gettext($attrib['alt'], $attrib['domain']));
}
// set accessibility attributes
if (!$attrib['role']) {
$attrib['role'] = 'button';
}
if (!empty($attrib['class']) && !empty($attrib['classact']) || !empty($attrib['imagepas']) && !empty($attrib['imageact'])) {
if (array_key_exists('tabindex', $attrib))
$attrib['data-tabindex'] = $attrib['tabindex'];
$attrib['tabindex'] = '-1'; // disable button by default
$attrib['aria-disabled'] = 'true';
}
// set title to alt attribute for IE browsers
if ($this->browser->ie && !$attrib['title'] && $attrib['alt']) {
$attrib['title'] = $attrib['alt'];
}
// add empty alt attribute for XHTML compatibility
if (!isset($attrib['alt'])) {
$attrib['alt'] = '';
}
// register button in the system
if ($attrib['command']) {
$this->add_script(sprintf(
"%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
self::JS_OBJECT_NAME,
$command,
$attrib['id'],
$attrib['type'],
$attrib['imageact'] ? $this->abs_url($attrib['imageact']) : $attrib['classact'],
$attrib['imagesel'] ? $this->abs_url($attrib['imagesel']) : $attrib['classsel'],
$attrib['imageover'] ? $this->abs_url($attrib['imageover']) : ''
));
// make valid href to specific buttons
if (in_array($attrib['command'], rcmail::$main_tasks)) {
$attrib['href'] = $this->app->url(array('task' => $attrib['command']));
$attrib['onclick'] = sprintf("return %s.command('switch-task','%s',this,event)", self::JS_OBJECT_NAME, $attrib['command']);
}
else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) {
$attrib['href'] = $this->app->url(array('action' => $attrib['command'], 'task' => $attrib['task']));
}
else if (in_array($attrib['command'], $a_static_commands)) {
$attrib['href'] = $this->app->url(array('action' => $attrib['command']));
}
else if (($attrib['command'] == 'permaurl' || $attrib['command'] == 'extwin') && !empty($this->env['permaurl'])) {
$attrib['href'] = $this->env['permaurl'];
}
}
// overwrite attributes
if (!$attrib['href']) {
$attrib['href'] = '#';
}
if ($attrib['task']) {
if ($attrib['classact'])
$attrib['class'] = $attrib['classact'];
}
else if ($command && !$attrib['onclick']) {
$attrib['onclick'] = sprintf(
"return %s.command('%s','%s',this,event)",
self::JS_OBJECT_NAME,
$command,
$attrib['prop']
);
}
$out = '';
// generate image tag
if ($attrib['type'] == 'image') {
$attrib_str = html::attrib_string(
$attrib,
array(
'style', 'class', 'id', 'width', 'height', 'border', 'hspace',
'vspace', 'align', 'alt', 'tabindex', 'title'
)
);
$btn_content = sprintf('<img src="%s"%s />', $this->abs_url($attrib['image']), $attrib_str);
if ($attrib['label']) {
$btn_content .= ' '.$attrib['label'];
}
$link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'target');
}
else if ($attrib['type'] == 'link') {
$btn_content = isset($attrib['content']) ? $attrib['content'] : ($attrib['label'] ? $attrib['label'] : $attrib['command']);
$link_attrib = array_merge(html::$common_attrib, array('href', 'onclick', 'tabindex', 'target'));
if ($attrib['innerclass'])
$btn_content = html::span($attrib['innerclass'], $btn_content);
}
else if ($attrib['type'] == 'input') {
$attrib['type'] = 'button';
if ($attrib['label']) {
$attrib['value'] = $attrib['label'];
}
if ($attrib['command']) {
$attrib['disabled'] = 'disabled';
}
$out = html::tag('input', $attrib, null, array('type', 'value', 'onclick', 'id', 'class', 'style', 'tabindex', 'disabled'));
}
// generate html code for button
if ($btn_content) {
$attrib_str = html::attrib_string($attrib, $link_attrib);
$out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
}
if ($attrib['wrapper']) {
$out = html::tag($attrib['wrapper'], null, $out);
}
if ($menuitem) {
$class = $attrib['menuitem-class'] ? ' class="' . $attrib['menuitem-class'] . '"' : '';
$out = '<li role="menuitem"' . $class . '>' . $out . '</li>';
}
return $out;
}
/**
* Link an external script file
*
* @param string File URL
* @param string Target position [head|foot]
*/
public function include_script($file, $position='head')
{
if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
$file = $this->file_mod($this->scripts_path . $file);
}
if (!is_array($this->script_files[$position])) {
$this->script_files[$position] = array();
}
if (!in_array($file, $this->script_files[$position])) {
$this->script_files[$position][] = $file;
}
}
/**
* Add inline javascript code
*
* @param string JS code snippet
* @param string Target position [head|head_top|foot]
*/
public function add_script($script, $position='head')
{
if (!isset($this->scripts[$position])) {
$this->scripts[$position] = "\n" . rtrim($script);
}
else {
$this->scripts[$position] .= "\n" . rtrim($script);
}
}
/**
* Link an external css file
*
* @param string File URL
*/
public function include_css($file)
{
$this->css_files[] = $file;
}
/**
* Add HTML code to the page header
*
* @param string $str HTML code
*/
public function add_header($str)
{
$this->header .= "\n" . $str;
}
/**
* Add HTML code to the page footer
* To be added right befor </body>
*
* @param string $str HTML code
*/
public function add_footer($str)
{
$this->footer .= "\n" . $str;
}
/**
* Process template and write to stdOut
*
* @param string HTML template
* @param string Base for absolute paths
*/
public function _write($templ = '', $base_path = '')
{
$output = trim($templ);
if (empty($output)) {
$output = html::doctype('html5') . "\n" . $this->default_template;
$is_empty = true;
}
// set default page title
if (empty($this->pagetitle)) {
$this->pagetitle = 'Roundcube Mail';
}
// declare page language
if (!empty($_SESSION['language'])) {
$lang = substr($_SESSION['language'], 0, 2);
$output = preg_replace('/<html/', '<html lang="' . html::quote($lang) . '"', $output, 1);
if (!headers_sent()) {
header('Content-Language: ' . $lang);
}
}
// replace specialchars in content
$page_title = html::quote($this->pagetitle);
$page_header = '';
$page_footer = '';
// include meta tag with charset
if (!empty($this->charset)) {
if (!headers_sent()) {
header('Content-Type: text/html; charset=' . $this->charset);
}
$page_header = '<meta http-equiv="content-type"';
$page_header.= ' content="text/html; charset=';
$page_header.= $this->charset . '" />'."\n";
}
// definition of the code to be placed in the document header and footer
if (is_array($this->script_files['head'])) {
foreach ($this->script_files['head'] as $file) {
$page_header .= html::script($file);
}
}
$head_script = $this->scripts['head_top'] . $this->scripts['head'];
if (!empty($head_script)) {
$page_header .= html::script(array(), $head_script);
}
if (!empty($this->header)) {
$page_header .= $this->header;
}
// put docready commands into page footer
if (!empty($this->scripts['docready'])) {
$this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
}
if (is_array($this->script_files['foot'])) {
foreach ($this->script_files['foot'] as $file) {
$page_footer .= html::script($file);
}
}
if (!empty($this->footer)) {
$page_footer .= $this->footer . "\n";
}
if (!empty($this->scripts['foot'])) {
$page_footer .= html::script(array(), $this->scripts['foot']);
}
// find page header
if ($hpos = stripos($output, '</head>')) {
$page_header .= "\n";
}
else {
if (!is_numeric($hpos)) {
$hpos = stripos($output, '<body');
}
if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
while ($output[$hpos] != '>') {
$hpos++;
}
$hpos++;
}
$page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
}
// add page hader
if ($hpos) {
$output = substr_replace($output, $page_header, $hpos, 0);
}
else {
$output = $page_header . $output;
}
// add page footer
if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
$output = substr_replace($output, $page_footer."\n", $fpos, 0);
}
else {
$output .= "\n".$page_footer;
}
// add css files in head, before scripts, for speed up with parallel downloads
if (!empty($this->css_files) && !$is_empty
&& (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
) {
$css = '';
foreach ($this->css_files as $file) {
$css .= html::tag('link', array('rel' => 'stylesheet',
'type' => 'text/css', 'href' => $file, 'nl' => true));
}
$output = substr_replace($output, $css, $pos, 0);
}
$output = $this->parse_with_globals($this->fix_paths($output));
if ($this->assets_path) {
$output = $this->fix_assets_paths($output);
}
// trigger hook with final HTML content to be sent
$hook = $this->app->plugins->exec_hook("send_page", array('content' => $output));
if (!$hook['abort']) {
if ($this->charset != RCUBE_CHARSET) {
echo rcube_charset::convert($hook['content'], RCUBE_CHARSET, $this->charset);
}
else {
echo $hook['content'];
}
}
}
/**
* Returns iframe object, registers some related env variables
*
* @param array $attrib HTML attributes
* @param boolean $is_contentframe Register this iframe as the 'contentframe' gui object
* @return string IFRAME element
*/
public function frame($attrib, $is_contentframe = false)
{
static $idcount = 0;
if (!$attrib['id']) {
$attrib['id'] = 'rcmframe' . ++$idcount;
}
$attrib['name'] = $attrib['id'];
$attrib['src'] = $attrib['src'] ? $this->abs_url($attrib['src'], true) : 'program/resources/blank.gif';
// register as 'contentframe' object
if ($is_contentframe || $attrib['contentframe']) {
$this->set_env('contentframe', $attrib['contentframe'] ? $attrib['contentframe'] : $attrib['name']);
$this->set_env('blankpage', $this->asset_url($attrib['src']));
}
return html::iframe($attrib);
}
/* ************* common functions delivering gui objects ************** */
/**
* Create a form tag with the necessary hidden fields
*
* @param array Named tag parameters
* @return string HTML code for the form
*/
public function form_tag($attrib, $content = null)
{
if ($this->framed || $this->env['framed']) {
$hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
$hidden = $hiddenfield->show();
}
if ($this->env['extwin']) {
$hiddenfield = new html_hiddenfield(array('name' => '_extwin', 'value' => '1'));
$hidden = $hiddenfield->show();
}
if (!$content)
$attrib['noclose'] = true;
return html::tag('form',
$attrib + array('action' => $this->app->comm_path, 'method' => "get"),
$hidden . $content,
array('id','class','style','name','method','action','enctype','onsubmit'));
}
/**
* Build a form tag with a unique request token
*
* @param array Named tag parameters including 'action' and 'task' values which will be put into hidden fields
* @param string Form content
* @return string HTML code for the form
*/
public function request_form($attrib, $content = '')
{
$hidden = new html_hiddenfield();
if ($attrib['task']) {
$hidden->add(array('name' => '_task', 'value' => $attrib['task']));
}
if ($attrib['action']) {
$hidden->add(array('name' => '_action', 'value' => $attrib['action']));
}
unset($attrib['task'], $attrib['request']);
$attrib['action'] = './';
// we already have a <form> tag
if ($attrib['form']) {
if ($this->framed || $this->env['framed'])
$hidden->add(array('name' => '_framed', 'value' => '1'));
return $hidden->show() . $content;
}
else
return $this->form_tag($attrib, $hidden->show() . $content);
}
/**
* GUI object 'username'
* Showing IMAP username of the current session
*
* @param array Named tag parameters (currently not used)
* @return string HTML code for the gui object
*/
public function current_username($attrib)
{
static $username;
// alread fetched
if (!empty($username)) {
return $username;
}
// Current username is an e-mail address
if (strpos($_SESSION['username'], '@')) {
$username = $_SESSION['username'];
}
// get e-mail address from default identity
else if ($sql_arr = $this->app->user->get_identity()) {
$username = $sql_arr['email'];
}
else {
$username = $this->app->user->get_username();
}
return rcube_utils::idn_to_utf8($username);
}
/**
* GUI object 'loginform'
* Returns code for the webmail login form
*
* @param array Named parameters
* @return string HTML code for the gui object
*/
protected function login_form($attrib)
{
$default_host = $this->config->get('default_host');
$autocomplete = (int) $this->config->get('login_autocomplete');
$_SESSION['temp'] = true;
// save original url
$url = rcube_utils::get_input_value('_url', rcube_utils::INPUT_POST);
if (empty($url) && !preg_match('/_(task|action)=logout/', $_SERVER['QUERY_STRING']))
$url = $_SERVER['QUERY_STRING'];
// Disable autocapitalization on iPad/iPhone (#1488609)
$attrib['autocapitalize'] = 'off';
// set atocomplete attribute
$user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
$host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
$pass_attrib = $autocomplete > 1 ? array() : array('autocomplete' => 'off');
$input_task = new html_hiddenfield(array('name' => '_task', 'value' => 'login'));
$input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
$input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_'));
$input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url));
$input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'required' => 'required')
+ $attrib + $user_attrib);
$input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'required' => 'required')
+ $attrib + $pass_attrib);
$input_host = null;
if (is_array($default_host) && count($default_host) > 1) {
$input_host = new html_select(array('name' => '_host', 'id' => 'rcmloginhost'));
foreach ($default_host as $key => $value) {
if (!is_array($value)) {
$input_host->add($value, (is_numeric($key) ? $value : $key));
}
else {
$input_host = null;
break;
}
}
}
else if (is_array($default_host) && ($host = key($default_host)) !== null) {
$hide_host = true;
$input_host = new html_hiddenfield(array(
'name' => '_host', 'id' => 'rcmloginhost', 'value' => is_numeric($host) ? $default_host[$host] : $host) + $attrib);
}
else if (empty($default_host)) {
$input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost')
+ $attrib + $host_attrib);
}
$form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
$this->add_gui_object('loginform', $form_name);
// create HTML table with two cols
$table = new html_table(array('cols' => 2));
$table->add('title', html::label('rcmloginuser', html::quote($this->app->gettext('username'))));
$table->add('input', $input_user->show(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC)));
$table->add('title', html::label('rcmloginpwd', html::quote($this->app->gettext('password'))));
$table->add('input', $input_pass->show());
// add host selection row
if (is_object($input_host) && !$hide_host) {
$table->add('title', html::label('rcmloginhost', html::quote($this->app->gettext('server'))));
$table->add('input', $input_host->show(rcube_utils::get_input_value('_host', rcube_utils::INPUT_GPC)));
}
$out = $input_task->show();
$out .= $input_action->show();
$out .= $input_tzone->show();
$out .= $input_url->show();
$out .= $table->show();
if ($hide_host) {
$out .= $input_host->show();
}
if (rcube_utils::get_boolean($attrib['submit'])) {
$submit = new html_inputfield(array('type' => 'submit', 'id' => 'rcmloginsubmit',
'class' => 'button mainaction', 'value' => $this->app->gettext('login')));
$out .= html::p('formbuttons', $submit->show());
}
// surround html output with a form tag
if (empty($attrib['form'])) {
$out = $this->form_tag(array('name' => $form_name, 'method' => 'post'), $out);
}
// include script for timezone detection
$this->include_script('jstz.min.js');
return $out;
}
/**
* GUI object 'preloader'
* Loads javascript code for images preloading
*
* @param array Named parameters
* @return void
*/
protected function preloader($attrib)
{
$images = preg_split('/[\s\t\n,]+/', $attrib['images'], -1, PREG_SPLIT_NO_EMPTY);
$images = array_map(array($this, 'abs_url'), $images);
$images = array_map(array($this, 'asset_url'), $images);
if (empty($images) || $_REQUEST['_task'] == 'logout') {
return;
}
$this->add_script('var images = ' . self::json_serialize($images) .';
for (var i=0; i<images.length; i++) {
img = new Image();
img.src = images[i];
}', 'docready');
}
/**
* GUI object 'searchform'
* Returns code for search function
*
* @param array Named parameters
* @return string HTML code for the gui object
*/
protected function search_form($attrib)
{
// add some labels to client
$this->add_label('searching');
$attrib['name'] = '_q';
if (empty($attrib['id'])) {
$attrib['id'] = 'rcmqsearchbox';
}
if ($attrib['type'] == 'search' && !$this->browser->khtml) {
unset($attrib['type'], $attrib['results']);
}
$input_q = new html_inputfield($attrib);
$out = $input_q->show();
$this->add_gui_object('qsearchbox', $attrib['id']);
// add form tag around text field
if (empty($attrib['form'])) {
$out = $this->form_tag(array(
'name' => "rcmqsearchform",
'onsubmit' => self::JS_OBJECT_NAME . ".command('search'); return false",
'style' => "display:inline"),
$out);
}
return $out;
}
/**
* Builder for GUI object 'message'
*
* @param array Named tag parameters
* @return string HTML code for the gui object
*/
protected function message_container($attrib)
{
if (isset($attrib['id']) === false) {
$attrib['id'] = 'rcmMessageContainer';
}
$this->add_gui_object('message', $attrib['id']);
return html::div($attrib, '');
}
/**
* GUI object 'charsetselector'
*
* @param array Named parameters for the select tag
* @return string HTML code for the gui object
*/
public function charset_selector($attrib)
{
// pass the following attributes to the form class
$field_attrib = array('name' => '_charset');
foreach ($attrib as $attr => $value) {
if (in_array($attr, array('id', 'name', 'class', 'style', 'size', 'tabindex'))) {
$field_attrib[$attr] = $value;
}
}
$charsets = array(
'UTF-8' => 'UTF-8 ('.$this->app->gettext('unicode').')',
'US-ASCII' => 'ASCII ('.$this->app->gettext('english').')',
'ISO-8859-1' => 'ISO-8859-1 ('.$this->app->gettext('westerneuropean').')',
'ISO-8859-2' => 'ISO-8859-2 ('.$this->app->gettext('easterneuropean').')',
'ISO-8859-4' => 'ISO-8859-4 ('.$this->app->gettext('baltic').')',
'ISO-8859-5' => 'ISO-8859-5 ('.$this->app->gettext('cyrillic').')',
'ISO-8859-6' => 'ISO-8859-6 ('.$this->app->gettext('arabic').')',
'ISO-8859-7' => 'ISO-8859-7 ('.$this->app->gettext('greek').')',
'ISO-8859-8' => 'ISO-8859-8 ('.$this->app->gettext('hebrew').')',
'ISO-8859-9' => 'ISO-8859-9 ('.$this->app->gettext('turkish').')',
'ISO-8859-10' => 'ISO-8859-10 ('.$this->app->gettext('nordic').')',
'ISO-8859-11' => 'ISO-8859-11 ('.$this->app->gettext('thai').')',
'ISO-8859-13' => 'ISO-8859-13 ('.$this->app->gettext('baltic').')',
'ISO-8859-14' => 'ISO-8859-14 ('.$this->app->gettext('celtic').')',
'ISO-8859-15' => 'ISO-8859-15 ('.$this->app->gettext('westerneuropean').')',
'ISO-8859-16' => 'ISO-8859-16 ('.$this->app->gettext('southeasterneuropean').')',
'WINDOWS-1250' => 'Windows-1250 ('.$this->app->gettext('easterneuropean').')',
'WINDOWS-1251' => 'Windows-1251 ('.$this->app->gettext('cyrillic').')',
'WINDOWS-1252' => 'Windows-1252 ('.$this->app->gettext('westerneuropean').')',
'WINDOWS-1253' => 'Windows-1253 ('.$this->app->gettext('greek').')',
'WINDOWS-1254' => 'Windows-1254 ('.$this->app->gettext('turkish').')',
'WINDOWS-1255' => 'Windows-1255 ('.$this->app->gettext('hebrew').')',
'WINDOWS-1256' => 'Windows-1256 ('.$this->app->gettext('arabic').')',
'WINDOWS-1257' => 'Windows-1257 ('.$this->app->gettext('baltic').')',
'WINDOWS-1258' => 'Windows-1258 ('.$this->app->gettext('vietnamese').')',
'ISO-2022-JP' => 'ISO-2022-JP ('.$this->app->gettext('japanese').')',
'ISO-2022-KR' => 'ISO-2022-KR ('.$this->app->gettext('korean').')',
'ISO-2022-CN' => 'ISO-2022-CN ('.$this->app->gettext('chinese').')',
'EUC-JP' => 'EUC-JP ('.$this->app->gettext('japanese').')',
'EUC-KR' => 'EUC-KR ('.$this->app->gettext('korean').')',
'EUC-CN' => 'EUC-CN ('.$this->app->gettext('chinese').')',
'BIG5' => 'BIG5 ('.$this->app->gettext('chinese').')',
'GB2312' => 'GB2312 ('.$this->app->gettext('chinese').')',
);
if (!empty($_POST['_charset'])) {
$set = $_POST['_charset'];
}
else if (!empty($attrib['selected'])) {
$set = $attrib['selected'];
}
else {
$set = $this->get_charset();
}
$set = strtoupper($set);
if (!isset($charsets[$set])) {
$charsets[$set] = $set;
}
$select = new html_select($field_attrib);
$select->add(array_values($charsets), array_keys($charsets));
return $select->show($set);
}
/**
* Include content from config/about.<LANG>.html if available
*/
protected function about_content($attrib)
{
$content = '';
$filenames = array(
'about.' . $_SESSION['language'] . '.html',
'about.' . substr($_SESSION['language'], 0, 2) . '.html',
'about.html',
);
foreach ($filenames as $file) {
$fn = RCUBE_CONFIG_DIR . $file;
if (is_readable($fn)) {
$content = file_get_contents($fn);
$content = $this->parse_conditions($content);
$content = $this->parse_xml($content);
break;
}
}
return $content;
}
}
diff --git a/skins/classic/common.css b/skins/classic/common.css
index e97c30d6c..c163240e4 100644
--- a/skins/classic/common.css
+++ b/skins/classic/common.css
@@ -1,1529 +1,1539 @@
/***** Roundcube|Mail basic styles *****/
body
{
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
margin: 8px;
background-color: #F6F6F6;
color: #000;
font-size: 12px;
}
body.iframe
{
margin: 20px 0 0 0;
background-color: #FFF;
}
body.extwin
{
margin: 10px;
}
select, input, textarea, button
{
font-size: inherit;
font-family: inherit;
}
html.mozilla select {
padding: 2px 1px;
}
th
{
font-weight: normal;
}
h3
{
font-size: 18px;
}
a, a:active, a:visited
{
color: #000;
outline: none;
}
a.button, a.button:visited, a.tab, a.tab:visited, a.axislist
{
color: #000;
text-decoration: none;
}
a.tab
{
width: 80px;
display: block;
text-align: center;
}
a.disabled
{
color: #999;
text-decoration: none;
cursor: default;
}
hr
{
height: 1px;
background-color: #666;
border-style: none;
}
input[type="text"],
input[type="button"],
input[type="password"],
textarea
{
border: 1px solid #666;
color: #333;
background-color: #FFF;
}
input, textarea
{
color: black;
padding: 1px 3px;
}
input.placeholder,
textarea.placeholder,
input:-moz-placeholder,
textarea:-moz-placeholder
{
color: #aaa;
}
input.button
{
height: 20px;
color: #333333;
font-size: 12px;
padding-left: 8px;
padding-right: 8px;
background: url(images/buttons/bg.gif) repeat-x #f0f0f0;
border: 1px solid #a4a4a4;
}
input.button:hover
{
color: black;
}
input.button[disabled],
input.button[disabled]:hover
{
color: #aaa;
border-color: #ccc;
}
input.mainaction
{
font-weight: bold;
border: 1px solid #999;
}
img
{
border: 0;
}
.alttext
{
font-size: 11px;
}
.hint
{
color: #666;
font-size: 11px;
}
.formlinks a,
.formlinks a:visited
{
color: #CC0000;
font-size: 11px;
text-decoration: none;
}
.formlinks a.disabled,
.formlinks a.disabled:visited
{
color: #999999;
}
.voice
{
display: none;
}
/* fixes vertical alignment of checkboxes and labels */
label input,
label span
{
vertical-align: middle;
}
/** common user interface objects */
#mainscreen
{
position: absolute;
top: 85px;
right: 20px;
bottom: 20px;
left: 20px;
}
.extwin #mainscreen
{
top: 43px;
}
body > #logo
{
margin-left: 12px;
cursor: pointer;
}
#taskbar
{
position: absolute;
top: 0px;
right: 0px;
height: 24px;
left: 250px;
background: url(images/taskbar.png) top right no-repeat;
padding: 10px 6px 5px 0px;
text-align: right;
white-space: nowrap;
z-index: 2;
}
#taskbar a
{
font-size: 11px;
color: #666666;
text-decoration: none;
padding: 6px 12px 6px 26px;
background: url(images/taskicons.gif) no-repeat;
}
#taskbar a:hover
{
color: #333333;
}
#taskbar a.button-mail
{
background-position: 0 0;
}
#taskbar a.button-addressbook
{
background-position: 0 -25px;
}
#taskbar a.button-settings
{
background-position: 0 -50px;
}
#taskbar a.button-logout
{
background-position: 0 -75px;
}
body > #message
{
position: absolute;
display: none;
top: -1px;
margin-left: -225px;
left: 50%;
z-index: 5000;
opacity: 0.85;
}
body > #message div
{
width: 400px;
margin: 0px;
min-height: 22px;
padding: 8px 10px 8px 46px;
}
body > #message div.notice,
body > #messagebody .part-notice,
body > #mainscreen #messagebody .part-notice,
#message-objects div.notice
{
background: url(images/display/icons.png) 6px 3px no-repeat;
background-color: #F7FDCB;
border: 1px solid #C2D071;
}
body > #message div.error,
body > #message div.warning,
#message-objects div.warning,
#message-objects div.error
{
background: url(images/display/icons.png) 6px -97px no-repeat;
background-color: #EF9398;
border: 1px solid #DC5757;
}
body > #message div.confirmation,
#message-objects div.confirmation
{
background: url(images/display/icons.png) 6px -47px no-repeat;
background-color: #A6EF7B;
border: 1px solid #76C83F;
}
body > #message div.loading,
body > #message div.uploading,
#message-objects div.loading
{
background: url(images/display/loading.gif) 6px 3px no-repeat;
background-color: #EBEBEB;
border: 1px solid #CCCCCC;
}
body > #message div.voice
{
position: absolute;
top: -1000px;
clip: rect(0 0 0 0);
}
body > #message a
{
cursor: pointer;
text-decoration: underline;
}
body.extwin #closelink
{
position: absolute;
top: 5px;
right: 20px;
text-align: right;
z-index:100;
}
.box
{
border: 1px solid #999;
}
.boxtitle
{
height: 12px !important;
padding: 2px 10px 5px 5px;
border-bottom: 1px solid #999;
color: #333;
font-size: 11px;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
white-space: nowrap;
background: url(images/listheader.gif) top left repeat-x #CCC;
}
.boxtitle .rightalign
{
float: right;
}
body.iframe .boxtitle
{
position: fixed;
top: 0;
left: 0;
width: 100%;
}
.boxcontent
{
padding: 15px 10px 10px 10px;
background-color: #F2F2F2;
}
+.boxcontent .boxwarning
+{
+ margin: 0 0 10px;
+ display: block;
+ min-height: 22px;
+ background: url(images/display/icons.png) #EF9398 6px -95px no-repeat;
+ border: 1px solid #DC5757;
+ padding: 8px 10px 8px 46px;
+}
+
.boxcontent table td.title
{
color: #666;
padding-right: 10px;
}
.boxlistcontent
{
position: absolute;
top: 20px;
bottom: 22px;
left: 0;
right: 0;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
}
.boxsubject
{
position: absolute;
top: 0px;
left: 0px;
right: 0px;
overflow: hidden;
height: 22px;
border-bottom: 1px solid #999;
background: url(images/listheader.gif) top left repeat-x #CCC;
}
.boxfooter
{
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
overflow: hidden;
height: 22px;
border-top: 1px solid #999;
background: url(images/listheader.gif) top left repeat-x #CCC;
}
.boxfooter a.button,
.boxfooter a.buttonPas
{
display: block;
float: left;
width: 34px;
height: 22px;
padding: 0px;
margin: 0;
overflow: hidden;
background: url(images/icons/groupactions.png) 0 0 no-repeat transparent;
opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */
}
.boxfooter a.groupactions
{
background-position: 0 -26px;
}
.boxfooter a.delgroup {
background-position: 0 -49px;
}
.boxfooter a.buttonPas
{
opacity: 0.35;
}
.pagenav span
{
color: #444;
font-size: 11px;
text-shadow: white 1px 1px;
white-space: nowrap;
}
.pagenav a.button,
.pagenav a.buttonPas
{
display: block;
float: left;
width: 11px;
height: 11px;
padding: 0;
margin: 1px;
margin-top: 2px;
overflow: hidden;
background: url(images/pagenav.gif) 0 0 no-repeat transparent;
opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */
}
.pagenav a.buttonPas {
opacity: 0.35;
}
.pagenav a.firstpageSel {
background-position: 0 -11px;
}
.pagenav a.prevpage {
background-position: -11px 0;
}
.pagenav a.prevpageSel {
background-position: -11px -11px;
}
.pagenav a.nextpage {
background-position: -22px 0;
}
.pagenav a.nextpageSel {
background-position: -22px -11px;
}
.pagenav a.lastpage {
background-position: -33px 0;
}
.pagenav a.lastpageSel {
background-position: -33px -11px;
}
#rcmcountdisplay
{
float: left;
margin-right: 10px;
}
#countcontrols #pagejumper
{
margin: 0 5px;
float: right;
text-align: center;
padding: 0;
cursor: default;
font-size: 10px;
}
.splitter
{
user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
position: absolute;
background: url(images/dimple.png) center no-repeat;
}
.splitter-h
{
cursor: n-resize; cursor: row-resize;
background-position: center 2px;
}
.splitter-v
{
cursor: e-resize; cursor: col-resize;
background-position: 2px center;
}
.popupmenu
{
position: absolute;
top: 32px;
left: 90px;
width: auto;
max-height: 70%;
overflow: -moz-scrollbars-vertical;
overflow-y: auto;
display: none;
background-color: #fff;
background-color: rgba(255, 255, 255, 0.95);
border: 1px solid #999;
padding: 4px;
z-index: 240;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
box-shadow: 1px 1px 12px #999;
-moz-box-shadow: 1px 1px 12px #999;
-webkit-box-shadow: #999 1px 1px 12px;
}
.popupmenu ul
{
margin: -4px 0;
padding: 0;
list-style: none;
}
.popupmenu ul li
{
font-size: 11px;
white-space: nowrap;
min-width: 100px;
margin: 3px -4px;
}
.popupmenu li a,
.popupmenu li label
{
display: block;
color: #a0a0a0;
padding: 2px 16px 2px 10px;
text-decoration: none;
min-height: 14px;
background: transparent;
}
.popupmenu li label.comment
{
color: #999;
font-style: italic;
padding-top: 4px;
padding-bottom: 3px;
}
.popupmenu li a.active,
.popupmenu li a.active:active,
.popupmenu li a.active:visited
{
color: #333;
cursor: pointer;
}
.popupmenu li a.active:hover,
.popupmenu.selectable li a.selected:hover
{
color: #fff;
background-color: #c00;
}
.popupmenu li.block input
{
float: left;
}
.popupmenu.selectable li a.selected
{
background: url(images/messageicons.png) 2px -372px no-repeat;
}
.popupmenu.selectable li a
{
padding-left: 20px;
}
.darkbg
{
background-color: #F2F2F2 !important;
}
.dropbutton,
.dropbutton span
{
float: left;
height: 32px;
}
.dropbutton:hover
{
/* background: url(images/dbutton.png) 0 0 no-repeat transparent; */
}
.dropbutton span
{
width: 9px;
background: url(images/dbutton.png) -53px 0 no-repeat transparent;
}
.dropbutton span:hover
{
cursor: pointer;
background-position: -74px 0;
}
img.uploading
{
width: 16px;
height: 16px;
}
.popup label > input {
margin-left: 10px;
}
/***** common table settings ******/
table.records-table thead tr th,
table.records-table thead tr td
{
height: 20px;
padding: 0px 4px 0px 4px;
vertical-align: middle;
border-bottom: 1px solid #999999;
color: #333333;
background: url(images/listheader.gif) top left repeat-x #CCC;
font-size: 11px;
font-weight: bold;
text-align: left;
}
table.records-table tbody tr td
{
height: 16px;
padding: 2px 4px 2px 4px;
font-size: 11px;
white-space: nowrap;
border-bottom: 1px solid #EBEBEB;
overflow: hidden;
text-align: left;
outline: none;
}
table.records-table tr
{
background-color: #FFFFFF;
}
table.records-table tr.selected td
{
color: #FFFFFF;
background-color: #CC3333;
}
table.records-table tr.focused td
{
}
table.records-table tr.unfocused td
{
color: #FFFFFF;
background-color: #929292;
}
ul.treelist li
{
position: relative;
}
ul.treelist li div.treetoggle
{
position: absolute;
left: 8px;
top: 2px;
width: 14px;
height: 16px;
cursor: pointer;
}
ul.treelist ul li div.treetoggle
{
left: 25px;
}
ul.treelist ul ul li div.treetoggle
{
left: 42px;
}
ul.treelist li div.collapsed
{
background: url(images/icons/collapsed.png) bottom right no-repeat;
}
ul.treelist li div.expanded
{
background: url(images/icons/expanded.png) bottom right no-repeat;
}
ul.treelist,
ul.treelist li ul
{
list-style: none;
margin: 0;
padding: 0;
background-color: #FFFFFF;
}
ul.treelist li ul
{
border-top: 1px solid #EBEBEB;
}
ul.treelist li
{
display: block;
font-size: 11px;
border-bottom: 1px solid #EBEBEB;
white-space: nowrap;
overflow: hidden;
}
ul.treelist li a
{
cursor: default;
display: block;
padding-left: 25px;
padding-top: 2px;
padding-bottom: 2px;
height: 16px;
line-height: 16px;
text-decoration: none;
white-space: nowrap;
}
ul.treelist li ul li a
{
padding-left: 45px;
}
ul.treelist ul ul li a
{
padding-left: 65px;
}
ul.treelist li ul li:last-child
{
border-bottom: 0;
}
ul.treelist li.selected > a,
ul.treelist li.selected > div a
{
color: #FFF;
font-weight: bold;
background-color: #929292;
}
ul.treelist li.droptarget
{
background-color: #FFFFA6;
}
/***** folders list *****/
.folderlist li ul li:last-child
{
border-bottom: 0 none;
}
.folderlist li.inbox a
{
background-position: 5px -18px;
}
.folderlist li.drafts a
{
background-position: 5px -36px;
}
.folderlist li.sent a
{
background-position: 5px -53px;
}
.folderlist li.junk a
{
background-position: 5px -72px;
}
.folderlist li.trash a
{
background-position: 5px -180px;
}
.folderlist li.trash.empty a
{
background-position: 5px -90px;
}
.folderlist li a
{
cursor: default;
display: block;
position: relative;
padding-left: 25px;
padding-top: 2px;
padding-bottom: 2px;
text-decoration: none;
height: 15px;
background: url(images/icons/folders.png) 5px 1px no-repeat;
}
.folderlist li.virtual > a
{
color: #666;
}
.folderlist li.selected,
.folderlist li.droptarget li.selected
{
background-color: #929292;
}
.folderlist li.selected > a,
.folderlist li.droptarget li.selected a
{
color: #FFF;
font-weight: bold;
}
.folderlist li.droptarget
{
background-color: #FFFFA6;
}
/* styles for nested folders */
.folderlist ul {
list-style: none;
padding: 0;
margin: 0;
border-top: 1px solid #EBEBEB;
background-color: #FFF;
font-weight: normal;
}
.folderlist li.mailbox ul li a {
padding-left: 40px; /* 24 + 1 x 16 */
background-position: 20px 1px; /* 4 + 1 x 16 */
}
.folderlist li.mailbox ul li div.treetoggle {
left: 23px !important;
}
.folderlist li.mailbox ul ul li.mailbox a {
padding-left: 56px; /* 2x */
background-position: 36px 1px;
}
.folderlist li.mailbox ul ul li div.treetoggle {
left: 39px !important;
}
.folderlist li.mailbox ul ul ul li.mailbox a {
padding-left: 72px; /* 3x */
background-position: 52px 1px;
}
.folderlist li.mailbox ul ul ul li div.treetoggle {
left: 55px !important;
}
.folderlist li.mailbox ul ul ul ul li.mailbox a {
padding-left: 88px; /* 4x */
background-position: 68px 1px;
}
.folderlist li.mailbox ul ul ul ul li div.treetoggle {
left: 71px !important;
}
/* indent folders on levels > 4 */
.folderlist li.mailbox ul ul ul ul ul li {
padding-left: 16px;
}
.folderlist li.mailbox ul ul ul ul ul li div.treetoggle {
left: 87px !important;
}
.folderlist li.mailbox ul li.drafts a
{
background-position: 21px -36px;
}
.folderlist li.mailbox ul li.sent a
{
background-position: 21px -53px;
}
.folderlist li.mailbox ul li.junk a
{
background-position: 21px -72px;
}
.folderlist li.mailbox ul li.trash a
{
background-position: 21px -180px;
}
.folderlist li.mailbox ul li.trash.empty a
{
background-position: 21px -90px;
}
/***** mac-style quicksearch field *****/
div.searchbox,
#quicksearchbar
{
position: relative;
width: 190px;
height: 20px;
text-align: right;
background: url(images/searchfield.gif) top left no-repeat;
}
#quicksearchbar
{
position: absolute;
top: 55px;
right: 10px;
}
#searchreset,
div.searchbox a.searchreset
{
position: absolute;
top: 3px;
right: 12px;
text-decoration: none;
}
#searchmenulink,
div.searchbox a.searchmenu,
div.searchbox a.searchicon
{
position: absolute;
top: 3px;
right: 168px;
}
div.searchbox a.searchreset
{
display: block;
width: 14px;
height: 14px;
overflow: hidden;
white-space: nowrap;
text-indent: 50000px;
background: url(images/icons/reset.gif) top left no-repeat;
}
div.searchbox a.searchicon
{
display: inline-block;
width: 16px;
height: 16px;
overflow: hidden;
background: url(images/icons/glass.png) top left no-repeat;
}
#quicksearchbar img
{
vertical-align: middle;
}
#quicksearchbox,
div.searchbox > input
{
position: absolute;
top: 2px;
left: 24px;
width: 140px;
height: 15px;
font-size: 11px;
padding: 0px;
border: none;
outline: none;
}
.propform div.prop
{
margin-bottom: 0.5em;
}
.propform div.prop.block label
{
display: block;
margin-bottom: 2px;
}
.propform div.prop.block input,
.propform div.prop.block textarea
{
width: 97%;
}
.listsearchbox
{
border-bottom: solid 1px #ddd;
padding: 2px 4px 1px;
display: none;
background-color: #f2f2f2;
}
.listsearchbox a.iconbutton.reset
{
background: url(images/icons/reset.gif) no-repeat 0 0;
width: 13px;
height: 13px;
text-indent: 50000px;
position: absolute;
top: 3px;
left: 165px;
overflow: hidden;
}
/***** roundcube webmail pre-defined classes *****/
#rcmversion
{
position: absolute;
bottom: 10px;
right: 20px;
text-align: right;
white-space: nowrap;
font-size: 8pt;
color: #999;
}
#rcmdraglayer
{
min-width: 300px;
width: auto !important;
width: 300px;
border: 1px solid #999999;
background-color: #fff;
padding-left: 8px;
padding-right: 8px;
padding-top: 3px;
padding-bottom: 3px;
font-size: 11px;
white-space: nowrap;
opacity: 0.82;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
box-shadow: 1px 1px 12px #999;
-moz-box-shadow: 1px 1px 12px #999;
-webkit-box-shadow: #999 1px 1px 12px;
}
.draglayercopy:before
{
position: absolute;
bottom: -5px;
left: -6px;
content: " ";
width: 14px;
height: 14px;
background: url(images/messageactions.png) -2px -128px no-repeat;
}
a.rcmContactAddress
{
text-decoration: none;
}
a.rcmContactAddress:hover
{
text-decoration: underline;
}
#rcmKSearchpane
{
background-color: #F9F9F9;
border: 1px solid #CCCCCC;
}
#rcmKSearchpane ul
{
margin: 0px;
padding: 2px;
list-style-image: none;
list-style-type: none;
}
#rcmKSearchpane ul li
{
display: block;
height: 16px;
font-size: 11px;
padding-left: 6px;
padding-top: 2px;
padding-right: 6px;
white-space: nowrap;
cursor: pointer;
}
#rcmKSearchpane ul li.selected,
#pagejump-selector ul li.selected
{
color: #ffffff;
background-color: #CC3333;
}
#login-form
{
margin-left: auto;
margin-right: auto;
margin-top: 50px;
width: 400px;
border: 1px solid #999;
}
#login-form table td.title
{
text-align: right;
white-space: nowrap;
}
#login-form table
{
width: 1%;
margin: auto;
}
#login-form table td.input input
{
width: 200px;
}
#login-bottomline
{
width: 400px;
margin: 5em auto;
font-size: 85%;
text-align: center;
color: #666;
}
#login-noscriptwarning
{
margin: 2em auto 0 auto;
width: 400px;
color: #cf2734;
font-weight: bold;
}
.disabled,
a.disabled
{
color: #999;
}
font.bold
{
font-weight: bold;
}
.formbuttons
{
text-align: center;
}
/***** onclick menu list *****/
ul.toolbarmenu
{
margin: -4px 0 -4px 0;
padding: 0;
list-style: none;
}
ul.toolbarmenu li
{
font-size: 11px;
white-space: nowrap;
min-width: 130px;
margin: 2px -4px;
}
ul.toolbarmenu li a
{
display: block;
color: #a0a0a0;
padding: 1px 12px 3px 28px;
text-decoration: none;
min-height: 14px;
}
ul.toolbarmenu li a.active,
ul.toolbarmenu li a.active:active,
ul.toolbarmenu li a.active:visited
{
color: #333;
}
ul.toolbarmenu li input
{
vertical-align: middle;
}
ul.toolbarmenu li hr
{
color: #ccc;
width: 130px;
height: 1px;
margin: 2px 1px 2px 1px;
}
ul.toolbarmenu li img
{
float: left;
margin: 0 2px;
}
div.popupmenu ul li.separator_below,
ul.toolbarmenu li.separator_below
{
border-bottom: 1px solid #ccc;
margin-bottom: 2px;
padding-bottom: 2px;
}
div.popupmenu ul li.separator_above,
ul.toolbarmenu li.separator_above
{
border-top: 1px solid #ccc;
margin-top: 2px;
padding-top: 2px;
}
#searchmenu
{
width: 160px;
}
#searchmenu ul.toolbarmenu
{
margin: 0;
}
#searchmenu ul.toolbarmenu li
{
margin: 1px 4px 1px;
}
#searchmenu ul.toolbarmenu li label
{
padding: 2px 0;
color: black;
}
#searchmenu ul.toolbarmenu li label.comment
{
color: #999;
}
#pagejump-selector
{
max-height: 250px;
overflow-x: hidden;
}
#pagejump-selector ul li
{
min-width: 45px;
padding: 2px 5px;
cursor: default;
}
/*** folder selector ***/
#folder-selector li a
{
padding: 0;
}
#folder-selector li a span
{
background: url(images/icons/folders.png) no-repeat 6px 0;
display: block;
height: 15px;
min-height: 14px;
padding: 2px 4px 2px 28px;
overflow: hidden;
max-width: 120px;
text-overflow: ellipsis;
}
#folder-selector li a.virtual
{
color: #A0A0A0;
}
#folder-selector li a.active:hover span
{
color: white;
}
#folder-selector li a.inbox span
{
background-position: 6px -18px;
}
#folder-selector li a.drafts span
{
background-position: 6px -37px;
}
#folder-selector li a.sent span
{
background-position: 6px -54px;
}
#folder-selector li a.trash span
{
background-position: 6px -91px;
}
#folder-selector li a.junk span
{
background-position: 6px -73px;
}
/***** tabbed interface elements *****/
div.tabsbar,
#tabsbar
{
position: absolute;
top: 50px;
left: 220px;
right: 20px;
height: 22px;
border-bottom: 1px solid #999999;
white-space: nowrap;
}
div.tabsbar
{
top: 35px;
left: 12px;
right: 12px;
}
span.tablink,
span.tablink-selected
{
float: left;
height: 23px !important;
height: 22px;
overflow: hidden;
background: url(images/tabs-left.gif) top left no-repeat;
}
span.tablink
{
cursor: pointer;
}
span.tablink-selected
{
cursor: default;
background-position: 0px -23px;
}
span.tablink a,
span.tablink-selected a
{
display: inline-block;
padding: 5px 10px 0 5px;
margin-left: 5px;
height: 23px;
color: #555555;
max-width: 185px;
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
background: url(images/tabs-right.gif) top right no-repeat;
}
span.tablink-selected a
{
cursor: inherit;
color: #000000;
background-position: right -23px;
}
fieldset
{
margin-bottom: 1em;
border: 1px solid #999999;
padding: 4px 8px 9px 8px;
}
legend
{
color: #999999;
}
fieldset.tabbed
{
margin-top: 22px;
padding-top: 12px;
}
.quota_text {
text-align: center;
font-size: 10px;
color: #666;
border: 1px solid #999;
cursor: default;
}
.quota_bg { background-color: white; }
.quota_high { background: url(images/quota-colors.png) repeat-x 0 -28px #f90509; }
.quota_mid { background: url(images/quota-colors.png) repeat-x 0 -14px #e3e909; }
.quota_low { background: url(images/quota-colors.png) repeat-x 0 0px #05f905; }
.quota_text_high { color: white; }
.quota_text_mid { color: #666; }
.quota_text_low { color: #666; }
table.quota-info {
border-spacing: 0;
border-collapse: collapse;
table-layout: fixed;
margin: 2px;
}
table.quota-info td,
table.quota-info th {
border: 1px solid #999;
padding: 2px 3px;
text-align: center;
min-width: 80px;
color: #333;
font-size: 11px;
}
table.quota-info th {
font-weight: bold;
background-color: #ddd;
}
table.quota-info td.name {
text-align: left;
}
table.quota-info td.root {
font-style: italic;
}
/********** TinyMCE styles **********/
.mce-btn-small button
{
height: 22px;
}
.mce-btn-small i
{
line-height: 16px !important;
vertical-align: text-top !important;
}
.mce-combobox button
{
padding: 6px 8px !important;
}
.mce-tinymce
{
border-radius: 0 !important;
{
.mce-panel.mce-toolbar-grp
{
border: 0 !important;
}
#image-selector-form.droptarget {
background: url(images/filedrop.png) center bottom no-repeat;
}
#image-selector-form.droptarget.hover
{
background-color: #F0F0EE;
box-shadow: 0 0 5px 0 #999;
-moz-box-shadow: 0 0 5px 0 #999;
-o-box-shadow: 0 0 5px 0 #999;
}
diff --git a/skins/larry/styles.css b/skins/larry/styles.css
index 327fd37bb..acb97a75e 100644
--- a/skins/larry/styles.css
+++ b/skins/larry/styles.css
@@ -1,3112 +1,3121 @@
/**
* Roundcube webmail styles for skin "Larry"
*
* Copyright (c) 2012, The Roundcube Dev Team
* Screendesign by FLINT / Büro für Gestaltung, bueroflint.com
*
* The contents are subject to the Creative Commons Attribution-ShareAlike
* License. It is allowed to copy, distribute, transmit and to adapt the work
* by keeping credits to the original autors in the README file.
* See http://creativecommons.org/licenses/by-sa/3.0/ for details.
*/
body {
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
color: #333;
background: url(images/linen.jpg) repeat #d1d5d8;
margin: 0;
}
body.noscroll {
/* also avoids bounce effect in Chrome and Safari */
overflow: hidden;
}
a {
color: #0069a6;
}
a:visited {
color: #0186ba;
}
img {
border: 0;
}
.voice {
position: absolute;
border: 0;
clip: rect(0 0 0 0);
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
}
html.mozilla select {
padding: 2px 1px;
}
input,
textarea,
select,
button {
font-family: inherit;
font-size: inherit;
vertical-align: middle;
}
input[type="text"],
input[type="password"],
textarea {
margin: 0; /* Safari by default adds a margin */
padding: 4px;
border: 1px solid #b2b2b2;
border-radius: 4px;
box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
-webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
}
input[type="text"]:focus,
input[type="password"]:focus,
input.button:focus,
textarea:focus {
border-color: #4787b1;
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
outline: none;
}
input[type="text"]:required,
input[type="password"]:required {
border-color: #4787b1;
}
input.placeholder,
textarea.placeholder {
color: #aaa;
}
.bold {
font-weight: bold;
}
/* fixes vertical alignment of checkboxes and labels */
label input + span {
vertical-align: middle;
}
/*** buttons ***/
input.button {
display: inline-block;
margin: 0 2px;
padding: 2px 5px;
color: #525252;
text-shadow: 0px 1px 1px #fff;
border: 1px solid #c0c0c0;
border-radius: 4px;
background: #f7f7f7;
background: -moz-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f9f9), color-stop(100%,#e6e6e6));
background: -o-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -ms-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: linear-gradient(to bottom, #f9f9f9 0%, #e6e6e6 100%);
box-shadow: 0 1px 1px 0 rgba(140, 140, 140, 0.3);
-webkit-box-shadow: 0 1px 1px 0 rgba(140, 140, 140, 0.3);
text-decoration: none;
outline: none;
}
.formbuttons input.button {
color: #ddd;
font-size: 110%;
text-shadow: 0px 1px 1px #333;
padding: 4px 12px;
border-color: #465864;
border-radius: 5px;
background: #7a7b7d;
background: -moz-linear-gradient(top, #7b7b7b 0%, #606060 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#7b7b7b), color-stop(100%,#606060)); /* Chrome,Safari4+ */
background: -o-linear-gradient(top, #7b7b7b 0%, #606060 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #7b7b7b 0%, #606060 100%); /* IE10+ */
background: linear-gradient(to bottom, #7b7b7b 0%, #606060 100%); /* W3C */
box-shadow: 0 1px 1px 0 #ccc, inset 0 1px 0 0 #888;
-webkit-box-shadow: 0 1px 1px 0 #ccc, inset 0 1px 0 0 #888;
}
.formbuttons input.button:hover,
.formbuttons input.button:focus,
input.button.mainaction:hover,
input.button.mainaction:focus {
color: #f2f2f2;
border-color: #465864;
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #888;
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.6), inset 0 1px 0 0 #888;
}
.formbuttons input.button:active {
color: #fff;
background: -moz-linear-gradient(top, #5c5c5c 0%, #7b7b7b 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#5c5c5c), color-stop(100%,#7b7b7b));
background: -o-linear-gradient(top, #5c5c5c 0%, #7b7b7b 100%);
background: -ms-linear-gradient(top, #5c5c5c 0%, #7b7b7b 100%);
background: linear-gradient(to bottom, #5c5c5c 0%, #7b7b7b 100%);
}
input.button.mainaction {
color: #ededed;
text-shadow: 0px 1px 1px #333;
border-color: #1f262c;
background: #505050;
background: -moz-linear-gradient(top, #505050 0%, #2a2e31 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#505050), color-stop(100%,#2a2e31));
background: -o-linear-gradient(top, #505050 0%, #2a2e31 100%);
background: -ms-linear-gradient(top, #505050 0%, #2a2e31 100%);
background: linear-gradient(to bottom, #505050 0%, #2a2e31 100%);
box-shadow: inset 0 1px 0 0 #777;
-webkit-box-shadow: inset 0 1px 0 0 #777;
}
input.button.mainaction:active {
color: #fff;
background: #515151;
background: -moz-linear-gradient(top, #2a2e31 0%, #505050 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#2a2e31), color-stop(100%,#505050));
background: -o-linear-gradient(top, #2a2e31 0%, #505050 100%);
background: -ms-linear-gradient(top, #2a2e31 0%, #505050 100%);
background: linear-gradient(to bottom, #2a2e31 0%, #505050 100%);
}
input.button[disabled],
input.button[disabled]:hover,
input.button.mainaction[disabled] {
color: #aaa !important;
}
input.mainaction {
font-weight: bold;
}
/** link buttons **/
a.button,
.buttongroup {
display: inline-block;
margin: 0 2px;
padding: 2px 5px;
color: #525252;
text-shadow: 0px 1px 1px #fff;
border: 1px solid #c6c6c6;
border-radius: 4px;
background: #f7f7f7;
background: -moz-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f9f9), color-stop(100%,#e6e6e6));
background: -o-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -ms-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: linear-gradient(to bottom, #f9f9f9 0%, #e6e6e6 100%);
box-shadow: 0 1px 1px 0 rgba(140, 140, 140, 0.3);
-webkit-box-shadow: 0 1px 1px 0 rgba(140, 140, 140, 0.3);
text-decoration: none;
}
.buttongroup {
padding: 0;
white-space: nowrap;
}
a.button:focus,
input.button:focus {
border-color: #4fadd5;
box-shadow: 0 0 2px 1px rgba(71,135,177, 0.6);
-webkit-box-shadow: 0 0 2px 1px rgba(71,135,177, 0.6);
outline: none;
}
label.disabled,
a.button.disabled {
color: #999;
}
a.button.disabled,
input.button.disabled,
input.button[disabled],
a.button.disabled:hover,
input.button.disabled:hover,
input.button[disabled]:hover {
border-color: #c6c6c6;
box-shadow: 0 1px 1px 0 rgba(160, 160, 160, 0.4);
-webkit-box-shadow: 0 1px 1px 0 rgba(160, 160, 160, 0.4);
}
a.button.disabled span.inner {
opacity: 0.4;
}
.buttongroup a.button {
margin: 0;
border-width: 0 1px 0 0;
border-radius: 0;
background: none;
box-shadow: none;
-webkit-box-shadow: none;
}
.buttongroup a.button.first,
.buttongroup a.button:first-child {
border-radius: 4px 0 0 4px;
border-left: 0;
}
.buttongroup a.button.last,
.buttongroup a.button:last-child {
border-radius: 0 4px 4px 0;
border-right: 0;
}
a.button.pressed,
a.button:active,
input.button:active {
background: #e6e6e6;
background: -moz-linear-gradient(top, #e6e6e6 0%, #f9f9f9 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#e6e6e6), color-stop(100%,#f9f9f9));
background: -o-linear-gradient(top, #e6e6e6 0%, #f9f9f9 100%);
background: -ms-linear-gradient(top, #e6e6e6 0%, #f9f9f9 100%);
background: linear-gradient(to bottom, #e6e6e6 0%, #f9f9f9 100%);
}
.pagenav.dark a.button {
font-weight: bold;
border-color: #e6e6e6;
background: #d8d8d8;
background: -moz-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d8d8d8), color-stop(100%,#bababa));
background: -o-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: -ms-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: linear-gradient(to bottom, #d8d8d8 0%, #bababa 100%);
box-shadow: 0 1px 1px 0 #999;
-webkit-box-shadow: 0 1px 1px 0 #999;
}
.pagenav.dark a.button.pressed {
background: #bababa;
background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bababa), color-stop(100%,#d8d8d8));
background: -o-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: -ms-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: linear-gradient(to bottom, #bababa 0%, #d8d8d8 100%);
}
.buttongroup a.button.selected,
.buttongroup a.button.selected:hover {
background: #8a8a8a;
background: -moz-linear-gradient(top, #909090 0%, #858585 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#909090), color-stop(100%,#858585));
background: -o-linear-gradient(top, #909090 0%, #858585 100%);
background: -ms-linear-gradient(top, #909090 0%, #858585 100%);
background: linear-gradient(to bottom, #909090 0%, #858585 100%);
box-shadow: inset 0 1px 2px 0 #555;
-webkit-box-shadow: inset 0 1px 2px 0 #555;
border-right-color: #555;
border-left-color: #555;
}
.buttongroup a.button:focus,
.buttongroup a.button.selected:focus {
background: #f2f2f2;
background: -moz-linear-gradient(top, #49b3d2 0, #66bcd9 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0,#49b3d2), color-stop(100%,#66bcd9));
background: -o-linear-gradient(top, #49b3d2 0, #66bcd9 100%);
background: -ms-linear-gradient(top, #49b3d2 0, #66bcd9 100%);
background: linear-gradient(to bottom, #49b3d2 0, #66bcd9 100%);
}
.pagenav a.button {
padding: 1px 3px;
height: 16px;
vertical-align: middle;
margin-bottom: 1px;
}
.pagenav .buttongroup a.button,
.pagenav .buttongroup a.button:hover {
padding: 1px 5px;
margin-bottom: 0;
}
a.button span.icon,
.pagenav a.button span.inner {
display: inline-block;
width: 16px;
height: 13px;
text-indent: 1000px;
overflow: hidden;
background: url(images/buttons.png) -6px -211px no-repeat;
}
a.button.prevpage span.icon,
.pagenav a.prevpage span.inner {
background-position: -7px -226px;
}
a.button.nextpage span.icon,
.pagenav a.nextpage span.inner {
background-position: -28px -226px;
}
a.button.lastpage span.icon,
.pagenav a.lastpage span.inner {
background-position: -28px -211px;
}
a.button.pageup span.icon,
.pagenav a.pageup span.inner {
background-position: -7px -241px;
}
a.button.pagedown span.icon,
.pagenav a.pagedown span.inner {
background-position: -29px -241px;
}
a.button.reply span.icon,
.pagenav a.reply span.inner {
background-position: -7px -256px;
}
a.button.forward span.icon,
.pagenav a.forward span.inner {
background-position: -29px -256px;
}
a.button.replyall span.icon,
.pagenav a.replyall span.inner {
background-position: -7px -271px;
}
a.button.extwin span.icon,
.pagenav a.extwin span.inner {
background-position: -29px -271px;
}
a.button.changeformat.html span.icon,
.pagenav a.changeformat.html span.inner {
background-position: -7px -1859px;
}
a.button.changeformat.html.selected span.icon,
.pagenav a.changeformat.html.selected span.inner {
background-position: -29px -1859px;
}
a.button.changeformat.text span.icon,
.pagenav a.changeformat.text span.inner {
background-position: -7px -1874px;
}
a.button.changeformat.text.selected span.icon,
.pagenav a.changeformat.text.selected span.inner {
background-position: -29px -1874px;
}
a.button.add span.icon {
background-position: -7px -2009px;
}
a.button.delete span.icon {
background-position: -29px -2009px;
}
.pagenav .countdisplay {
display: inline-block;
padding: 3px 1em 0 1em;
text-shadow: 0px 1px 1px #fff;
min-width: 16em;
}
.pagenavbuttons {
position: relative;
top: -2px;
}
.pagenav .pagejumper {
text-align: center;
background: #f8f8f8;
padding: 3px 0;
background: linear-gradient(to bottom, #dddddd 0%, #f8f8f8 100%);
cursor: default;
}
a.iconbutton {
display: inline-block;
width: 20px;
height: 18px;
text-decoration: none;
text-indent: -5000px;
background: url(images/buttons.png) -1000px 0 no-repeat;
}
a.iconbutton.disabled {
opacity: 0.4;
cursor: default;
}
a.iconbutton.searchicon,
a.iconbutton.searchoptions {
width: 24px;
background-position: -2px -317px;
}
a.iconbutton.searchicon {
width: 15px;
}
a.iconbutton.reset {
width: 24px;
background-position: -25px -317px;
}
a.iconbutton.remove,
a.iconbutton.cancel {
background-position: -7px -378px;
}
a.iconbutton.delete {
background-position: -7px -338px;
}
a.iconbutton.add {
background-position: -7px -358px;
}
a.iconbutton.remove {
background-position: -7px -379px;
}
a.iconbutton.cancel {
background-position: -7px -398px;
}
a.iconbutton.edit {
background-position: -7px -418px;
}
a.iconbutton.upload {
background-position: -6px -438px;
}
a.iconlink {
display: inline-block;
color: #888;
text-decoration: none;
white-space: nowrap;
padding: 2px 8px 2px 20px;
background: url(images/buttons.png) -1000px 0 no-repeat;
}
a.iconlink:hover {
text-decoration: underline;
}
a.iconlink.delete {
background-position: -7px -337px;
}
a.iconlink.add {
background-position: -7px -357px;
}
a.iconlink.remove {
background-position: -7px -378px;
}
a.iconlink.cancel {
background-position: -7px -397px;
}
a.iconlink.edit {
background-position: -7px -417px;
}
a.iconlink.upload {
background-position: -6px -437px;
}
/*** message bar ***/
#message div.loading,
#message div.uploading,
#message div.warning,
#message div.error,
#message div.notice,
#message div.confirmation,
#message-objects div.notice {
color: #555;
font-weight: bold;
padding: 6px 30px 6px 25px;
display: inline-block;
white-space: nowrap;
background: url(images/messages.png) 0 5px no-repeat;
cursor: default;
}
#message div.warning {
color: #960;
background-position: 0 -86px;
}
#message div.error {
color: #cf2734;
background-position: 0 -55px;
}
#message div.confirmation {
color: #093;
background-position: 0 -25px;
}
#message div.loading {
background: url(images/ajaxloader.gif) 2px 6px no-repeat;
}
#message div a,
#message div span {
padding-right: 0.5em;
text-decoration: none;
}
#message div a:hover {
text-decoration: underline;
cursor: pointer;
}
#message.statusbar {
display: none;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 27px;
padding-left: 8px;
border-top: 1px solid #ddd;
border-radius: 0 0 4px 4px;
background: #eaeaea;
background: -moz-linear-gradient(top, #eaeaea 0%, #c8c8c8 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eaeaea), color-stop(100%,#c8c8c8));
background: -o-linear-gradient(top, #eaeaea 0%, #c8c8c8 100%);
background: -ms-linear-gradient(top, #eaeaea 0%, #c8c8c8 100%);
background: linear-gradient(to bottom, #eaeaea 0%, #c8c8c8 100%);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#messagestack {
position: absolute;
bottom: 20px;
right: 12px;
z-index: 50000;
width: auto;
height: auto;
max-height: 85%;
overflow-y: auto;
padding: 2px;
}
#messagestack div {
display: block;
position: relative;
width: 280px;
height: auto;
min-height: 16px;
margin: 3px 2px 5px 2px;
padding: 8px 10px 7px 30px;
cursor: default;
font-size: 12px;
font-weight: bold;
border-radius: 4px;
border: 1px solid #444;
color: #ebebeb;
text-shadow: 0 1px 1px #000;
background: rgba(64,64,64,0.85);
background: -moz-linear-gradient(top, rgba(64,64,64,0.85) 0%, rgba(48,48,48,0.9) 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(64,64,64,0.85)), color-stop(100%,rgba(48,48,48,0.9)));
background: -webkit-linear-gradient(top, rgba(64,64,64,0.85) 0%, rgba(48,48,48,0.85) 100%);
background: -o-linear-gradient(top, rgba(64,64,64,0.85) 0%, rgba(48,48,48,0.85) 100%);
background: -ms-linear-gradient(top, rgba(64,64,64,0.85) 0%, rgba(48,48,48,0.85) 100%);
background: linear-gradient(to bottom, rgba(64,64,64,0.85) 0%, rgba(48,48,48,0.85) 100%);
box-shadow: 0 1px 4px 0 rgba(50,50,50,0.8), inset 0px 1px 0 0px #888;
-webkit-box-shadow: 0 1px 4px 0 rgba(50,50,50,0.8), inset 0px 1px 0 0px #888;
}
#messagestack div:after {
content: "";
position: absolute;
display: block;
top: 0;
left: 4px;
width: 20px;
height: 24px;
background: url(images/messages_dark.png) 0 7px no-repeat;
}
#messagestack div.error {
color: #ff615d;
}
#messagestack div.error:after {
background-position: 0 -55px;
}
#messagestack div.warning {
color: #f4bf0e;
}
#messagestack div.warning:after {
background-position: 0 -84px;
}
#messagestack div.confirmation {
color: #00e05a;
}
#messagestack div.confirmation:after {
background-position: 0 -25px;
}
#messagestack div.uploading,
#messagestack div.loading {
color: #ddd;
}
#messagestack div.uploading:after,
#messagestack div.loading:after {
top: 4px;
left: 6px;
background: url(images/ajaxloader_dark.gif) 0 4px no-repeat;
}
#messagestack div.voice {
position: absolute;
top: -1000px;
}
#messagestack div a {
color: #94c0da;
}
#messagestack div a:hover {
text-decoration: underline;
cursor: pointer;
}
.ui-dialog.error .ui-dialog-title,
.ui-dialog.warning .ui-dialog-title,
.ui-dialog.confirmation .ui-dialog-title {
padding-left: 25px;
background: url(images/messages.png) 0 5px no-repeat;
text-shadow: 0 1px 1px #fff;
}
.ui-dialog.warning .ui-dialog-title {
color: #960;
background-position: 0 -90px;
}
.ui-dialog.error .ui-dialog-title {
color: #cf2734;
background-position: 0 -60px;
}
.ui-dialog.confirmation .ui-dialog-title {
color: #093;
background-position: 0 -30px;
}
.ui-dialog.popupmessage .ui-dialog-titlebar {
padding: 8px 1em 4px 1em;
background: #e3e3e3;
background: -moz-linear-gradient(top, #e3e3e3 0%, #cfcfcf 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#e3e3e3), color-stop(100%,#cfcfcf));
background: -o-linear-gradient(top, #e3e3e3 0%, #cfcfcf 100%);
background: -ms-linear-gradient(top, #e3e3e3 0%, #cfcfcf 100%);
background: linear-gradient(to bottom, #e3e3e3 0%, #cfcfcf 100%);
}
.ui-dialog.popupmessage .ui-widget-content {
font-size: 12px;
background: #eee;
background: -moz-linear-gradient(top, #eee 0%, #dcdcdc 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eee), color-stop(100%,#dcdcdc));
background: -o-linear-gradient(top, #eee 0%, #dcdcdc 100%);
background: -ms-linear-gradient(top, #eee 0%, #dcdcdc 100%);
background: linear-gradient(to bottom, #eee 0%, #dcdcdc 100%);
}
/*** basic page layout ***/
#header {
overflow-x: hidden; /* Chrome bug #1488851 */
}
#topline {
height: 18px;
background: url(images/linen_header.jpg) repeat #666;
border-bottom: 1px solid #4f4f4f;
padding: 2px 0 2px 10px;
color: #aaa;
text-align: center;
}
#topnav {
position: relative;
height: 46px;
margin-bottom: 10px;
padding: 0 0 0 10px;
background: #111;
background: -moz-linear-gradient(top, #404040 0%, #060606 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#404040), color-stop(100%,#060606));
background: -o-linear-gradient(top, #404040 0%, #060606 100%);
background: -ms-linear-gradient(top, #404040 0%, #060606 100%);
background: linear-gradient(to bottom, #404040 0%, #060606 100%);
}
#topline a,
#topnav a {
color: #eee;
text-decoration: none;
}
#topline a:hover {
text-decoration: underline;
}
#toplogo {
padding-top: 2px;
cursor: pointer;
border: none;
}
.topleft {
float: left;
}
.topright {
float: right;
}
.closelink {
display: inline-block;
padding: 2px 10px 2px 20px;
}
#topline span.username {
padding-right: 1em;
}
#topline .topleft a {
display: inline-block;
padding: 2px 0.8em 0 0;
color: #aaa;
}
#topline a.button-logout {
display: inline-block;
padding: 2px 10px 2px 20px;
background: url(images/buttons.png) -6px -193px no-repeat;
color: #fff;
}
#taskbar .button-logout {
display: none;
}
#taskbar a.button-logout span.button-inner {
background-position: -2px -1791px;
}
#taskbar a.button-logout:hover span.button-inner {
background-position: -2px -1829px;
}
/*** minimal version of the page header ***/
.minimal #topline {
position: fixed;
top: -18px;
background: #444;
z-index: 5000;
width: 100%;
height: 22px;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.minimal #topline:hover {
top: 0px;
opacity: 0.94;
-webkit-transition: top 0.3s ease-in-out;
-moz-transition: top 0.3s ease-in-out;
-o-transition: top 0.3s ease-in-out;
transition: top 0.3s ease-in-out;
}
.extwin #topline,
.extwin #topline:hover {
position: static;
top: 0px;
height: 18px;
width: auto;
-moz-box-sizing: content-box;
box-sizing: content-box;
opacity: 0.999;
}
.minimal #topline a.button-logout {
display: none;
}
.minimal #topline span.username {
display: inline-block;
padding-top: 2px;
}
.minimal #topnav {
position: relative;
top: 4px;
height: 42px;
}
.minimal #taskbar a {
position: relative;
padding: 10px 10px 0 6px;
height: 32px;
}
.minimal #taskbar .button-logout {
display: inline-block;
}
.minimal #taskbar .button-inner {
top: -4px;
padding: 0;
height: 24px !important;
width: 27px;
text-indent: -5000px;
}
#taskbar .tooltip {
display: none;
}
.minimal #taskbar .tooltip {
position: absolute;
top: -500px;
right: 2px;
display: inline-block;
padding: 2px 8px 3px 8px;
background: #444;
background: -moz-linear-gradient(top, #444 0%, #333 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#444), color-stop(100%,#333));
background: -o-linear-gradient(top, #444 0%, #333 100%);
background: -ms-linear-gradient(top, #444 0%, #333 100%);
background: linear-gradient(to bottom, #444 0%, #333 100%);
color: #eee;
font-weight: bold;
white-space: nowrap;
border: 1px solid #777;
box-shadow: 0 1px 5px 0 #333;
-webkit-box-shadow: 0 1px 5px 0 #333;
z-index: 200;
white-space: nowrap;
text-shadow: 0px 1px 1px #000;
}
.minimal #taskbar .tooltip:after {
content: "";
position: absolute;
top: -4px;
right: 15px;
border-style: solid;
border-width: 0 4px 4px;
border-color: #888 transparent;
/* reduce the damage in FF3.0 */
display: block;
width: 0;
z-index: 251;
}
.minimal #taskbar a:hover .tooltip {
display: block;
top: 39px;
}
/*** taskbar ***/
#taskbar {
position: relative;
padding-right: 18px;
}
#taskbar a {
display: inline-block;
height: 34px;
padding: 12px 10px 0 6px;
}
#taskbar a span.button-inner {
display: inline-block;
font-size: 110%;
font-weight: normal;
text-shadow: 0px 1px 1px black;
padding: 5px 0 0 34px;
height: 19px;
background: url(images/buttons.png) -1000px 0 no-repeat;
}
#taskbar a:focus {
color: #fff;
text-shadow: 0px 1px 1px #666;
background-color: rgba(73,180,210,0.7);
outline: none;
}
#taskbar a.button-selected {
color: #3cf;
background-color: #2c2c2c;
}
#taskbar a.button-mail span.button-inner {
background-position: 0 2px;
}
#taskbar a.button-mail:hover span.button-inner,
#taskbar a.button-mail.button-selected span.button-inner {
background-position: 0 -22px;
}
#taskbar a.button-addressbook span.button-inner {
background-position: 0 -48px;
}
#taskbar a.button-addressbook:hover span.button-inner,
#taskbar a.button-addressbook.button-selected span.button-inner {
background-position: 0 -72px;
}
#taskbar a.button-settings span.button-inner {
background-position: 0 -96px;
}
#taskbar a.button-settings:hover span.button-inner,
#taskbar a.button-settings.button-selected span.button-inner {
background-position: 0 -120px;
}
#taskbar a.button-calendar span.button-inner {
background-position: 0 -144px;
}
#taskbar a.button-calendar:hover span.button-inner,
#taskbar a.button-calendar.button-selected span.button-inner {
background-position: 0 -168px;
}
#taskbar .minmodetoggle {
position: absolute;
top: 0;
right: 0;
display: block;
width: 19px;
height: 46px;
cursor: pointer;
background: url(images/buttons.png) -35px -1778px no-repeat;
}
.minimal #taskbar .minmodetoggle {
height: 42px;
background-position: -35px -1820px;
}
#mainscreen {
position: absolute;
top: 88px;
left: 10px;
right: 10px;
bottom: 20px;
}
#mainscreencontent {
position: absolute;
top: 42px;
left: 0;
right: 0;
bottom: 0;
}
#mainscreen.offset {
top: 132px;
}
#mainscreen .offset {
top: 42px;
}
.minimal #mainscreen {
top: 62px;
}
.minimal #mainscreen.offset {
top: 102px;
}
.extwin #mainscreen {
top: 40px;
}
.extwin #mainscreen.offset {
top: 86px;
}
.uibox {
border: 1px solid #a3a3a3;
border-radius: 4px;
overflow: hidden;
box-shadow: 0 0 2px #999;
-webkit-box-shadow: 0 0 2px #999;
background: #fff;
}
.minwidth {
min-width: 1024px;
}
.scroller {
overflow: auto;
}
.watermark {
background-image: url(images/watermark.jpg);
background-position: center;
background-repeat: no-repeat;
}
/* fix scrolling within iframes in webkit browsers on touch devices */
@media screen and (-webkit-min-device-pixel-ratio:0) and (max-device-width:1024px) {
.iframebox {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
}
/*** lists ***/
.listbox {
background: #d9ecf4;
overflow: hidden;
}
.listbox .scroller {
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
}
.listbox .scroller.withfooter {
bottom: 42px;
}
.listbox .boxtitle + .scroller {
top: 34px;
}
.boxtitle,
.uibox .listing thead th,
.uibox .listing thead td {
font-size: 12px;
font-weight: bold;
padding: 7px 8px 6px 8px;
line-height: 20px;
margin: 0;
text-shadow: 0px 1px 1px #fff;
border-bottom: 1px solid #bbd3da;
white-space: nowrap;
}
.uibox .listing thead th,
.uibox .listing thead td {
padding-bottom: 8px;
height: auto;
}
.uibox .boxtitle,
.uibox .listing thead th,
.uibox .listing thead td {
background: #b0ccd7;
color: #004458;
border-radius: 4px 4px 0 0;
}
.listbox .listitem,
.listbox .tablink,
.listing tbody td,
.listing li {
display: block;
border-top: 1px solid #fff;
border-bottom: 1px solid #bbd3da;
cursor: default;
font-weight: normal;
}
.listbox .listitem a,
.listbox .listitem span,
.listbox .tablink a,
.listing tbody td,
.listing li a {
display: block;
color: #376572;
text-shadow: 0px 1px 1px #fff;
text-decoration: none;
cursor: default;
padding: 4px 8px;
line-height: 17px;
height: 17px;
white-space: nowrap;
}
.listing tbody td {
display: table-cell;
min-height: 14px;
outline: none;
}
.listing tbody td a {
color: #376572;
text-shadow: 0px 1px 1px #fff;
text-decoration: none;
}
.webkit .listing tbody td {
height: 14px;
}
/* This padding-left minus the focused padding left should be half of the focused border-left */
.listing thead tr td:first-child,
.listing tbody tr td:first-child {
border-left: 2px solid transparent;
padding-left: 6px;
}
.listing.iconized thead tr td:first-child,
.listing.iconized tbody tr td:first-child {
padding-left: 34px;
}
/* because of border-collapse, we make the left border twice what we want it to be - half will be hidden to the left */
.listing.focus tbody tr.focused > td:first-child {
border-left: 2px solid #739da8;
}
.listbox .listitem.selected,
.listbox .tablink.selected,
.listbox .listitem.selected > a,
.listbox .tablink.selected > a,
.listing tbody tr.selected td,
.listing li.selected,
.listing li.selected > a {
color: #004458;
font-weight: bold;
background-color: #c7e3ef;
}
ul.listing {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
ul.listing li {
background-color: #d9ecf4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
ul.listing li ul {
border-top: 1px solid #bbd3da;
}
ul.listing li.droptarget,
table.listing tr.droptarget td {
background-color: #e8e798;
}
.listbox table.listing {
background-color: #d9ecf4;
}
table.listing,
table.layout {
border: 0;
width: 100%;
border-spacing: 0;
}
table.layout td {
vertical-align: top;
}
ul.treelist li {
position: relative;
}
ul.treelist li ul {
margin: 0;
padding: 0;
}
ul.treelist li ul li:last-child {
border-bottom: 0;
}
ul.treelist li a {
display: block;
padding-left: 20px;
overflow: hidden;
text-overflow: ellipsis;
}
ul.treelist li a:focus,
ul.listing .listitem a:focus,
ul.listing .listitem span:focus,
ul.listing.focus .listitem.focused span {
color: #fff !important;
background-color: rgba(73,180,210,0.6);
text-shadow: 0px 1px 1px #666;
outline: none;
}
ul.treelist ul li a {
padding-left: 38px;
}
ul.treelist ul ul li a {
padding-left: 54px;
}
ul.treelist.iconized li a {
padding-left: 36px;
}
ul.treelist.iconized ul li a {
padding-left: 62px;
}
ul.treelist.iconized ul ul li a {
padding-left: 88px;
}
ul.treelist.iconized ul ul ul li a {
padding-left: 114px;
}
ul.treelist li div.treetoggle {
position: absolute;
top: 7px;
left: 4px;
width: 13px;
height: 13px;
background: url(images/listicons.png) -3px -144px no-repeat;
cursor: pointer;
}
ul.treelist li ul li div.treetoggle {
left: 22px;
}
ul.treelist.iconized li div.treetoggle {
top: 13px;
left: 19px;
}
ul.treelist.iconized ul li div.treetoggle {
left: 45px;
}
ul.treelist.iconized ul ul li div.treetoggle {
left: 71px;
}
ul.treelist li div.treetoggle.expanded {
background-position: -3px -168px;
}
ul.treelist li.selected > div.collapsed {
background-position: -23px -144px;
}
ul.treelist li.selected > div.expanded {
background-position: -23px -168px;
}
.listbox .boxfooter {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 42px;
border-top: 1px solid #ccdde4;
background: #d9ecf4;
box-shadow: inset 0 1px 0 0 #fff;
-webkit-box-shadow: inset 0 1px 0 0 #fff;
white-space: nowrap;
overflow: hidden;
}
.uibox .boxfooter {
border-radius: 0 0 4px 4px;
}
.boxfooter .listbutton {
display: inline-block;
text-decoration: none;
width: 48px;
border-right: 1px solid #fff;
background: #c7e3ef;
padding: 3px 0;
margin-top: 1px;
}
.boxfooter a.listbutton:focus {
color: #fff;
background-color: rgba(73,180,210,0.6);
text-shadow: 0px 1px 1px #666;
outline: none;
}
.uibox .boxfooter .listbutton:first-child {
border-radius: 0 0 0 4px;
}
.boxfooter .listbutton .inner {
display: inline-block;
width: 48px;
height: 35px;
text-indent: -5000px;
background-image: url(images/buttons.png);
background-position: -1000px 0;
background-repeat: no-repeat;
}
.boxfooter .listbutton.add .inner {
background-position: 10px -1301px;
}
.boxfooter .listbutton.delete .inner {
background-position: 10px -1342px;
}
.boxfooter .listbutton.groupactions .inner {
background-position: 5px -1382px;
}
.boxfooter .listbutton.addto .inner {
background-position: 5px -1422px;
}
.boxfooter .listbutton.addcc .inner {
background-position: 5px -1462px;
}
.boxfooter .listbutton.addbcc {
width: 54px;
}
.boxfooter .listbutton.addbcc .inner {
width: 54px;
background-position: 2px -1502px;
}
.boxfooter .listbutton.removegroup .inner {
background-position: 5px -1540px;
}
.boxfooter .listbutton.disabled .inner {
opacity: 0.4;
}
.boxfooter .countdisplay {
display: inline-block;
position: relative;
top: 10px;
color: #69929e;
padding: 3px 6px;
}
.boxpagenav {
position: absolute;
top: 10px;
right: 6px;
width: auto;
}
.boxpagenav a.icon {
display: inline-block;
padding: 1px 3px;
height: 13px;
width: 14px;
text-indent: 1000px;
vertical-align: bottom;
overflow: hidden;
background: url(images/buttons.png) -4px -286px no-repeat;
}
.boxpagenav a.icon.prevpage {
background-position: -4px -301px;
}
.boxpagenav a.icon.nextpage {
background-position: -28px -301px;
}
.boxpagenav a.icon.lastpage {
background-position: -28px -286px;
}
.boxpagenav a.icon.disabled {
opacity: 0.4;
}
.centerbox {
width: 40em;
margin: 16px auto;
}
.errorbox {
width: 40em;
padding: 20px;
}
.errorbox h3 {
font-size: 16px;
margin-top: 0;
}
/*** Records table ***/
table.records-table {
display: table;
width: 100%;
table-layout: fixed;
border-spacing: 0;
border: 1px solid #bbd3da;
}
.boxlistcontent .records-table {
border: 0;
}
.records-table thead th,
.records-table thead td {
color: #69939e;
font-size: 11px;
font-weight: bold;
background: #d6eaf3;
background: -moz-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0,#e3f2f6), color-stop(8%,#d6eaf3), color-stop(100%,#d6eaf3));
background: -o-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
background: -ms-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px ,#d6eaf3 100%);
background: linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
border-left: 1px solid #bbd3da;
padding: 8px 7px;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
.records-table.sortheader thead th,
.records-table.sortheader thead td {
padding: 0;
}
.records-table thead th a,
.records-table thead td a,
.records-table thead th span,
.records-table thead td span {
display: block;
padding: 7px 7px;
color: #69939e;
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
}
.records-table thead th a:focus,
.records-table thead td a:focus {
color: #fff;
background-color: rgba(73,180,210,0.7);
text-shadow: 0px 1px 1px #666;
outline: none;
}
.records-table tbody td {
padding: 2px 7px;
border-bottom: 1px solid #ddd;
border-left: 1px dotted #bbd3da;
white-space: nowrap;
cursor: default;
overflow: hidden;
text-overflow: ellipsis;
background-color: #fff;
outline: none;
}
/* This padding-left minus the focused padding left should be half of the focused border-left */
.records-table thead tr th:first-child,
.records-table thead tr td:first-child,
.records-table tbody tr td:first-child {
border-left: 2px solid transparent;
padding-left: 4px;
}
/* because of border-collapse, we make the left border twice what we want it to be - half will be hidden to the left */
.records-table.focus tbody tr.focused > td:first-child {
border-left: 2px solid #49b3d2;
}
.records-table tr.selected td {
color: #fff !important;
background-color: #4db0d2 !important;
}
.records-table.focus tr.selected td {
background: #019bc6;
background: -moz-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#019bc6), color-stop(100%,#017cb4));
background: -o-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background: -ms-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background: linear-gradient(to bottom, #019bc6 0%, #017cb4 100%);
}
.records-table tr.selected td a,
.records-table tr.selected td span {
color: #fff !important;
}
.records-table tr.deleted td,
.records-table tr.deleted td a {
color: #ccc !important;
}
/*** iFrames ***/
#aboutframe {
width: 97%;
height: 100%;
border: 0;
padding: 0;
}
body.iframe {
background: #fff;
margin: 38px 0 10px 0;
}
body.iframe.error {
background: #ededed;
}
body.iframe.floatingbuttons {
margin-bottom: 40px;
}
body.iframe.fullheight {
margin: 0;
}
.contentbox .boxtitle,
body.iframe .boxtitle {
color: #777;
background: #eee;
background: -moz-linear-gradient(top, #eee 0%, #dfdfdf 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eee), color-stop(100%,#dfdfdf));
background: -o-linear-gradient(top, #eee 0%, #dfdfdf 100%);
background: -ms-linear-gradient(top, #eee 0%, #dfdfdf 100%);
background: linear-gradient(to bottom, #eee 0%, #dfdfdf 100%);
border-bottom: 1px solid #ccc;
}
body.iframe .boxtitle {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 100;
}
body.iframe .footerleft.floating,
#composeview-bottom .formbuttons.floating {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 110;
background: #fff;
padding-top: 8px;
padding-bottom: 12px;
}
body.iframe .footerleft.floating:before,
#composeview-bottom .formbuttons.floating:before {
content: " ";
position: absolute;
top: -6px;
left: 0;
width: 100%;
height: 6px;
background: url(images/overflowshadow.png) top center no-repeat;
}
.boxcontent {
padding: 10px;
}
+.boxcontent .boxwarning {
+ margin: 0 0 10px;
+ display: block;
+ color: #960;
+ border: 1px solid #ffdf0e;
+ background: url(images/messages.png) #fef893 5px -85px no-repeat;
+ padding: 6px 12px 6px 30px;
+}
+
.contentbox .scroller {
position: absolute;
top: 34px;
left: 0;
right: 0;
bottom: 0px;
overflow: auto;
}
.iframebox {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0px;
}
.footerleft {
padding: 0 12px 4px 12px;
}
.propform fieldset {
margin-bottom: 20px;
border: 0;
padding: 0;
}
.propform fieldset legend {
display: block;
font-size: 14px;
font-weight: bold;
padding-bottom: 10px;
margin-bottom: 0;
}
.propform fieldset fieldset legend {
color: #666;
font-size: 12px;
}
.propform div.prop {
margin-bottom: 0.5em;
}
.propform div.prop.block label {
display: block;
margin-bottom: 0.3em;
}
.propform div.prop.block input,
.propform div.prop.block textarea {
width: 95%;
}
.propform a.disabled {
color: #999;
text-decoration: none;
cursor: default;
}
fieldset.floating {
float: left;
margin-right: 10px;
margin-bottom: 10px;
}
table.propform {
width: 100%;
border-spacing: 0;
border-collapse: collapse;
}
ul.proplist li,
table.propform td {
width: 80%;
padding: 4px 10px;
background: #eee;
border-bottom: 2px solid #fff;
}
table.propform td.title {
width: 20%;
color: #333;
padding-right: 20px;
white-space: nowrap;
}
table.propform .mceLayout td {
padding: 0;
border-bottom: 0;
}
ul.proplist {
list-style: none;
margin: 0;
padding: 0;
}
ul.proplist li {
width: auto;
}
#pluginbody {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/*** Login form ***/
#login-form {
position: relative;
width: 580px;
margin: 20ex auto 2ex auto;
}
#login-form .box-inner {
width: 430px;
background: url(images/linen_login.jpg) top left no-repeat #5c5c5c;
margin: 0 50px;
padding: 10px 24px 24px 24px;
border: 1px solid #333;
border-radius: 5px;
box-shadow: inset 0 0 1px #ccc;
-webkit-box-shadow: inset 0 0 1px #ccc;
}
#login-form .box-bottom {
background: url(images/login_shadow.png) top center no-repeat;
margin-top: -3px;
padding-top: 10px;
}
#login-form .noscriptwarning {
margin: 0 auto;
width: 430px;
color: #cf2734;
font-size: 110%;
font-weight: bold;
}
#login-form td.input {
width: 80%;
padding: 8px;
}
#login-form input[type="text"],
#login-form input[type="password"] {
width: 100%;
border-color: #666;
}
#login-form input.button {
color: #444;
text-shadow: 0px 1px 1px #fff;
border-color: #f9f9f9;
background: #f9f9f9;
background: -moz-linear-gradient(top, #f9f9f9 0%, #e2e2e2 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f9f9), color-stop(100%,#e2e2e2));
background: -o-linear-gradient(top, #f9f9f9 0%, #e2e2e2 100%);
background: -ms-linear-gradient(top, #f9f9f9 0%, #e2e2e2 100%);
background: linear-gradient(to bottom, #f9f9f9 0%, #e2e2e2 100%);
box-shadow: inset 0 1px 0 0 #fff;
-webkit-box-shadow: inset 0 1px 0 0 #fff;
}
#login-form input.button:hover,
#login-form input.button:focus {
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9), inset 0 1px 0 0 #fff;
}
#login-form input.button:active {
color: #333;
background: -moz-linear-gradient(top, #dcdcdc 0%, #f9f9f9 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dcdcdc), color-stop(100%,#f9f9f9));
background: -o-linear-gradient(top, #dcdcdc 0%, #f9f9f9 100%);
background: -ms-linear-gradient(top, #dcdcdc 0%, #f9f9f9 100%);
background: linear-gradient(to bottom, #dcdcdc 0%, #f9f9f9 100%);
}
#login-form form table {
width: 98%;
}
#login-form td.title {
width: 20%;
white-space: nowrap;
color: #cecece;
text-shadow: 0px 1px 1px black;
text-align: right;
padding-right: 1em;
}
#login-form p.formbuttons {
margin-top: 2em;
text-align: center;
}
#login-form #logo {
margin-bottom: 20px;
border: none;
}
#login-form #message {
min-height: 40px;
padding: 5px 25px;
text-align: center;
font-size: 1.1em;
}
#login-form #message div {
display: inline-block;
padding-right: 0;
font-size: 12px;
}
#bottomline {
font-size: 90%;
text-align: center;
margin-top: 2em;
}
/*** quicksearch **/
.searchbox {
position: relative;
}
#quicksearchbar {
position: absolute;
right: 2px;
top: 2px;
width: 240px;
}
.searchbox input,
#quicksearchbar input {
width: 176px;
margin: 0;
padding: 3px 30px 3px 34px;
height: 18px;
background: #f1f1f1;
border-color: #ababab;
font-weight: bold;
font-size: 11px;
}
.searchbox .searchicon,
.searchbox #searchmenulink,
#quicksearchbar #searchmenulink {
position: absolute;
top: 5px;
left: 6px;
}
.searchbox #searchreset,
.searchbox .iconbutton.reset,
#quicksearchbar #searchreset {
position: absolute;
top: 4px;
right: 1px;
}
.listsearchbox {
padding: 4px;
background: #c7e3ef;
display: none;
}
.listsearchbox input {
width: 100%;
height: 26px;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/*** toolbar ***/
.toolbar .spacer {
display: inline-block;
width: 24px;
height: 40px;
padding: 0;
}
.toolbar a.button {
text-align: center;
font-size: 10px;
color: #555;
min-width: 50px;
max-width: 70px;
height: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 28px 2px 0 2px;
text-shadow: 0px 1px 1px #eee;
box-shadow: none;
-webkit-box-shadow: none;
background: url(images/buttons.png) -100px 0 no-repeat transparent;
border: 0;
border-radius: 0;
}
.dropbutton .dropbuttontip:focus,
.toolbar a.button:focus {
color: #fff;
text-shadow: 0px 1px 1px #666;
background-color: rgba(30,150,192, 0.5);
border-radius: 3px;
}
.toolbar a.button.disabled {
opacity: 0.4;
}
.dropbutton {
display: inline-block;
position: relative;
}
.dropbutton .dropbuttontip {
display: block;
position: absolute;
right: 0;
top: 0;
height: 41px;
width: 18px;
overflow: hidden;
text-indent: -5000px;
background: url(images/buttons.png) 0 -1255px no-repeat;
cursor: pointer;
outline: none;
}
.dropbutton .dropbuttontip:focus,
.dropbutton .dropbuttontip:hover {
background-position: -26px -1255px;
}
.dropbutton a.button.disabled + .dropbuttontip {
opacity: 0.5;
}
.dropbutton a.button.disabled + .dropbuttontip:hover {
background-position: 0 -1255px;
}
.dropbutton a.button {
margin-left: 0;
padding-left: 0;
margin-right: 0;
padding-right: 0;
}
.toolbar a.button.back {
background-position: 0 -1216px;
}
.toolbar a.button.checkmail {
background-position: center -1176px;
}
.toolbar a.button.compose {
background-position: center -530px;
}
.toolbar a.button.reply {
background-position: center -570px;
}
.toolbar a.button.reply-all {
min-width: 64px;
background-position: 0 -610px;
}
.toolbar a.button.forward {
min-width: 64px;
background-position: 0 -650px;
}
.toolbar a.button.delete {
background-position: center -690px;
}
.toolbar a.button.archive {
background-position: center -730px;
}
.toolbar a.button.junk {
background-position: center -770px;
}
.toolbar a.button.print {
background-position: center -810px;
}
.toolbar a.button.markmessage {
background-position: center -1094px;
}
.toolbar a.button.move {
background-position: center -1971px;
}
.toolbar a.button.more {
background-position: center -850px;
}
.toolbar a.button.attach {
background-position: center -890px;
}
.toolbar a.button.spellcheck {
min-width: 64px;
background-position: 0 -930px;
}
.toolbar a.button.spellcheck.selected {
background-position: 0 -1620px;
color: #1978a1;
}
.toolbar a.button.insertsig {
background-position: center -1135px;
}
.toolbar a.button.search {
background-position: center -970px;
}
.toolbar a.button.import {
background-position: center -1012px;
}
.toolbar a.button.export {
min-width: 64px;
background-position: 0 -1054px;
}
.toolbar a.button.send {
background-position: center -1660px;
}
.toolbar a.button.savedraft {
background-position: center -1700px;
}
.toolbar a.button.close {
background-position: 0 -1745px;
}
.toolbar a.button.download {
background-position: center -1892px;
}
.toolbar a.button.responses {
background-position: center -1932px;
}
a.menuselector {
display: inline-block;
border: 1px solid #ababab;
border-radius: 4px;
background: #f8f8f8;
background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));
background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);
background: -ms-linear-gradient(top, #f9f9f9 0%, #dddddd 100%);
background: linear-gradient(to bottom, #f8f8f8 0%, #dddddd 100%);
text-decoration: none;
color: #333;
cursor: pointer;
white-space: nowrap;
}
a.menuselector .handle {
display: inline-block;
padding: 0 32px 0 6px;
height: 20px;
line-height: 19px;
text-shadow: 0px 1px 1px #fff;
background: url(images/selector.png) right center no-repeat;
border-radius: 4px;
}
a.menuselector:active {
background: #dddddd;
background: -moz-linear-gradient(top, #dddddd 0%, #f8f8f8 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dddddd), color-stop(100%,#f8f8f8));
background: -o-linear-gradient(top, #dddddd 0%, #f8f8f8 100%);
background: -ms-linear-gradient(top, #dddddd 0%, #f8f8f8 100%);
background: linear-gradient(to bottom, #dddddd 0%, #f8f8f8 100%);
text-decoration: none;
}
select.decorated {
position: relative;
z-index: 10;
opacity: 0;
height: 22px;
cursor: pointer;
-khtml-appearance: none;
-webkit-appearance: none;
border: 0;
}
html.opera select.decorated {
opacity: 1;
}
select.decorated option {
color: #fff;
background: #444;
border: 0;
border-top: 1px solid #5a5a5a;
border-bottom: 1px solid #333;
text-shadow: 0px 1px 1px #333;
padding: 4px 6px;
outline: none;
cursor: default;
}
a.menuselector:focus,
a.menuselector.focus,
a.iconbutton:focus,
.pagenav a.button:focus {
border-color: #4fadd5;
box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
-webkit-box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
outline: none;
}
/*** quota indicator ***/
#quotadisplay {
left: 6px;
height: 18px;
font-size: 12px;
font-weight: bold;
text-shadow: 0px 1px 1px #fff;
padding-left: 30px;
background: url(images/quota.png) -100px 0 no-repeat;
}
#quotadisplay.p90,
#quotadisplay.p100 {
color: #e03221;
}
table.quota-info {
border-spacing: 0;
border-collapse: collapse;
table-layout: fixed;
margin: 5px;
}
table.quota-info td,
table.quota-info th {
color: white;
border: 1px solid lightgrey;
padding: 2px 3px;
text-align: center;
min-width: 80px;
}
table.quota-info td.name {
text-align: left;
}
table.quota-info td.root {
font-style: italic;
}
/*** popup menus ***/
.popupmenu,
#rcmKSearchpane {
display: none;
position: absolute;
top: 32px;
left: 90px;
width: auto;
max-height: 70%;
overflow: -moz-scrollbars-vertical;
overflow-y: auto;
background: #444;
border: 1px solid #999;
z-index: 240;
border-radius: 4px;
box-shadow: 0 2px 6px 0 #333;
-webkit-box-shadow: 0 2px 6px 0 #333;
}
.popupmenu.dropdown {
border-radius: 0 0 4px 4px;
border-top: 0;
}
ul.toolbarmenu,
ul.toolbarmenu ul,
#rcmKSearchpane ul {
margin: 0;
padding: 0;
list-style: none;
}
.googie_list td,
ul.toolbarmenu li,
#rcmKSearchpane ul li {
color: #fff;
white-space: nowrap;
min-width: 130px;
margin: 0;
border-top: 1px solid #5a5a5a;
border-bottom: 1px solid #333;
}
.googie_list tr:first-child td,
ul.toolbarmenu > li:first-child,
select.decorated option:first-child {
border-top: 0;
}
.googie_list tr:last-child td,
ul.toolbarmenu > li:last-child,
select.decorated option:last-child {
border-bottom: 0;
}
.googie_list td span,
ul.toolbarmenu li a {
display: block;
color: #666;
text-shadow: 0px 1px 1px #333;
text-decoration: none;
min-height: 14px;
padding: 6px 16px 6px 10px;
}
.googie_list td span {
padding: 3px 10px;
}
.googie_list td span,
ul.toolbarmenu li a.active {
color: #fff;
cursor: default;
}
.googie_list td.googie_list_onhover,
ul.toolbarmenu li a.active:hover,
ul.toolbarmenu li a.active:focus,
#rcmKSearchpane ul li.selected,
#pagejump-selector ul li.selected,
select.decorated option:hover,
select.decorated option[selected='selected'] {
background-color: #00aad6;
background: -moz-linear-gradient(top, #00aad6 0%, #008fc9 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#00aad6), color-stop(100%,#008fc9));
background: -o-linear-gradient(top, #00aad6 0%, #008fc9 100%);
background: -ms-linear-gradient(top, #00aad6 0%, #008fc9 100%);
background: linear-gradient(to bottom, #00aad6 0%, #008fc9 100%);
outline: none;
}
ul.toolbarmenu.iconized li a,
ul.toolbarmenu.selectable li a {
padding-left: 30px;
}
ul.toolbarmenu.selectable li a.selected {
background: url(images/messages.png) 4px -27px no-repeat;
}
ul.toolbarmenu li label {
display: block;
color: #fff;
padding: 4px 8px;
text-shadow: 0px 1px 1px #333;
}
ul.toolbarmenu li.separator label {
color: #bbb;
font-style: italic;
}
ul.toolbarmenu li a.icon {
color: #eee;
padding: 2px 6px;
}
ul.toolbarmenu li span.icon,
#rcmKSearchpane ul li i.icon {
display: block;
min-height: 14px;
padding: 4px 4px 1px 24px;
height: 17px;
background-image: url(images/listicons.png);
background-position: -100px 0;
background-repeat: no-repeat;
opacity: 0.2;
}
ul.toolbarmenu li a.active span.icon {
opacity: 0.99;
}
ul.toolbarmenu li span.read {
background-position: 0 -1220px;
}
ul.toolbarmenu li span.unread {
background-position: 0 -1196px;
}
ul.toolbarmenu li span.flagged {
background-position: 0 -1244px;
}
ul.toolbarmenu li span.unflagged {
background-position: 0 -1268px;
}
ul.toolbarmenu li span.mail {
background-position: 0 -1293px;
}
ul.toolbarmenu li span.list {
background-position: 0 -1317px;
}
ul.toolbarmenu li span.invert {
background-position: 0 -1340px;
}
ul.toolbarmenu li span.cross {
background-position: 0 -1365px;
}
ul.toolbarmenu li span.print {
background-position: 0 -1436px;
}
ul.toolbarmenu li span.download {
background-position: 0 -1412px;
}
ul.toolbarmenu li span.edit {
background-position: 0 -1388px;
}
ul.toolbarmenu li span.viewsource {
background-position: 0 -1460px;
}
ul.toolbarmenu li span.extwin {
background-position: 0 -1484px;
}
ul.toolbarmenu li span.conversation {
background-position: 0 -1532px;
}
ul.toolbarmenu li span.move {
background-position: 0 -2126px;
}
ul.toolbarmenu li span.copy {
background-position: 0 -2150px;
}
#pagejump-selector {
max-height: 250px;
overflow-x: hidden;
}
#pagejump-selector ul li {
min-width: 45px;
padding: 2px 5px;
cursor: default;
}
#snippetslist {
max-width: 200px;
}
#snippetslist li a {
overflow: hidden;
text-overflow: ellipsis;
}
#rcmKSearchpane {
border-radius: 0 0 4px 4px;
border-top: 0;
}
#rcmKSearchpane ul li {
text-shadow: 0px 1px 1px #333;
text-decoration: none;
min-height: 14px;
padding: 6px 10px 6px 28px;
border: 0;
cursor: default;
position: relative;
}
#rcmKSearchpane ul li i.icon {
opacity: 0.99;
position: absolute;
top: 4px;
left: 5px;
width: 18px;
height: 18px;
padding: 0;
background-position: -1px -2223px;
}
#rcmKSearchpane ul li.group i.icon {
background-position: -1px -2247px;
}
.popupdialog {
display: none;
padding: 10px;
}
.popupdialog .formbuttons {
margin: 20px 0 4px 0;
}
.ui-dialog .prompt input {
display: block;
margin: 8px 0;
}
.hint {
margin: 4px 0;
color: #999;
text-shadow: 0px 1px 1px #fff;
}
.splitter {
user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
position: absolute;
background: url(images/splitter.png) center no-repeat;
}
.splitter-h {
height: 10px;
width: 100%;
cursor: n-resize;
cursor: row-resize;
background-position: center 0;
}
.splitter-v {
width: 10px;
height: 100%;
cursor: e-resize;
cursor: col-resize;
background-position: 0 center;
}
#rcmdraglayer {
min-width: 260px;
width: auto !important;
width: 260px;
padding: 6px 8px;
background: #444;
border: 1px solid #555;
border-radius: 4px;
box-shadow: 0 2px 6px 0 #333;
-webkit-box-shadow: 0 2px 6px 0 #333;
z-index: 250;
color: #ccc;
white-space: nowrap;
opacity: 0.92;
text-shadow: 0px 1px 1px #333;
}
#rcmdraglayer:after {
content: "";
position: absolute;
top: 6px;
left: -6px;
border-style: solid;
border-width: 6px 6px 6px 0;
border-color: transparent #444;
/* reduce the damage in FF3.0 */
display: block;
width: 0;
z-index: 251;
}
.draglayercopy:before {
position: absolute;
bottom: -6px;
left: -6px;
content: " ";
width: 16px;
height: 16px;
background: url(images/buttons.png) -7px -358px no-repeat;
z-index: 255;
}
.popup label > input {
margin-left: 10px;
}
/*** folder selector ***/
#folder-selector {
z-index: 1000;
}
#folder-selector li a span {
background: url("images/listicons.png") 4px -2021px no-repeat;
display: block;
height: 17px;
min-height: 14px;
padding: 4px 4px 1px 28px;
overflow: hidden;
max-width: 120px;
text-overflow: ellipsis;
}
#folder-selector li a.virtual {
opacity: .2;
}
#folder-selector li a.inbox span {
background-position: 4px -2049px;
}
#folder-selector li a.drafts span {
background-position: 4px -1388px;
}
#folder-selector li a.sent span {
background-position: 4px -2074px;
}
#folder-selector li a.trash span {
background-position: 4px -1508px;
}
#folder-selector li a.junk span {
background-position: 4px -2100px;
}
/*** folders list ***/
.folderlist li.mailbox a {
padding-left: 36px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
background-image: url(images/listicons.png);
background-repeat: no-repeat;
background-position: 6px 3px;
}
.folderlist li.mailbox.unread > a {
padding-right: 36px;
}
.folderlist li.mailbox > a:focus,
.folderlist li.mailbox.selected > a {
background-position: 6px -21px;
}
.folderlist li.mailbox.inbox > a {
background-position: 6px -189px;
}
.folderlist li.mailbox.inbox > a:focus,
.folderlist li.mailbox.inbox.selected > a {
background-position: 6px -213px;
}
.folderlist li.mailbox.drafts > a {
background-position: 6px -238px;
}
.folderlist li.mailbox.drafts > a:focus,
.folderlist li.mailbox.drafts.selected > a {
background-position: 6px -262px;
}
.folderlist li.mailbox.sent > a {
background-position: 6px -286px;
}
.folderlist li.mailbox.sent > a:focus,
.folderlist li.mailbox.sent.selected > a {
background-position: 6px -310px;
}
.folderlist li.mailbox.junk > a {
background-position: 6px -334px;
}
.folderlist li.mailbox.junk > a:focus,
.folderlist li.mailbox.junk.selected > a {
background-position: 6px -358px;
}
.folderlist li.mailbox.trash > a {
background-position: 6px -382px;
}
.folderlist li.mailbox.trash > a:focus,
.folderlist li.mailbox.trash.selected > a {
background-position: 6px -406px;
}
.folderlist li.mailbox.trash.empty > a {
background-position: 6px -1924px;
}
.folderlist li.mailbox.trash.empty > a:focus,
.folderlist li.mailbox.trash.empty.selected > a {
background-position: 6px -1948px;
}
.folderlist li.mailbox.archive > a {
background-position: 6px -1699px;
}
.folderlist li.mailbox.archive > a:focus,
.folderlist li.mailbox.archive.selected > a {
background-position: 6px -1723px;
}
.folderlist li.mailbox ul li.drafts > a {
background-position: 23px -238px;
}
.folderlist li.mailbox ul li.drafts > a:focus,
.folderlist li.mailbox ul li.drafts.selected > a {
background-position: 23px -262px;
}
.folderlist li.mailbox ul li.sent > a {
background-position: 23px -286px;
}
.folderlist li.mailbox ul li.sent > a:focus,
.folderlist li.mailbox ul li.sent.selected > a {
background-position: 23px -310px;
}
.folderlist li.mailbox ul li.junk > a {
background-position: 23px -334px;
}
.folderlist li.mailbox ul li.junk > a:focus,
.folderlist li.mailbox ul li.junk.selected > a {
background-position: 23px -358px;
}
.folderlist li.mailbox ul li.trash > a {
background-position: 23px -382px;
}
.folderlist li.mailbox ul li.trash > a:focus,
.folderlist li.mailbox ul li.trash.selected > a {
background-position: 23px -406px;
}
.folderlist li.mailbox ul li.trash.empty > a {
background-position: 23px -1924px;
}
.folderlist li.mailbox ul li.trash.empty > a:focus,
.folderlist li.mailbox ul li.trash.empty.selected > a {
background-position: 23px -1948px;
}
.folderlist li.mailbox ul li.archive > a {
background-position: 23px -1699px;
}
.folderlist li.mailbox ul li.archive > a:focus,
.folderlist li.mailbox ul li.archive.selected > a {
background-position: 23px -1723px;
}
.folderlist li.virtual > a {
color: #aaa;
}
.folderlist li.mailbox div.treetoggle {
top: 13px;
left: 19px;
}
.folderlist li.mailbox ul li:last-child {
border-bottom: 0;
}
/* nested mailboxes */
.folderlist li.mailbox ul {
list-style: none;
margin: 0;
padding: 0;
border-top: 1px solid #bbd3da;
}
.folderlist li.mailbox ul li a {
padding-left: 52px; /* 36 + 1 x 16 */
background-position: 22px -95px; /* 6 + 1 x 16 */
}
.folderlist li.mailbox ul li > a:focus,
.folderlist li.mailbox ul li.selected > a {
background-position: 22px -119px;
}
.folderlist li.mailbox ul li div.treetoggle {
left: 33px;
top: 14px;
}
.folderlist li.mailbox ul ul li.mailbox a {
padding-left: 68px; /* 2x */
background-position: 38px -95px;
}
.folderlist li.mailbox ul ul li > a:focus,
.folderlist li.mailbox ul ul li.selected > a {
background-position: 38px -119px;
}
.folderlist li.mailbox ul ul li div.treetoggle {
left: 48px;
}
.folderlist li.mailbox ul ul ul li.mailbox a {
padding-left: 84px; /* 3x */
background-position: 54px -95px;
}
.folderlist li.mailbox ul ul ul li > a:focus,
.folderlist li.mailbox ul ul ul li.selected > a {
background-position: 54px -119px;
}
.folderlist li.mailbox ul ul ul li div.treetoggle {
left: 64px;
}
.folderlist li.mailbox ul ul ul ul li.mailbox a {
padding-left: 100px; /* 4x */
background-position: 70px -95px;
}
.folderlist li.mailbox ul ul ul ul li > a:focus,
.folderlist li.mailbox ul ul ul ul li.selected > a {
background-position: 70px -119px;
}
.folderlist li.mailbox ul ul ul ul li div.treetoggle {
left: 80px;
}
/* indent folders on levels > 4 */
.folderlist li.mailbox ul ul ul ul ul li {
padding-left: 16px;
}
.folderlist li.mailbox ul ul ul ul ul li div.treetoggle {
left: 96px;
}
/*** attachment list ***/
.attachmentslist {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
text-overflow: ellipsis;
}
.attachmentslist li {
display: block;
position: relative;
background: url(images/filetypes.png) 0 0 no-repeat;
margin-bottom: 1px;
}
.attachmentslist li.txt,
.attachmentslist li.text {
background-position: 0 -416px;
}
.attachmentslist li.pdf {
background-position: 0 -26px;
}
.attachmentslist li.doc,
.attachmentslist li.docx,
.attachmentslist li.msword {
background-position: 0 -52px;
}
.attachmentslist li.odt {
background-position: 0 -78px;
}
.attachmentslist li.xls,
.attachmentslist li.xlsx,
.attachmentslist li.msexcel {
background-position: 0 -104px;
}
.attachmentslist li.ods {
background-position: 0 -130px;
}
.attachmentslist li.zip,
.attachmentslist li.gz {
background-position: 0 -156px;
}
.attachmentslist li.rar {
background-position: 0 -182px;
}
.attachmentslist li.image {
background-position: 0 -208px;
}
.attachmentslist li.jpg,
.attachmentslist li.jpeg {
background-position: 0 -234px;
}
.attachmentslist li.png {
background-position: 0 -260px;
}
.attachmentslist li.m4p {
background-position: 0 -286px;
}
.attachmentslist li.mp3,
.attachmentslist li.audio {
background-position: 0 -312px;
}
.attachmentslist li.video {
background-position: 0 -338px;
}
.attachmentslist li.ics,
.attachmentslist li.calendar {
background-position: 0 -364px;
}
.attachmentslist li.vcard {
background-position: 0 -390px;
}
.attachmentslist li.sig,
.attachmentslist li.pgp-signature,
.attachmentslist li.pkcs7-signature {
background-position: 0 -442px;
}
.attachmentslist li.html {
background-position: 0 -468px;
}
.attachmentslist li.eml,
.attachmentslist li.rfc822 {
background-position: 0 -494px;
}
.attachmentslist li.ppt,
.attachmentslist li.pptx,
.attachmentslist li.ppsx,
.attachmentslist li.vnd.mspowerpoint {
background-position: 0 -520px;
}
.attachmentslist li.odp,
.attachmentslist li.otp {
background-position: 0 -546px;
}
.attachmentslist li a,
#compose-attachments ul li {
display: block;
color: #333;
font-weight: bold;
padding: 3px 15px 3px 30px;
text-shadow: 0px 1px 1px #fff;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 20px;
outline: none;
}
.attachmentslist li a.drop {
background: url(images/buttons.png) no-repeat scroll center -1570px;
width: 14px;
height: 20px;
cursor: pointer;
position: absolute;
right: 0;
top: 0;
padding: 0;
overflow: hidden;
text-indent: -5000px;
outline: none;
}
.attachmentslist li a:focus,
.attachmentslist li a.drop:focus {
background-color: rgba(30,150,192, 0.5);
border-radius: 2px;
}
#compose-attachments ul li {
padding-right: 28px;
}
.attachmentslist li a:hover {
text-decoration: underline;
}
.attachmentslist li.uploading {
background: url(images/ajaxloader.gif) 2px 6px no-repeat;
}
.attachmentslist li a.delete,
.attachmentslist li a.cancelupload {
position: absolute;
top: 4px;
right: 0;
width: 20px;
height: 18px;
padding: 0;
text-decoration: none;
text-indent: -5000px;
background-image: url(images/buttons.png);
background-position: -6px -338px;
background-repeat: no-repeat;
}
.attachmentslist li a.cancelupload {
background-position: -6px -378px;
}
/*** fieldset tabs ***/
.tabbed.ui-tabs {
padding: 0;
border: 0 !important;
background: none;
}
.ui-dialog .tabbed.ui-tabs {
margin: -12px -8px 0 -8px;
}
.boxcontent.tabbed.ui-tabs {
padding: 10px;
}
.ui-tabs .tabsbar.ui-tabs-nav {
margin-bottom: 10px;
}
.ui-dialog-content .ui-tabs .tabsbar.ui-tabs-nav {
margin-bottom: 0;
}
.tabsbar .tablink:last-child {
background: none;
}
.tabsbar .tablink:last-child a {
border-right: 0;
}
.ui-tabs .ui-tabs-nav li.tablink a {
background: #fff;
}
.ui-tabs fieldset.ui-tabs-panel {
border: 0;
padding: 0;
margin-left: 0;
background: none;
}
.ui-dialog .propform .ui-tabs-panel {
display: block;
background: #efefef;
padding: 0.5em 1em;
}
#image-selector-form.droptarget {
background: url(images/filedrop.png) center bottom no-repeat;
}
/** Common TinyMCE fixes **/
.mce-btn-small .mce-ico {
display: inline; /* for old Firefox */
}
.mce-btn-small i {
line-height: 16px !important;
vertical-align: text-top !important;
}
_:not(), _:-moz-handler-blocked, .mozilla .mce-btn-small i {
line-height: 20px !important;
}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jan 31, 9:39 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
426492
Default Alt Text
(337 KB)

Event Timeline