Compare commits

..

330 Commits

Author SHA1 Message Date
Mark Scarbrough d0a14ffc05 Fix SQL syntax error on MariaDB 10.2 (#5774) (#6833)
Backported from 1.3 release to the 1.1 LTS release.
5 years ago
Thomas Bruederli fe0dc4eef8 Bump version to 1.1.12 and copyright to 2018 6 years ago
Aleksander Machniak 0c9074f286 Fix regression where IMAP commands with '*' uidset argument wasn't working 6 years ago
Thomas Bruederli d4475e58db Bump version to 1.1.11 6 years ago
Thomas Bruederli aaafe8f917 Fix check_request() bypass in plugins using get_uids() (#6238)
[CVE-2018-9846]
6 years ago
Thomas Bruederli 498ff0a283 Fix possible IMAP command injection vulnerability (#6229)
[CVE-2018-9846]
6 years ago
Aleksander Machniak 5d889cca13 Fix bug in remote content blocking on HTML image and style tags (#6178) 6 years ago
Aleksander Machniak a5dac2e694 Small improvement in log_dir handling 6 years ago
Aleksander Machniak bb9db12a79 Fix parse error from last commit 6 years ago
Aleksander Machniak a5e4578482 Don't ignore (global) userlogins/sendmail logs in per_user_logging mode 6 years ago
Thomas Bruederli 7f992eac3d Bump version + add CVE ID 7 years ago
Aleksander Machniak b707e19f4b Update changelog 7 years ago
Aleksander Machniak e757cc4101 Fix file disclosure vulnerability caused by insuficient input validation in relation with attachment plugins (#6026) 7 years ago
Thomas Bruederli 4181f29608 Bump version to 1.1.9 7 years ago
Aleksander Machniak 24902b7fc3 Add CVE ident 7 years ago
Aleksander Machniak 10b227d70a Password: Fix security issue in virtualmin and sasl drivers 7 years ago
Aleksander Machniak bcdba37a82 Fix bug where base_dn setting was ignored inside group_filters (#5720) 7 years ago
Aleksander Machniak 6b16e0d593 Fix regression in LDAP fuzzy search where it always used prefix search instead (#5713) 7 years ago
Aleksander Machniak 2a2b04eb2a Remove redundant spaces from generated contact names 7 years ago
Thomas Bruederli f1483204c7 Bump version to 1.1.8 7 years ago
Thomas Bruederli d6ddd31a1b Better fix for XSS in style tags (9b5eee294) 7 years ago
Aleksander Machniak 9b5eee2946 Fix XSS issue in handling of a style tag inside of an svg element 7 years ago
Aleksander Machniak 11b65a905f Make sure date_create_from_format() exists
Only for Roundcube 1.1 (this function does not exist on PHP < 5.3)
7 years ago
Aleksander Machniak 7536739c7a Fix bug where microsecond format in logged date didn't work in some cases 7 years ago
Aleksander Machniak 6c6b299d2a Fix so microseconds macro (u) in log_date_format works (#1490446) 7 years ago
Aleksander Machniak b7a4257ffb Rename $sql_arr variable to $record as it's not about sql only 7 years ago
Aleksander Machniak 4cd090aa24 Fix regression where groups with email address were resolved to its members' addresses 7 years ago
Aleksander Machniak fca2bb7869 Fix visual glitch when using disabled_actions for items in Settings menu 7 years ago
Aleksander Machniak f8e0e1d4ed Fix bug where signature couldn't be added above the quote in Firefox 51 (#5628) 7 years ago
Aleksander Machniak 72975042a5 Fix bug where mail content frame couldn't be reset in some corner cases (#5608)
Conflicts:
	CHANGELOG
7 years ago
Aleksander Machniak e6132dda95 Fix so group/addressbook selection is retained on page refresh 8 years ago
Aleksander Machniak 28e3da2325 Disable Print button for pdf attachments in Firefox (#5125)
Mozilla's PDF.js viewer does not allow printing from host page.
We try to detect such situation and disable the button to minimize
user confusion.
8 years ago
Thomas Bruederli 4c1394cf2d Bump version to 1.1.7 8 years ago
Aleksander Machniak 45a3e81653 Fix vulnerability in handling of mail()'s 5th argument 8 years ago
Aleksander Machniak aa6bf38843 Fix _from argument validation 8 years ago
Aleksander Machniak 860a3b47e7 Fix recognizing Sent folder on search if current folder has been changed by plugins in meantime 8 years ago
Bostjan Skufca 9b8db4c9e0 Autocomplete refactoring: replace variable name '$id' with '$abook_id'
Reason:
Having genericly named variable $id in nested loops makes code unreadable.
Replacing generic name '$id' with '$ENTITIY_id' format removes all ambiguity.
8 years ago
Aleksander Machniak 1123f39cf4 Fix missing contact ID for contacts from non-sql addressbooks 8 years ago
Bostjan Skufca 6fb8da08f3 Autocomplete search: add id and source (addressbook) into resulting contact data array
Two reasons:
- provide it to plugin backend functions that use 'contacts_autocomplete_after' hook
- provide it to frontend

Why to frontend?
If plugin JS adds an 'autocomplete_insert' hook we need to provide it with exact
autocomplete data. Providing it with name and email address only, without pinpointing
exact origin of this autocomplete result, will severely limit learning capabilities of
potential future autocomplete implementations.
8 years ago
Thomas Bruederli 802d119153 Bump version to 1.1.6 8 years ago
Aleksander Machniak 008f310f3a de_DE: abboniert -> abonniert 8 years ago
Aleksander Machniak 32ddcfd3d0 Fix error causing empty INBOX listing in Firefox when using an URL with user:password specified (#5400) 8 years ago
Aleksander Machniak 8e2fdee671 Fix de_DE translation for 'open' action (T1456) 8 years ago
Aleksander Machniak 16b6c8a0ce Fix missing min-height on ui-autocomplete lists (T1428) 8 years ago
Aleksander Machniak 93cb7b1fea Support contact+group searches in all relevant places (T1360)
Before the search worked only in Addressbook, not also in Compose.
The point of the change is also to align group searches with contact searches
in that it now uses the same set of attributes. Previously groups
in Compose were searched by name only.

Conflicts:

	program/lib/Roundcube/rcube_addressbook.php
	program/lib/Roundcube/rcube_contacts.php
	program/steps/mail/search_contacts.inc
8 years ago
Aleksander Machniak 3f10f9a2e6 Fix regression where LDAP results could be counted incorrectly when using VLV
... broken by d08bd0a51f where we added searching in users+groups in one request
8 years ago
Aleksander Machniak a647f994d8 Fix typo in de_DE localization (T1398) 8 years ago
Aleksander Machniak 264dfbbf82 Update changelog 8 years ago
Aleksander Machniak 425e31dc27 Wash position:fixed style in HTML mail for better security (#5264) 8 years ago
Aleksander Machniak b2781e145e Fix German localization label 8 years ago
Aleksander Machniak 4fa70856b9 Fix handling of blockquote tags with mixed case on html2text conversion (#5363)
Conflicts:
	CHANGELOG
8 years ago
Aleksander Machniak d10c591a61 Merge pull request #5330 from urc/patch-1
Do not mask fatal error when unable to load PEAR class
8 years ago
Aleksander Machniak 25510199be Don't create multipart/alternative messages with empty text/plain part (#5283)
Conflicts:
	CHANGELOG
	program/steps/mail/sendmail.inc
8 years ago
Thomas Bruederli f1d80c649e Avoid sending completely empty text parts for multipart/alternative messages (#5283) 8 years ago
Aleksander Machniak fbf89913a3 Fix missing localization of HTML editor when assets_dir != INSTALL_PATH
Conflicts:
	CHANGELOG
8 years ago
Aleksander Machniak 72a09408e9 Use contact_search_name format in popup on results in compose contacts search
Conflicts:

	CHANGELOG
	program/steps/mail/search_contacts.inc
8 years ago
dsoares f85227358a Avoid PHP fatal error
After last change to file `rcube_ldap.php`, my roundcube instance was getting this error:
```
PHP Fatal error:  Cannot use object of type Net_LDAP3_Result as array in ...
```
In
```php
protected function extended_search($count = false)
```
`$result = $this->ldap->search()` returns a LDAP object (whatever package we use).
If the search returns no results (and if `$is_extended_search` is false), then it gets to line 971 trying to do a `usort()` and then a `count()` on an object, instead of an array.
8 years ago
Aleksander Machniak 194690f59b Add managesieve plugin documentation 8 years ago
Aleksander Machniak ac592fd169 Searching in both contacts and groups when LDAP addressbook with group_filters option is used
Conflicts:

	CHANGELOG
	program/steps/addressbook/search.inc
8 years ago
urc 3e508e9587 Do not mask fatal error
A failure to load PEAR consistutes a fatal PHP error, and @-loading it prevents that error from being logged, making debugging problems with loading the PEAR class really difficult. It should therefore be loaded without the @ sign, allowing the fatal error to end up in the logs, if it occurs.
8 years ago
Aleksander Machniak e48f8945b3 Fix bug where message list columns could be in wrong order after column drag-n-drop and list sorting
Conflicts:
	CHANGELOG
8 years ago
Aleksander Machniak 73f411db7d Add missing sigbelow label in german localizations 8 years ago
Aleksander Machniak 7d14065baa Fix XSS issue in href attribute on area tag (#5240, #5241)
Conflicts:

	CHANGELOG
8 years ago
Aleksander Machniak 877b911dc4 Fix bug where contact search menu fields where always unchecked in Larry skin
Conflicts:

	CHANGELOG
8 years ago
Aleksander Machniak 550143269a Fix message list multi-select/deselect issue (#5219)
Conflicts:

	CHANGELOG
8 years ago
Thomas Bruederli 25bc871ee7 Bump version to 1.1.5 8 years ago
Aleksander Machniak ead0846934 Plugin API: Add html2text hook (backport from master) 8 years ago
Aleksander Machniak 848410042c Fix converting mail addresses with @www. into mailto links (#5197) 8 years ago
Aleksander Machniak c91d4975ff Make sure an email address is valid when replacing it with mailto: link 8 years ago
Aleksander Machniak d54eb6c951 CS fixes 8 years ago
Bostjan Skufca 55d90b2f62 mailbox/listing: Make server response for large mailbox listing faster when using threaded view
Symptom
=======
When using roundcube with mailboxes with over 60k messages, list
view was way faster than viewing in threaded view.

Mailbox index view timing:    ~360 ms
Mailbox threaded view timing: ~800 ms

Resolution
==========
Use native PHP array manipulation functions instead of rolling custom
string data reversal implementation using strpos() and substr() in a
'while' loop.

This optimization is already present in index view handler, but was missing
from threaded view.

Results after optimization
==========================
Both average out around ~360 ms response time.
8 years ago
Thomas Bruederli e1ae200201 Transliterate ticket IDs after migration to Github issues 8 years ago
Aleksander Machniak 473dc0b86d Fix so SPECIAL-USE assignments are forced only until user sets special folders (#4782)
The old behaviour where SPECIAL-USE has always a prio can be bringed back
by setting lock_special_folders=false and adding it to dont_override.
8 years ago
Aleksander Machniak b99a1bce89 Use pear repository via secure channel 8 years ago
Aleksander Machniak 86bc1f95ea Require Net_Socket >= 1.0.12 (because of timeout=0 bugfix)
Conflicts:
	INSTALL
8 years ago
Aleksander Machniak 2bfce1ae20 Refer to Github issues instead of Trac 8 years ago
Thomas Bruederli 066b205c72 Refer to Github issues instead of Trac 8 years ago
Aleksander Machniak 7c04110698 Fix so contactlist_fields option can be set via config file 8 years ago
Aleksander Machniak 4d3f055ce0 Refactor desktop notifications
- Remove webkitNotifications support, clean up the code
- Unify look and behaviour of notifications in Mail and in Settings

Conflicts:

	plugins/newmail_notifier/newmail_notifier.js
8 years ago
Aleksander Machniak 126d099e83 Fix PHP warning when defaults.inc.php is not readable 8 years ago
Aleksander Machniak 160013555f Update changelog 8 years ago
Thomas Bruederli 699af1e520 Protect download urls against CSRF using unique request tokens (#1490642)
Send X-Frame-Options headers with every HTTP response

Conflicts:
	plugins/enigma/enigma.js
	plugins/enigma/lib/enigma_ui.php
	program/lib/Roundcube/rcube_message.php
8 years ago
Aleksander Machniak b01689caf8 Hide DSN option in Preferences when smtp_server is not used (#1490666) 8 years ago
Aleksander Machniak 7a73635214 Fix unicode-awareness of Base64 encoding implementation in javascript 8 years ago
Aleksander Machniak 58c03846e7 Fix list row selection when provided uid is number not a string 8 years ago
Aleksander Machniak d66793f0af Fix missing emoticons on html-to-text conversion 8 years ago
Aleksander Machniak f915d15c43 Bring back additional_message_headers compatibility with Mail_Mime < 1.9 8 years ago
Aleksander Machniak c8023ac6b1 Fix additional_message_headers plugin compatibility with Mail_Mime >= 1.9 (#1490657) 8 years ago
Aleksander Machniak 8d047c668f Plugin API: Added addressbook_export hook 8 years ago
Aleksander Machniak 3e55a2d9cb Fix bug in long recipients list parsing for cases where recipient name contained @-char (#1490653) 8 years ago
Aleksander Machniak a2d5db0a98 Fix bug where Archive/Junk buttons were not active after page jump with select=all mode (#1490647) 8 years ago
Aleksander Machniak d3b98eb4dc Fix (again) security issue in DBMail driver of password plugin [CVE-2015-2181] (#1490643)
Unify the C program code with the one used by other drivers.

Conflicts:
	CHANGELOG
8 years ago
Aleksander Machniak 4de4438340 Fix regression where xml mode could be used to parse xhtml messages causing empty result 8 years ago
Aleksander Machniak 768e3e1b09 Improved SVG cleanup code 8 years ago
Aleksander Machniak 847c771d9e Refactor wash_attribs() - fix regressions 8 years ago
Aleksander Machniak 3e4b7cd19d Extend rcube_washtml with SVG support 8 years ago
Aleksander Machniak 7bbefdb63b Fix XSS issue in SVG images handling (#1490625)
Conflicts:

	CHANGELOG
8 years ago
Aleksander Machniak 3f6fbdcc6d Fix random "access to this resource is secured against CSRF" message at logout (#1490641)
- this is when openssl module is not installed
8 years ago
Aleksander Machniak db76c50a7c Update ticket number 9 years ago
Francis Russell 8a53588940 Make TLS method for IMAP parameterisable. 9 years ago
Francis Russell f8911c2a7f Enable use of TLSv1.1 and TLSv1.2 for IMAP. 9 years ago
Aleksander Machniak fc5befff0f Fix missing language name in "Add to Dictionary" request in HTML mode (#1490634)
Conflicts:

	CHANGELOG
9 years ago
Thomas Bruederli 772e08fa2a Fix mail view scaling on iOS (#1490551) 9 years ago
Thomas Bruederli f2ff464002 Bump version to 1.1.4; update Changelog 9 years ago
Aleksander Machniak ded453cdc4 Fix .htaccess rewrite rules to not block .well-known URIs (#1490615)
Conflicts:

	.htaccess
	CHANGELOG
9 years ago
Aleksander Machniak 7d0099f28e Fix so drag-n-drop of text (e.g. recipient addresses) on compose page actually works (#1490619)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak 89a5dcb946 Fix path traversal vulnerability in setting a skin (#1490620)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak 9fbabc4668 Add INBOX to the list of folders only if no filter and no prefix was specified 9 years ago
Aleksander Machniak c67e7e8f85 Fix PDF support detection in Firefox > 19 (#1490610)
Conflicts:
	CHANGELOG
9 years ago
Aleksander Machniak c82d09a052 Fix handling of message/rfc822 attachments on replies and forwards (#1490607)
Conflicts:

	CHANGELOG
	program/lib/Roundcube/rcube_message.php
	program/steps/mail/compose.inc
9 years ago
Aleksander Machniak 6e71c958fc Fix also charset encoding of message/rfc822 part bodies (#1490606) 9 years ago
Aleksander Machniak 2382c6e822 Fix regression in displaying contents of message/rfc822 parts (#1490606)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak b6b92c0ddd Optionally throw 404 error when contact photo wasn't found 9 years ago
Aleksander Machniak 5143c47e0f Fix rcube_utils::words_match() to work with mixed/invalid/binary content (T844) 9 years ago
Aleksander Machniak 818b78a893 Fix invalid LDAP query in ACL user autocompletion (#1490591) 9 years ago
Aleksander Machniak 78a9870e00 Remove redundant .gitignore files 9 years ago
Thomas Bruederli 62ee427b7e Improve directory protection for Apache 2.4 9 years ago
Aleksander Machniak 9953d5c10c Add workaround for https://bugs.php.net/bug.php?id=70757 (#1490582) 9 years ago
Aleksander Machniak c7c09f85d9 Fix HTML sanitizer to skip <!-- node type X --> in output (#1490583) 9 years ago
Aleksander Machniak 2c3634df04 Update changelog 9 years ago
Aleksander Machniak 8e7f32fddc Small improvements in HTML to text conversion.
Better handling of <body> and trailing spaces, and </p><div> or <br><div>.
9 years ago
Aleksander Machniak 9e808942ba Update changelog 9 years ago
Aleksander Machniak a04a16c285 Make sure list page is never set to 0 (#1490458)
This should fix the issue where after message move wrong message was
added to the list and the list counter was invalid.
9 years ago
Aleksander Machniak 72be74508f Fix redundant blank lines when using HTML and top posting (#1490576) 9 years ago
Aleksander Machniak 6ee039e10e Bump Net_SMTP version in composer config (#1490569) 9 years ago
Aleksander Machniak 5de338e45e Update changelog 9 years ago
Aleksander Machniak 70942083ce After failed login wait a second to slow down brute-force attacks (#1490549) 9 years ago
Aleksander Machniak 280395a544 Fix bug where HTML messages with invalid/excessive css styles couldn't be displayed (#1490539)
Technically speaking we remove the whole CSS content when it has more than 5k lines.
9 years ago
Aleksander Machniak c5acbc6c94 Fix bug where message preview was unintentionally reset on check-recent action (#1490563) 9 years ago
Aleksander Machniak 5e6f6ac539 Fix responses list update issue after response name change (#1490555) 9 years ago
Aleksander Machniak ba48318e2c Fix so database_attachments::cleanup() does not remove attachments from other sessions (#1490542)
Conflicts:
	CHANGELOG
9 years ago
Aleksander Machniak 3d9798da1f Make brute force attacks harder by re-generating security token on every failed login (#1490549)
Or more precissely use the same we did in git-master, i.e. do not base the token on
session ID, but use random bytes instead.
9 years ago
Aleksander Machniak 7d9a29cbc0 Remove also old .htaccess file that is not used anymore (#1489980) 9 years ago
Aleksander Machniak c2269df436 Require PHP5 9 years ago
Aleksander Machniak 0596f79a18 Require PHP5 9 years ago
Aleksander Machniak 357cd5103d Fix issue where Content-Length of some attachments could be set to wrong value causing browser errors (#1490482) 9 years ago
Aleksander Machniak 6731d2116c Fix XSS issue in drag-n-drop file uploads (#1490530) 9 years ago
Aleksander Machniak 73d98c4766 Fix missing HTTP_X_FORWARDED_FOR address in generated Received header 9 years ago
Aleksander Machniak 9f98332240 Fix so In-Reply-To header is set also for MDN receipts (#1490523) 9 years ago
Aleksander Machniak bbef212b0e Fallback to C locale 9 years ago
Aleksander Machniak 7bfe676d53 Fix various issues with Turkish (and similar) locales (#1490519) 9 years ago
Aleksander Machniak ac3078fe93 Fix support for Mozilla-based browsers, e.g. Pale Moon (#1490517) 9 years ago
Aleksander Machniak 03be470538 Fix so gc.sh script removes also expired sessions from sql database (#1490512) 9 years ago
Aleksander Machniak 52b75f2506 Fix so adding CC/BCC recipients from the sidebar unhides compose form fields in Classic skin (#1490472) 9 years ago
Aleksander Machniak 8ef86f5253 Fix handling of plus character in mailto: links (#1490510) 9 years ago
Aleksander Machniak b9bbc69ddc Fix typo 9 years ago
Aleksander Machniak 5f10f13472 Fix so css of one html part does not apply to other text parts on message display (#1490505) 9 years ago
Thomas Bruederli 106d47992b Bump version and update changelog 9 years ago
Thomas Bruederli 27e02f0f3b Fix closing of nested menus (#1490443) 9 years ago
Aleksander Machniak 8a2d5561b6 Fix dependencies version numbers where ~ is used
Conflicts:

	composer.json-dist
9 years ago
Aleksander Machniak 1e15c50e87 Lock dependencies versions
Conflicts:

	composer.json-dist
9 years ago
Aleksander Machniak 6564cf8a4b Change code so versions of Mail_mime before and after 1.9.0 are supported
Conflicts:
	program/lib/Roundcube/rcube.php
9 years ago
Aleksander Machniak dddc985ce2 Make Mail_mime>=1.9.0 a requirement, fix compat. errors
Conflicts:
	composer.json-dist
9 years ago
Aleksander Machniak 495b5c3883 Don't display not-sent-warning in compose page on save-pref action 9 years ago
Aleksander Machniak b45b15e5a8 Fix selecting a folder on collapse when any subfolder is selected 9 years ago
Aleksander Machniak 794b2f1d46 Really make base64 encoding unicode-aware 9 years ago
Aleksander Machniak b44a6554bb Fix base64.encode/decode for unicode characters - use fallback if btoa/atob functions fail 9 years ago
Aleksander Machniak 14693832b2 Fix so input field (e.g. search box) does not loose focus on list load (#1490455) 9 years ago
Aleksander Machniak ca7fc75bec Fix "washing" of style elements wrapped into many lines 9 years ago
Thomas Bruederli 8b26f548b5 Add localization alias for tr => tr_TR 9 years ago
Aleksander Machniak f3c12bf7ef Get rid of Mail_mimeDecode package dependency (#1490416)
Conflicts:

	CHANGELOG
	composer.json-dist
9 years ago
Aleksander Machniak eddae8976d Disable links list generation on html-to-text conversion of identities or composed message (#1490437) 9 years ago
Aleksander Machniak b45e9b49b9 Fix removing signature when switching to identity with an empty sig in HTML mode (#1490470) 9 years ago
Aleksander Machniak 1172330b2a Fix error when using back button after sending an email (#1490009) 9 years ago
Aleksander Machniak 0e647e4aa0 Don't use private properties of Net_SMTP object 9 years ago
Aleksander Machniak 468e61b264 Fix some javascript errors in rare situations (#1490441) 9 years ago
Aleksander Machniak 9ca27756f1 Fix wrong positioning of message list header on page scroll in Webkit browsers (#1490035)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak fe82e213c3 Fix so E_DEPRECATED errors from PEAR libs are ignored by error_reporting change (#1490281) 9 years ago
Aleksander Machniak 424c25e5bc Fix bug where new messages weren't added to the list in search mode 9 years ago
Aleksander Machniak 844ee296a8 Revert create_folder() behaviour change where the method didn't fail if folder already existed.
This should not be the default behaviour. It could likely
become an optional functionality, however we should keep the method simple.
9 years ago
Aleksander Machniak f0feb7701e Use in_array_nocase() also for \\Noselect flag check (#1490466) 9 years ago
Aleksander Machniak 19a61851ae Fix so imap folder attribute comparisons are case-insensitive (#1490466)
+ make in_array_nocase() much faster for ASCII strings
9 years ago
Aleksander Machniak 71bfa5f207 Fix draft removal after a message is sent and storing sent message is disabled (#1490467) 9 years ago
Aleksander Machniak 612b04ac30 Reset internal cache index in close()
Conflicts:

	program/lib/Roundcube/rcube_cache.php
	program/lib/Roundcube/rcube_cache_shared.php
9 years ago
Aleksander Machniak 895efa1d42 Fix bug where some messages in multi-folder search couldn't be printed/downloaded (#1490426)
Conflicts:

	program/js/app.js
9 years ago
Aleksander Machniak 383749eeff Update to TinyMCE 4.1.10 (#1490405) 9 years ago
Aleksander Machniak a9035b1561 Fix so *-request@ addresses in Sender: header are also ignored on reply-all (#1490452)
Conflicts:
	program/steps/mail/compose.inc
9 years ago
Aleksander Machniak f7dd463174 Fix multi-folder search result sorting by arrival date (#1490450) 9 years ago
Aleksander Machniak 8cc6b18bcd Get rid of array_walk() when simple foreach() can be used 9 years ago
Aleksander Machniak 70422cd7a2 Fix Fatal error after last commit 9 years ago
Aleksander Machniak 947c4dc30b Fix issue when first search() argument is not an array 9 years ago
Thomas Bruederli c0087512aa Adapt washtml test to pass with different versions of iconv (i.e. on CentOS7) 9 years ago
Thomas Bruederli b91adb30a2 Adapt charset cleanup tests to pass with different versions of iconv propucing slightyl different output 9 years ago
Aleksander Machniak 0aadd71183 Fix self-reply detection issues (#1490439) 9 years ago
Aleksander Machniak 8e68430749 Fix handling of non-break spaces in html to text conversion (#1490436) 9 years ago
Aleksander Machniak 3a428d9571 Make has_(html|text)_part and first_(html|text)_part methods consistent in arguments and functionality 9 years ago
Aleksander Machniak 25c457dc68 Modify rcube_smtp::send_mail() so it is possible to send message by
specifying only the message stream no headers, it's for cases when
the stream already contains a complete message.
9 years ago
Aleksander Machniak fec877f038 Fix so links with href == content aren't added to links list on html to text conversion (#1490434) 9 years ago
Aleksander Machniak 3f4521bcf4 Fix so plain text signature field uses monospace font (#1490435) 9 years ago
Aleksander Machniak 92e36f6839 Fix race-condition in saving user preferences and loading plugin config (#1490431) 9 years ago
Aleksander Machniak 8cab554252 Fix unintentional messages list page change on page switch in compose addressbook (#1490427) 9 years ago
Aleksander Machniak e8028083b9 Fix bug where some messages in multi-folder search couldn't be opened (#1490426) 9 years ago
Aleksander Machniak 2ddd3b1a25 Update changelog 9 years ago
Aleksander Machniak cb0e0777ce Fix "PHP Fatal error: Using $this when not in object context" 9 years ago
Aleksander Machniak 30e71606a0 Fix Compose action in addressbook for results from multiple addressbooks (#1490413)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak 5eafc4b9d6 Update changelog 9 years ago
Aleksander Machniak ef07e9e546 Update to jQuery 2.1.4 (#1490406) 9 years ago
Aleksander Machniak d438147ddc Fix SQL error on logout when using session_storage=php (#1490421) 9 years ago
Aleksander Machniak 552854d738 Fix "Importing..." message does not hide on error (#1490422)
Conflicts:
	CHANGELOG
9 years ago
Daniel Hoffend 8fab64e594 remove debug test code 9 years ago
Thomas Bruederli a552b506da Fix composer.json update routine 9 years ago
Aleksander Machniak 15fd8f9dc7 Fix XSS vulnerability in _mbox argument handling (#1490417) 9 years ago
Aleksander Machniak 5529d94ed7 Installer: Use openssl_random_pseudo_bytes() (if available) to generate des_key (#1490402)
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak 4312ac809c Fix blank image in html_signature when saving identity changes (#1490412) 9 years ago
Aleksander Machniak a76693ef4c Fix replacing :$, :-$, O:) and O:-) with emoticons (#1490408, #1490409) 9 years ago
Thomas Bruederli 245619e98d Update localizations from Transifex 9 years ago
Thomas Bruederli 024de499e5 Updated Changelog 9 years ago
Thomas Bruederli f1ae19dc6b Bump version 9 years ago
Thomas Bruederli d8ffedbd5e Add new plugin hook 'identity_create_after' (#1490358) 9 years ago
Aleksander Machniak d5694ef84f Fix issues when using moduserprefs.sh without --user argument (#1490399)
Conflicts:

	program/include/rcmail_utils.php
9 years ago
Aleksander Machniak 4d97838ed9 Fix font artifacts in text2html conversion (#1490353)
Use white-space:nowrap elements instead of unicode word-joiner character
9 years ago
Aleksander Machniak 1f61e55a33 Fix attached file path unsetting in database_attachments plugin (#1490393) 9 years ago
Aleksander Machniak 84af0db103 Fix bug where some files could have "executable" extension when stored in temp folder (#1490377) 9 years ago
Aleksander Machniak b33c076d8c Fix bug where imap_conn_options were ignored in IMAP connection test (#1490392) 9 years ago
Aleksander Machniak 942b82a418 Fix bug where database_attachments_cache setting was not working 9 years ago
Aleksander Machniak 244a46fdea Fix missing index update after write() call 9 years ago
Aleksander Machniak 92459da0e2 Fix possible memcache/apc cache data consistency issues (#1490390)
And removed unused code

Conflicts:

	program/lib/Roundcube/rcube_cache.php
	program/lib/Roundcube/rcube_cache_shared.php
9 years ago
Aleksander Machniak a7d269253f Workaround possible issue where some keys were ignored when deleting cached entries
by key name prefix and keys index is in inconsistent state (does not contain all keys)
9 years ago
Thomas Bruederli 16640c7fb0 Add .htaccess files to deny access to config, temp, logs + describe how to protect access to these directories in the INSTALL instructions (#1490378) 9 years ago
Aleksander Machniak 1d024f37cc Fix mb_substitute_character() use 9 years ago
Aleksander Machniak 884070db68 Skip some tests on PHP 5.3.3 9 years ago
Aleksander Machniak 100780d837 Add some more tests for rcube_charset::clean() 9 years ago
Aleksander Machniak c084a6ab8b Fix rcube_charset::clean() for case when mbstring and iconv are not installed 9 years ago
Aleksander Machniak 04e767613d Fix failing rcube_utils::strtotime() test if system timezone was different than expected 9 years ago
Aleksander Machniak 4471b2bffb Fix security issue in contact photo handling (#1490379) 9 years ago
Thomas Bruederli b765160fd5 Improve LDAP search by ignoring words order in fuzzy substring matching mode 9 years ago
Thomas Bruederli 15bcfbd55f Add utility function to compose a full-text-like LDAP search filter 9 years ago
Aleksander Machniak 7310a6d66c Fix bug where messages count was not updated after message move/delete with skip_deleted=false (#1490372) 9 years ago
Aleksander Machniak 6efad5325d Fix typo in aria attribute name (#1490370) 9 years ago
Thomas Bruederli 9c24e1963a Switch repository URLs to https: 9 years ago
Aleksander Machniak 322186014c Bump up version number 9 years ago
Aleksander Machniak d0a4f1152e Add option to prepopulate vacation addresses on form init (#1490030) 9 years ago
Aleksander Machniak 4d35a983cc Fix bug where preview_pane setting wasn't always saved into user preferences (#1490362) 9 years ago
Aleksander Machniak 84dde88680 Fix decoding array headers 9 years ago
Aleksander Machniak 3a46e7defc Fix message highligh regression from last commit (#1490363) 9 years ago
Aleksander Machniak d3333df32b Trigger 'listupdate' event also on response to check-recent request 9 years ago
Aleksander Machniak 4315619cfe Update changelog 9 years ago
Aleksander Machniak 35a32df940 Fix mouseup event handling when dragging a list record (#1490359)
This fixes drag-n-drop on managesieve filters list.
9 years ago
Aleksander Machniak 0f797eddd8 Fix incorrect filter data after filter delete (#1490356)
Fix missing position idicator in Larry skin when dragging a filter
9 years ago
Aleksander Machniak 9dd3559ee4 Fix bug where some unrelated attachments in multipart/related message were not listed (#1490355) 9 years ago
Aleksander Machniak ef595a10e0 Add option to place signature at bottom of the quoted text even in top-posting mode [sig_below]
Conflicts:

	CHANGELOG
9 years ago
Thomas Bruederli 306bbba353 Update git url for kolab/Net_LDAP3 package repository 9 years ago
Aleksander Machniak 6188233705 Fix Net_LDAP3 homepage location 9 years ago
Aleksander Machniak 3d87a667b1 Add option to define default vacation interval 9 years ago
Aleksander Machniak 24f046cf47 Fix bug where forced extwin page reload could exit from the extwin mode (#1490350)
With small improvements in rcube_webmail.url() method.
9 years ago
Aleksander Machniak 22c0b291f6 Fix font artifact in Google Chrome on Windows (#1490353) 9 years ago
Aleksander Machniak 72863836e5 Fix handling spaces after <br> on html2text conversion 9 years ago
Aleksander Machniak 61c35b4a2b Fix lack of signature separator for plain text signatures in html mode (#1490352)
Conflicts:
	CHANGELOG
9 years ago
Aleksander Machniak 3832e4507b Fix so text/calendar parts are listed as attachments even if not marked as such (#1490325) 9 years ago
Aleksander Machniak d671bed7eb Fix message list header in classic skin on window resize in Internet Explorer (#1490213) 9 years ago
Aleksander Machniak b41140ba37 Fix tables listing routine on mysql and postgres so it skips system or other database tables and views (#1490337) 9 years ago
Aleksander Machniak 998afb1725 Remove Kolab's hack for Cyrus Murder bug in SETANNOTATION - it's not needed anymore 9 years ago
Aleksander Machniak fdcef5ef7e Fix PHP warning: Non-static method PEAR::setErrorHandling() should not be called statically (#1490343) 9 years ago
Aleksander Machniak 88578e27d5 Fix vpopmaild driver of password plugin 9 years ago
Aleksander Machniak 91ac83e82f Fix zipped messages downloads after selecting all messages in a folder (#1490339) 9 years ago
Aleksander Machniak 68f76fddbe Fix handling of %-encoded entities in mailto: URLs (#1490346)
Conflicts:

	CHANGELOG
9 years ago
Thomas Bruederli 6066619818 Allow help plugin to append a link to the error page for more information about CSRF protection 9 years ago
Thomas Bruederli d5b4ef0de2 Wording 9 years ago
Thomas Bruederli c7a88ff0c2 Localize common error messages; improve explanation for CSRF check failures 9 years ago
Thomas Bruederli 91d3545193 Lock PEAR Mail_mimeDecode at version 1.5.5 9 years ago
Thomas Bruederli 4ba89c9f99 Backport new utility function for compatibility reasons 9 years ago
Thomas Bruederli 2c0861495b Bump version for next release 9 years ago
Thomas Bruederli ee9742c873 Avoid errors when message list doesn't have a header 9 years ago
Aleksander Machniak f62fe135bf Fix missing host:port in connection error message 9 years ago
Aleksander Machniak 979f08e4df Fix javascripts errors in IE8 - lack of Event.which, focusing a hidden element (#1490318) 9 years ago
Thomas Bruederli 791c66c5fb Do not re-append an existing node when re-rendering with childs 9 years ago
Thomas Bruederli d9e854ccfe Update Changelog 9 years ago
Thomas Bruederli bb345b4b4b Fix menu container references to point to the actual <ul> element (#1490313) 9 years ago
Thomas Bruederli b50ae45698 Update Changelog 9 years ago
Thomas Bruederli c14c21472e Fix redirct URL for attachments loaded in an iframe (#1490191) 9 years ago
Thomas Bruederli 70f47ffc0b Update Changelog 9 years ago
Thomas Bruederli 1aa49741b2 Give other plugins the opportunity to adjust the list of permissions and groups to edit 9 years ago
Thomas Bruederli edabce3091 Make ACL popups scale to the actual content and avoid scrolling if possible 9 years ago
Aleksander Machniak 00a1759129 Fix handling of header test with one-element array as header name 9 years ago
Thomas Bruederli 7ba82e0992 Update Changelog 9 years ago
Thomas Bruederli 3e09bcdef0 Generate random hash for the per-user local storage prefix (#1490279); only unserialize user prefs once 9 years ago
Aleksander Machniak 8f74b23dd2 Fix backtick character handling in sql queries (#1490312) 9 years ago
Thomas Bruederli 50e1ca2814 Fix submission of _reload parameter when switching address books 9 years ago
Aleksander Machniak b9f8bb3cab Fix bug where TinyMCE area height was too small on slow network connection (#1490310) 9 years ago
Aleksander Machniak 6855623cf5 Fix bug where spellchecking in HTML editor do not work after switching editor type more than once (#1490311) 9 years ago
Aleksander Machniak 5c74c978f8 Update TinyMCE cache_suffix (forgot to do this after last update) 9 years ago
Aleksander Machniak 2d5b35eb5b Upgrade TinymCE to version 4.1.9 9 years ago
Aleksander Machniak ef09b2751b Fix rows count when messages search fails (#1490266) 9 years ago
Aleksander Machniak 2ea55829be (Properly) reset search filter on reset-search action 9 years ago
Aleksander Machniak 1e7c877a66 Reset search filter on folder selection and search reset 9 years ago
Aleksander Machniak 100fea325e Unified request* event arguments handling, added support for _unlock and _action parameters 9 years ago
Aleksander Machniak 5bdd767a48 Fix so search filter, scope and fields are reset on folder change 9 years ago
Aleksander Machniak c13dd984e1 Fix Opera browser detection in javascript (#1490307) 9 years ago
Aleksander Machniak 6d876a3b54 Fix storing signatures with big images in MySQL database (#1490306) 9 years ago
Aleksander Machniak 26c9930103 get_part_content() -> get_part_body() 9 years ago
Aleksander Machniak d8efe06f4c Update to TinyMCE 4.1.8 9 years ago
Aleksander Machniak c861ba15fe Fix missing vcard_attachment icon on messages list (#1490303) 9 years ago
Aleksander Machniak e14e631947 Update changelog 9 years ago
Aleksander Machniak 14f4633b0b Remove redundant encoding of message subject with mb_encode_mimeheader() (#1490295) 9 years ago
Aleksander Machniak d093e96ec2 Fix javascript error after creating a folder which is a subfolder of another one (#1490297) 9 years ago
Aleksander Machniak 199446c16d Fix so localized folder name is displayed in multi-folder search result (#1490243) 9 years ago
Aleksander Machniak 9613687428 Fix "Add response" button title, remove wrong identities_level checks in Responses, fix cursor on some lists 9 years ago
Aleksander Machniak df4243b80a Fix duplicate entry on timezones list in rcube_config::timezone_name_from_abbr() (#1490293) 9 years ago
Aleksander Machniak c4104166e3 Update changelog 9 years ago
Aleksander Machniak 5bb2fe27a0 Fix parsing ldap URI for cases where hostname is non-empty 9 years ago
Aleksander Machniak b7048d8d2d Fix parsing invalid HTML messages with BOM after <!DOCTYPE> (#1490291) 9 years ago
Aleksander Machniak 2799f049bb Fix "Non-static method PEAR::isError() should not be called statically" errors (#1490281) 9 years ago
Aleksander Machniak ab84cc15e5 Reset default db_max_allowed_packet, fix max packet size detection 9 years ago
Aleksander Machniak f985cbedc6 Fix duplicate entries supression in autocomplete result (#1490290) 9 years ago
Aleksander Machniak f129972361 Improve compose_search_name() to not return "email@address <email@address>" entries
which may happen for contacts without name(s)
9 years ago
Aleksander Machniak b56a3b00f0 Don't sent the message again in saveonly mode 9 years ago
Aleksander Machniak 16c326380d Improved handling of storage errors after message is sent
After sending a message it is stored in Sent folder, this operation
may fail, e.g. because of "over quota" error. In such a case we'll
not close the compose window, but display the error and, if user clicks
Send/Save button, we'll display a dialog informing about the situation and
providing an option to try the save operation again.
9 years ago
Aleksander Machniak bbbd02bd6a Fix so "over quota" errors are displayed also in message compose page
This also fixes over quota responses on cyrus imap which uses "Over quota" string and no error identifier.
9 years ago
Thomas Bruederli 230ec1104f Update internal reference to treelist node contents after insert. Fixes some strange behavior in FF 3.6 9 years ago
Aleksander Machniak 44f58b0bcb Add possibility to configure max_allowed_packet value for all database engines (#1490283) 9 years ago
Aleksander Machniak cd8bcf3801 Fix "PHP Fatal error: Call to a member function getMessage() on a non-object" 9 years ago
Aleksander Machniak 1cb0b1481d Use also Organization field as a fallback if contact has no name(s) specified 9 years ago
Aleksander Machniak 366ffd7aa0 Fix typo 9 years ago
Aleksander Machniak ce08e08dad Fix cursor position on reply below the quote in HTML mode (#1490263)
Also other cursor position inconsistency. Additionally fixed
invisible cursor in HTML editor in older Firefox browser versions.
9 years ago
Thomas Bruederli 39434509cd Describe Composer installation when upgrading from a < 1.1 version 9 years ago
Aleksander Machniak 9e147a36ad Fix fatal errors on systems without mbstring extension or mb_regex_encoding() function (#1490280) 9 years ago
Aleksander Machniak 334eb48cfe Merge branch 'release-1.1' of github.com:roundcube/roundcubemail into release-1.1
Conflicts:
	CHANGELOG
9 years ago
Aleksander Machniak 99dafc41a3 Fix missing or not up-to-date CATEGORIES entry in vCard export (#1490277)
Conflicts:
	CHANGELOG
9 years ago
Aleksander Machniak bec8735d66 Display group icon on group entry in ACL autocomplete list 9 years ago
Aleksander Machniak c8468c2960 Really fix unwanted warning on BMP attachments (#1490269) 9 years ago
Aleksander Machniak 825b2b9ab9 Fix performance of rcube_db_mysql::get_variable()
As currently we're using this to find only max_allowed_packet value,
it is better to use "SHOW VARIABLES LIKE ?" instead of asking for all variables.
9 years ago
Aleksander Machniak ca85a8e32c Fix handling of some improper constructs in format=flowed text as per the RFC3676[4.5] (#1490284) 9 years ago
Aleksander Machniak afd5e4f8a9 Fix needless security warning on BMP attachments display (#1490282) 9 years ago
Aleksander Machniak dab95db19c Fix setting max packet size for DB caches and check packet size also in shared cache
Conflicts:

	CHANGELOG
9 years ago
Aleksander Machniak c8aa7a2048 Update changelog 9 years ago
Aleksander Machniak cd51e611ff Fix saving/sending emoticon images when assets_dir is set (Kolab #4608) 9 years ago
Aleksander Machniak 9a833f6faa Fix PHP fatal error when visiting Vacation interface and there's no sieve script yet 9 years ago
Aleksander Machniak 9920097bfc Add possibility to print contact information (of a single contact) 9 years ago
Aleksander Machniak 2839caa7e7 Fix regression where Help toolbar buttons have had incorrect title 9 years ago
Aleksander Machniak 9ed3c429eb Fix a regression where some contact data was missing in export and PHP warnings were logged (Kolab #4522) 9 years ago

@ -1,30 +0,0 @@
<?php
$config = array();
// Database configuration
$config['db_dsnw'] = 'sqlite:////tmp/sqlite.db?mode=0646';
// Test user credentials
$config['tests_username'] = 'test';
$config['tests_password'] = 'test';
// GreenMail
$config['smtp_port'] = 25;
// Settings required by the tests
$config['create_default_folders'] = true;
$config['skin'] = 'elastic';
$config['support_url'] = 'http://support.url';
// Plugins with tests
$config['plugins'] = [
'archive',
'attachment_reminder',
'markasjunk',
'zipdownload'
];
$config['archive_mbox'] = 'Archive';

@ -1,22 +0,0 @@
#!/bin/bash
# The script is intended for use on Travis with Trusty distribution
DIR=$(dirname $0)
# Enable xdebug for code coverage
if [ "$CODE_COVERAGE" != 1 ]; then phpenv config-rm xdebug.ini || true; fi
cd $DIR/..
cp composer.json-dist composer.json
# Add laravel/dusk for Browser tests
if [ "$BROWSER_TESTS" = 1 ]; then composer require "laravel/dusk:~5.9.1" --no-update; fi
# Remove qr-code as it requires php-gd which is not always available on Travis
# and we don't really need it for tests
composer remove endroid/qr-code --no-update
# Install PHP dependencies
composer install --prefer-dist

@ -1,25 +0,0 @@
#!/bin/bash
# The script is intended for use on Travis with Trusty distribution
# It executes unit and functional tests
DIR=$(dirname $0)
cd $DIR/..
if [ "$CODE_COVERAGE" = 1 ]
then
CODE_COVERAGE_ARGS="--coverage-text"
fi
vendor/bin/phpunit -c tests/phpunit.xml $CODE_COVERAGE_ARGS
if [ "$BROWSER_TESTS" = 1 ] && [ $? = 0 ]
then
.ci/setup.sh \
&& echo "TESTS_MODE: DESKTOP" \
&& TESTS_MODE=desktop vendor/bin/phpunit -c tests/Browser/phpunit.xml \
&& echo "TESTS_MODE: PHONE" \
&& TESTS_MODE=phone vendor/bin/phpunit -c tests/Browser/phpunit.xml \
&& echo "TESTS_MODE: TABLET" \
&& TESTS_MODE=tablet vendor/bin/phpunit -c tests/Browser/phpunit.xml
fi

@ -1,30 +0,0 @@
#!/bin/bash
# The script is intended for use on Travis with Trusty distribution
# It installs in-browser tests dependencies and prepares Roundcube instance
GMV=1.5.11
CHROMEVERSION=$(google-chrome-stable --version | tr -cd [:digit:]. | cut -d . -f 1)
GMARGS="-Dgreenmail.setup.all -Dgreenmail.users=test:test -Dgreenmail.startup.timeout=3000"
# Roundcube tests and instance configuration
cp .ci/config-test.inc.php config/config-test.inc.php
# Make temp and logs writeable
sudo chmod 777 temp logs
# Install javascript dependencies
bin/install-jsdeps.sh
# Compile Elastic's styles
lessc skins/elastic/styles/styles.less > skins/elastic/styles/styles.css
lessc skins/elastic/styles/print.less > skins/elastic/styles/print.css
lessc skins/elastic/styles/embed.less > skins/elastic/styles/embed.css
# Install proper WebDriver version for installed Chrome browser
php tests/Browser/install.php $CHROMEVERSION
# GreenMail server download, setup and start
wget https://repo1.maven.org/maven2/com/icegreen/greenmail-standalone/$GMV/greenmail-standalone-$GMV.jar \
&& (sudo java $GMARGS -jar greenmail-standalone-$GMV.jar &) \
&& sleep 5

8
.gitignore vendored

@ -13,11 +13,3 @@ composer.json
composer.phar
composer.lock
vendor
# javascript dependencies
plugins/enigma/openpgp.min.js
plugins/managesieve/codemirror/
program/js/jquery.min.js
program/js/jstz.min.js
program/js/publickey.js
program/js/tinymce/

@ -1,24 +1,52 @@
# This is a sample with suggested security and performance options
# AddDefaultCharset UTF-8
AddType text/x-component .htc
<IfModule mod_php5.c>
php_flag display_errors Off
php_flag log_errors On
# php_value error_log logs/errors
php_value upload_max_filesize 5M
php_value post_max_size 6M
php_value memory_limit 64M
php_flag register_globals Off
php_flag zlib.output_compression Off
php_flag magic_quotes_gpc Off
php_flag magic_quotes_runtime Off
php_flag suhosin.session.encrypt Off
#php_value session.cookie_path /
php_flag session.auto_start Off
php_value session.gc_maxlifetime 21600
php_value session.gc_divisor 500
php_value session.gc_probability 1
</IfModule>
<IfModule mod_rewrite.c>
Options +SymLinksIfOwnerMatch
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^favicon\.ico$ skins/larry/images/favicon.ico
# security rules:
# - deny access to files not containing a dot or starting with a dot
# in all locations except installer directory
RewriteRule ^(?!installer|\.well-known\/|[a-zA-Z0-9]{16})(\.?[^\.]+)$ - [F]
RewriteRule ^(?!installer|\.well-known\/|[a-f0-9]{16})(\.?[^\.]+)$ - [F]
# - deny access to some locations
RewriteRule ^/?(\.git|\.tx|SQL|bin|config|logs|temp|tests|vendor|program\/(include|lib|localization|steps)) - [F]
RewriteRule ^/?(\.git|\.tx|SQL|bin|config|logs|temp|tests|program\/(include|lib|localization|steps)) - [F]
# - deny access to some documentation files
RewriteRule /?(README.*|meta\.json|composer\..*|jsdeps.json)$ - [F]
RewriteRule /?(README\.md|composer\.json-dist|composer\.json|package\.xml|Dockerfile)$ - [F]
</IfModule>
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
</IfModule>
<IfModule mod_headers.c>
# replace 'append' with 'merge' for Apache version 2.2.9 and later
#Header append Cache-Control public env=!NO_CACHE
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
@ -28,42 +56,4 @@ FileETag MTime Size
<IfModule mod_autoindex.c>
Options -Indexes
</IfModule>
<IfModule mod_headers.c>
# Disable page indexing
Header set X-Robots-Tag "noindex, nofollow"
# replace 'merge' with 'append' for Apache < 2.2.9
#Header merge Cache-Control public env=!NO_CACHE
# Optional security headers
# Only provides increased security if the browser supports those features
# Be careful! Testing is required! They should be adjusted to your installation / user environment
# HSTS - HTTP Strict Transport Security
#Header always set Strict-Transport-Security "max-age=31536000; preload" env=HTTPS
# HPKP - HTTP Public Key Pinning
# Only template - fill with your values
#Header always set Public-Key-Pins "max-age=3600; report-uri=\"\"; pin-sha256=\"\"; pin-sha256=\"\"" env=HTTPS
# X-Xss-Protection
# This header is used to configure the built in reflective XSS protection found in Internet Explorer, Chrome and Safari (Webkit).
#Header set X-XSS-Protection "1; mode=block"
# X-Frame-Options
# The X-Frame-Options header (RFC), or XFO header, protects your visitors against clickjacking attacks
# Already set by php code! Do not activate both options
#Header set X-Frame-Options SAMEORIGIN
# X-Content-Type-Options
# It prevents Google Chrome and Internet Explorer from trying to mime-sniff the content-type of a response away from the one being declared by the server.
#Header set X-Content-Type-Options: "nosniff"
# CSP - Content Security Policy
# for better privacy/security ask browsers to not set the Referer
# more flags for script, stylesheets and images available, read RFC for more information
# Note: "Referrer-Policy: same-origin" is already set by php code.
#Header set Content-Security-Policy "referrer no-referrer"
</IfModule>
</ifModule>

@ -1,37 +0,0 @@
language: php
dist: trusty #
sudo: false
matrix:
fast_finish: true
include:
- php: 5.4
- php: 5.5
- php: 5.6
- php: 7.0
- php: 7.1
env: CODE_COVERAGE=1
- php: 7.2
- php: 7.3
dist: bionic # for proper node-less version
env: BROWSER_TESTS=1
addons:
chrome: stable
apt:
packages:
- node-less
- php: 7.4
cache:
directories:
- $HOME/.composer
install:
- .ci/install.sh
script:
- .ci/run.sh
notifications:
email: false

@ -13,11 +13,6 @@ file_filter = program/localization/<lang>/messages.inc
source_file = program/localization/en_US/messages.inc
source_lang = en_US
[roundcube-webmail.timezones]
file_filter = program/localization/<lang>/timezones.inc
source_file = program/localization/en_US/timezones.inc
source_lang = en_US
[roundcube-webmail.plugin-acl]
file_filter = plugins/acl/localization/<lang>.inc
source_file = plugins/acl/localization/en_US.inc
@ -33,16 +28,6 @@ file_filter = plugins/attachment_reminder/localization/<lang>.inc
source_file = plugins/attachment_reminder/localization/en_US.inc
source_lang = en_US
[roundcube-webmail.plugin-emoticons]
file_filter = plugins/emoticons/localization/<lang>.inc
source_file = plugins/emoticons/localization/en_US.inc
source_lang = en_US
[roundcube-webmail.plugin-enigma]
file_filter = plugins/enigma/localization/<lang>.inc
source_file = plugins/enigma/localization/en_US.inc
source_lang = en_US
[roundcube-webmail.plugin-help]
file_filter = plugins/help/localization/<lang>.inc
source_file = plugins/help/localization/en_US.inc
@ -97,3 +82,4 @@ source_lang = en_US
file_filter = plugins/zipdownload/localization/<lang>.inc
source_file = plugins/zipdownload/localization/en_US.inc
source_lang = en_US

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
FROM debian:latest
MAINTAINER Alex Brandt <alunduil@alunduil.com>
EXPOSE 80 443
RUN apt-get -qq update
RUN apt-get install -qq apache2-mpm-event
RUN sed -e 's|/var/www|&/public_html|' -e 's/\(Log \+\)[^ ]\+/\1"|cat"/' -i /etc/apache2/sites-available/default
RUN a2ensite default
RUN sed -e 's|/var/www|&/public_html|' -e 's/\(Log \+\)[^ ]\+/\1"|cat"/' -i /etc/apache2/sites-available/default-ssl
RUN sed -e '/SSLCertificateKeyFile/s|ssl-cert-snakeoil.key|ssl-cert.key|' -e '/SSLCertificateFile/s|ssl-cert-snakeoil.pem|ssl-cert.pem|' -i /etc/apache2/sites-available/default-ssl
RUN ln -snf ssl-cert-snakeoil.pem /etc/ssl/certs/ssl-cert.pem
RUN ln -snf ssl-cert-snakeoil.key /etc/ssl/private/ssl-cert.key
RUN a2ensite default-ssl
RUN a2enmod expires
RUN a2enmod headers
RUN a2enmod ssl
RUN apt-get install -qq php5 php-pear php5-mysql php5-pgsql php5-sqlite
RUN pear install mail_mime mail_mimedecode net_smtp net_idna2-beta auth_sasl net_sieve crypt_gpg
RUN rm -rf /var/www
ADD . /var/www
RUN echo -e '<?php\n$config = array();\n' > /var/www/config/config.inc.php
RUN rm -rf /var/www/installer
RUN . /etc/apache2/envvars && chown -R ${APACHE_RUN_USER}:${APACHE_RUN_GROUP} /var/www/temp /var/www/logs
ENTRYPOINT [ "/usr/sbin/apache2ctl", "-D", "FOREGROUND" ]
CMD [ "-k", "start" ]

@ -3,60 +3,56 @@ INTRODUCTION
This file describes the basic steps to install Roundcube Webmail on your
web server. For additional information, please also consult the project's
wiki page at https://github.com/roundcube/roundcubemail/wiki
wiki page at http://trac.roundcube.net/wiki
REQUIREMENTS
============
* An IMAP, HTTP and SMTP server
* The Apache, Lighttpd, Cherokee or Hiawatha web server
* .htaccess support allowing overrides for DirectoryIndex
* PHP Version 5.4 or greater including:
- PCRE, DOM, JSON, Session, Sockets, OpenSSL, Mbstring, Filter, Ctype (required)
- PHP PDO with driver for either MySQL, PostgreSQL, SQL Server, Oracle or SQLite (required)
- Zip, Fileinfo, Intl, Exif (recommended)
- LDAP for LDAP addressbook support (optional)
- GD, Imagick (optional thumbnails generation, QR-code)
* PEAR and PEAR packages distributed with Roundcube or external:
- Mail_Mime 1.10.0 or newer
- Net_SMTP 1.8.1 or newer
* PHP Version 5.3.7 or greater (but not PHP 7) including
- PCRE, DOM, JSON, Session, Sockets (required)
- PHP Data Objects (PDO) with driver for either MySQL, PostgreSQL or SQLite (required)
- Libiconv, Zip (recommended)
- OpenSSL, Fileinfo, Mcrypt, mbstring (optional)
* PEAR packages distributed with Roundcube or external:
- Mail_Mime 1.9.0 or newer
- Net_SMTP 1.7.1 or newer
- Net_Socket 1.0.12 or newer
- Net_IDNA2 0.1.1 or newer
- Auth_SASL 1.0.6 or newer
- Net_Sieve 1.4.3 or newer (for managesieve plugin)
- Crypt_GPG 1.6.3 or newer (for enigma plugin)
- Endroid/QrCode 1.6.0 or newer (https://github.com/endroid/QrCode)
- Kolab/Net_LDAP3 1.0.6 or newer (for LDAP addressbook)
- Masterminds/HTML5 2.5.x (optional HTML parser)
* php.ini options:
- error_reporting E_ALL & ~E_NOTICE & ~E_STRICT
- memory_limit > 16MB
- file_uploads enabled (for uploading attachments and import files)
- Net_Sieve 1.3.2 or newer (for managesieve plugin)
- Crypt_GPG 1.2.0 or newer (for enigma plugin)
* php.ini options (see .htaccess file):
- error_reporting E_ALL & ~E_NOTICE (or lower)
- memory_limit > 16MB (increase as suitable to support large attachments)
- file_uploads enabled (for attachment upload features)
- session.auto_start disabled
- suhosin.session.encrypt disabled
- mbstring.func_overload disabled
- pcre.backtrack_limit >= 100000
* A MySQL, PostgreSQL, MS SQL Server (2005 or newer), Oracle database
or SQLite support in PHP - with permission to create tables
- magic_quotes_runtime disabled
- magic_quotes_sybase disabled
- register_globals disabled (PHP < 5.4)
* PHP compiled with OpenSSL to use secure (tls/ssl) connections and to use the spell checker
* A MySQL (4.0.8 or newer), PostgreSQL, MS SQL Server (2005 or newer) database engine
or SQLite support in PHP
* One of the above databases with permission to create tables
* An SMTP server (recommended) or PHP configured for mail delivery
* Composer installed either locally or globally (https://getcomposer.org)
INSTALLATION
============
1. Decompress and put this folder somewhere inside your document root.
Note: Make sure files have proper owner/group for your setup. If you use
tar command `--no-same-owner` option might be helpful.
2. In case you don't use the so-called "complete" release package,
you have to install PHP and javascript dependencies.
2.1. Install PHP dependencies using composer:
- get composer from https://getcomposer.org/download/
- rename the composer.json-dist file into composer.json
- if you want to use LDAP address books, enable the LDAP libraries in your
composer.json file by moving the items from "suggest" to the "require"
section (remove the explanation texts after the version!).
- run `php composer.phar install --no-dev`
2.2. Install Javascript dependencies by executing `bin/install-jsdeps.sh` script.
1. Decompress and put this folder somewhere inside your document root
2. Install dependencies using composer:
- get composer from https://getcomposer.org/download/
- rename the composer.json-dist file into composer.json
- if you want to use LDAP address books, enable the LDAP libraries in your
composer.json file by moving the items from "suggest" to the "require"
section (remove the explanation texts after the version!).
- run `php composer.phar install --no-dev`
3. Make sure that the following directories (and the files within)
are writable by the webserver
- /temp
@ -65,42 +61,27 @@ INSTALLATION
5. Point your browser to http://url-to-roundcube/installer/
6. Follow the instructions of the install script (or see MANUAL CONFIGURATION)
7. After creating and testing the configuration, remove the installer directory
------------------------------------------
IMPORTANT: REMOVE THE INSTALLER DIRECTORY!
------------------------------------------
8. If you use git sources compile css files for the Elastic skin (required
lessc >= 1.5.0):
$ cd skins/elastic
$ lessc -x styles/styles.less > styles/styles.css
$ lessc -x styles/print.less > styles/print.css
$ lessc -x styles/embed.less > styles/embed.css
9. Check Known Issues section of this file
8. Check Known Issues section of this file
CONFIGURATION HINTS
===================
IMPORTANT! Read all comments in defaults.inc.php, understand them
and configure your installation to be not surprised by default behaviour.
Roundcube writes internal errors to the 'errors.log' log file located in the logs
Roundcube writes internal errors to the 'errors' log file located in the logs
directory which can be configured in config/config.inc.php. If you want ordinary
PHP errors to be logged there as well, set error_log in php.ini or .htaccess file.
Roundcube forces display_errors=Off and log_errors=On.
PHP errors to be logged there as well, enable the 'php_value error_log' line
in the .htaccess file and set the path to the log file accordingly.
By default the session cookie settings of PHP are not modified by Roundcube.
By default the session_path settings of PHP are not modified by Roundcube.
However if you want to limit the session cookies to the directory where
Roundcube resides you can set session.cookie_path in the php.ini or .htaccess file.
More about PHP settings: https://github.com/roundcube/roundcubemail/wiki/Installation#php-configuration
Roundcube resides you can uncomment and configure the according line
in the .htaccess file.
DATABASE SETUP
==============
Note: Database for Roundcube must use UTF-8 character set.
Note: See defaults.inc.php file for examples of DSN configuration.
* MySQL
-------
@ -109,9 +90,9 @@ importing the table layout and granting the proper permissions to the
roundcube user. Here is an example of that procedure:
# mysql
> CREATE DATABASE roundcubemail CHARACTER SET utf8 COLLATE utf8_general_ci;
> CREATE USER roundcube@localhost IDENTIFIED BY 'password';
> GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost;
> CREATE DATABASE roundcubemail /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
> GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost
IDENTIFIED BY 'password';
> quit
# mysql roundcubemail < SQL/mysql.initial.sql
@ -120,11 +101,6 @@ Note 1: 'password' is the master password for the roundcube user. It is strongly
recommended you replace this with a more secure password. Please keep in
mind: You need to specify this password later in 'config/db.inc.php'.
Note 2: When using MySQL < 5.7.7 or MariaDB < 10.2.2 it is required to configure
the database engine with:
innodb_large_prefix=true
innodb_file_format=Barracuda
* SQLite
--------
@ -151,7 +127,7 @@ createuser and createdb commands.
* Microsoft SQL Server
----------------------
Language/locale of the database must be set to us_english (1033). More info
on this at https://github.com/roundcube/roundcubemail/issues/4078.
on this at http://trac.roundcube.net/ticket/1488918.
Database cleaning
@ -169,12 +145,12 @@ to config/config.inc.php and make the necessary adjustments according to your
environment and your needs. More configuration options can be copied from the
config/defaults.inc.php file into your local config.inc.php file as needed.
Read the comments above the individual configuration options to find out what
they do or read https://github.com/roundcube/roundcubemail/wiki/Installation
for even more guidance.
they do or read http://trac.roundcube.net/wiki/Howto_Install for even more
guidance.
The maximum size of email attachments and other file uploads is controlled by
PHP settings: upload_max_filesize and post_max_size. Read more about PHP
settings at https://github.com/roundcube/roundcubemail/wiki/Installation#php-configuration.
You can also modify the default .htaccess file. This is necessary to
increase the allowed size of file attachments, for example:
php_value upload_max_filesize 2M
SECURE YOUR INSTALLATION
@ -197,14 +173,7 @@ NOTE: In Apache 2.4, support for .htaccess files has been disabled by
default. Therefore you first need to enable this in your Apache main or
virtual host config by with:
AllowOverride all
For non-apache web servers add equivalent configuration parameters to deny
direct access to these private resources.
It is also recommended to change the document root to <install path>/public_html
after installation if Roundcube runs at root of a dedicated virtual host. This
will automatically keep sensitive files out of reach for http requests.
AllowOverride all
UPGRADING
@ -255,6 +224,11 @@ To enable these features in apache the following modules need to be enabled:
The optimisation is already included in the .htaccess file in the top
directory of your installation.
If you are using Apache version 2.2.9 and later, in the .htaccess file
change the 'append' word to 'merge' for a more correct response. Keeping
as 'append' shouldn't cause any problems though changing to merge will
eliminate the possibility of duplicate 'public' headers in Cache-control.
Lighttpd:
---------
With Lightty the addition of Expire: tags by mod_expire is incompatible with
@ -291,25 +265,3 @@ KNOWN ISSUES
Installations with uw-imap server should set imap_disabled_caps = array('ESEARCH')
in main configuration file. ESEARCH implementation in this server is broken (#1489184).
PHP >= 5.6 validates the ssl certificates by default. It means that
if IMAP/SMTP certificates are self-signed or use wrong host name you'll get
connection errors. A solution in such cases is to set imap_conn_options,
smtp_conn_options and managesieve_conn_options in a way described in config/defaults.inc.php.
If you have problems with temp files or non-working logs make sure temp and logs folders
are writeable to the user used by http server. Access to them may also be blocked by
SELINUX. Here's some sample commands for SELINUX:
$ semanage fcontext -a -t httpd_sys_rw_content_t "/path_to_roundcube/logs(/.*)?"
$ semanage fcontext -a -t httpd_sys_rw_content_t "/path_to_roundcube/temp(/.*)?"
$ restorecon -Rv /path_to_roundcube/
Microsoft IIS Server by default does not support WOFF fonts used in Elastic skin. It might be
needed to add following MIME Types definitions (via web.config or IIS Manager):
.woff application/font-woff
.woff2 application/font-woff2
When installing on Windows be aware we're using symbolic links which may need an additional
attention. See https://github.com/roundcube/roundcubemail/issues/7151.

@ -1,8 +1,7 @@
Roundcube Webmail
=================
[roundcube.net](https://roundcube.net)
[roundcube.net](http://roundcube.net)
[![Build Status](https://api.travis-ci.org/roundcube/roundcubemail.svg?branch=master)](https://travis-ci.org/roundcube/roundcubemail)
ATTENTION
---------
@ -19,11 +18,17 @@ application-like user interface. It provides full functionality you expect
from an email client, including MIME support, address book, folder management,
message searching and spell checking. Roundcube Webmail is written in PHP and
requires the MySQL, PostgreSQL or SQLite database. With its plugin API it is
easily extendable and the user interface is fully customizable using skins.
easily extendable and the user interface is fully customizable using skins
which are pure XHTML and CSS 2.
The code designed to run on a webserver is mainly written in PHP and Javascript.
It includes a custom framework with an IMAP library derived from [IlohaMail][iloha]
and requires a set of external libraries (see composer.json and jsdeps.json files).
The code is mainly written in PHP and is designed to run on a webserver.
It includes other open-source classes/libraries from [PEAR][pear],
an IMAP library derived from [IlohaMail][iloha] the [TinyMCE][tinymce] rich
text editor, [Googiespell][googiespell] library for spell checking or
the [WASHTML][washtml] sanitizer by Frederic Motte.
The current default skin 'Larry' was kindly created by FLINT / Büro für
Gestaltung, Berne, Switzerland.
INSTALLATION
@ -35,19 +40,6 @@ If you're updating an older version of Roundcube please follow the steps
described in the UPGRADING file.
BROWSER SUPPORT
---------------
Roundcube uses jQuery 3.x for its client and therefore inherits the browser
support from there. This currently includes:
- Chrome: (Current - 1) and Current
- Edge: (Current - 1) and Current
- Firefox: (Current - 1) and Current, ESR
- Internet Explorer: 9+ (11+ for the Elastic skin)
- Safari: (Current - 1) and Current
- Opera: Current
LICENSE
-------
This program is free software: you can redistribute it and/or modify
@ -96,9 +88,14 @@ You're always welcome to send a message to the project admin:
hello(at)roundcube(dot)net
[iloha]: https://sourceforge.net/projects/ilohamail/
[gpl]: https://www.gnu.org/licenses/
[license]: https://roundcube.net/license
[contrib]: https://roundcube.net/contribute
[support]: https://roundcube.net/support
[githubissues]: https://github.com/roundcube/roundcubemail/issues
[pear]: http://pear.php.net
[iloha]: http://sourceforge.net/projects/ilohamail/
[tinymce]: http://www.tinymce.com/
[googiespell]: http://orangoo.com/labs/GoogieSpell/
[washtml]: http://www.ubixis.com/washtml/
[kmgerich]: http://kmgerich.com/
[gpl]: http://www.gnu.org/licenses/
[license]: http://roundcube.net/license
[contrib]: http://roundcube.net/contribute
[support]: http://roundcube.net/support
[githubissues]: https://github.com/roundcube/roundcubemail/issues

@ -1,13 +1,15 @@
CREATE TABLE [dbo].[cache] (
[user_id] [int] NOT NULL ,
[cache_key] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL ,
[cache_key] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[created] [datetime] NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[cache_shared] (
[cache_key] [varchar] (255) COLLATE Latin1_General_CS_AS NOT NULL ,
[cache_key] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,
[created] [datetime] NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
@ -15,7 +17,7 @@ GO
CREATE TABLE [dbo].[cache_index] (
[user_id] [int] NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[expires] [datetime] NULL ,
[valid] [char] (1) COLLATE Latin1_General_CI_AI NOT NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
@ -24,7 +26,7 @@ GO
CREATE TABLE [dbo].[cache_thread] (
[user_id] [int] NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
@ -32,7 +34,7 @@ GO
CREATE TABLE [dbo].[cache_messages] (
[user_id] [int] NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL ,
[mailbox] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[uid] [int] NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL ,
@ -88,6 +90,7 @@ GO
CREATE TABLE [dbo].[session] (
[sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[created] [datetime] NOT NULL ,
[changed] [datetime] NULL ,
[ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL ,
[vars] [text] COLLATE Latin1_General_CI_AI NOT NULL
@ -96,20 +99,18 @@ GO
CREATE TABLE [dbo].[users] (
[user_id] [int] IDENTITY (1, 1) NOT NULL ,
[username] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL ,
[username] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[mail_host] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[created] [datetime] NOT NULL ,
[last_login] [datetime] NULL ,
[failed_login] [datetime] NULL ,
[failed_login_counter] [int] NULL ,
[language] [varchar] (16) COLLATE Latin1_General_CI_AI NULL ,
[language] [varchar] (5) COLLATE Latin1_General_CI_AI NULL ,
[preferences] [text] COLLATE Latin1_General_CI_AI NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[dictionary] (
[user_id] [int] ,
[language] [varchar] (16) COLLATE Latin1_General_CI_AI NOT NULL ,
[language] [varchar] (5) COLLATE Latin1_General_CI_AI NOT NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
@ -123,36 +124,12 @@ CREATE TABLE [dbo].[searches] (
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[filestore] (
[file_id] [int] IDENTITY (1, 1) NOT NULL ,
[user_id] [int] NOT NULL ,
[context] [varchar] (32) COLLATE Latin1_General_CI_AI NOT NULL ,
[filename] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[mtime] [int] NOT NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NULL ,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[system] (
[name] [varchar] (64) COLLATE Latin1_General_CI_AI NOT NULL ,
[value] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED
(
[user_id],[cache_key]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache_shared] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED
(
[cache_key]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache_index] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED
(
@ -223,13 +200,6 @@ ALTER TABLE [dbo].[searches] WITH NOCHECK ADD
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[filestore] WITH NOCHECK ADD
CONSTRAINT [PK_filestore_file_id] PRIMARY KEY CLUSTERED
(
[file_id]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[system] WITH NOCHECK ADD
CONSTRAINT [PK_system_name] PRIMARY KEY CLUSTERED
(
@ -239,7 +209,12 @@ GO
ALTER TABLE [dbo].[cache] ADD
CONSTRAINT [DF_cache_user_id] DEFAULT ('0') FOR [user_id],
CONSTRAINT [DF_cache_cache_key] DEFAULT ('') FOR [cache_key]
CONSTRAINT [DF_cache_cache_key] DEFAULT ('') FOR [cache_key],
CONSTRAINT [DF_cache_created] DEFAULT (getdate()) FOR [created]
GO
ALTER TABLE [dbo].[cache_shared] ADD
CONSTRAINT [DF_cache_shared_created] DEFAULT (getdate()) FOR [created]
GO
ALTER TABLE [dbo].[cache_index] ADD
@ -250,6 +225,12 @@ ALTER TABLE [dbo].[cache_messages] ADD
CONSTRAINT [DF_cache_messages_flags] DEFAULT (0) FOR [flags]
GO
CREATE INDEX [IX_cache_user_id] ON [dbo].[cache]([user_id]) ON [PRIMARY]
GO
CREATE INDEX [IX_cache_cache_key] ON [dbo].[cache]([cache_key]) ON [PRIMARY]
GO
CREATE INDEX [IX_cache_shared_cache_key] ON [dbo].[cache_shared]([cache_key]) ON [PRIMARY]
GO
@ -332,15 +313,13 @@ GO
ALTER TABLE [dbo].[session] ADD
CONSTRAINT [DF_session_sess_id] DEFAULT ('') FOR [sess_id],
CONSTRAINT [DF_session_created] DEFAULT (getdate()) FOR [created],
CONSTRAINT [DF_session_ip] DEFAULT ('') FOR [ip]
GO
CREATE INDEX [IX_session_changed] ON [dbo].[session]([changed]) ON [PRIMARY]
GO
CREATE INDEX [IX_filestore_user_id] ON [dbo].[filestore]([user_id]) ON [PRIMARY]
GO
ALTER TABLE [dbo].[users] ADD
CONSTRAINT [DF_users_username] DEFAULT ('') FOR [username],
CONSTRAINT [DF_users_mail_host] DEFAULT ('') FOR [mail_host],
@ -361,9 +340,6 @@ GO
CREATE UNIQUE INDEX [IX_searches_user_type_name] ON [dbo].[searches]([user_id],[type],[name]) ON [PRIMARY]
GO
CREATE UNIQUE INDEX [IX_filestore_user_id_context_filename] ON [dbo].[filestore]([user_id],[context],[filename]) ON [PRIMARY]
GO
ALTER TABLE [dbo].[identities] ADD CONSTRAINT [FK_identities_user_id]
FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])
ON DELETE CASCADE ON UPDATE CASCADE
@ -409,11 +385,6 @@ ALTER TABLE [dbo].[searches] ADD CONSTRAINT [FK_searches_user_id]
ON DELETE CASCADE ON UPDATE CASCADE
GO
ALTER TABLE [dbo].[filestore] ADD CONSTRAINT [FK_filestore_user_id]
FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])
ON DELETE CASCADE ON UPDATE CASCADE
GO
-- Use trigger instead of foreign key (#1487112)
-- "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths."
CREATE TRIGGER [contact_delete_member] ON [dbo].[contacts]
@ -422,6 +393,6 @@ CREATE TRIGGER [contact_delete_member] ON [dbo].[contacts]
WHERE [contact_id] IN (SELECT [contact_id] FROM deleted)
GO
INSERT INTO [dbo].[system] ([name], [value]) VALUES ('roundcube-version', '2020020101')
INSERT INTO [dbo].[system] ([name], [value]) VALUES ('roundcube-version', '2015030800')
GO

@ -1,4 +0,0 @@
ALTER TABLE [dbo].[users] ADD [failed_login] [datetime] NULL
GO
ALTER TABLE [dbo].[users] ADD [failed_login_counter] [int] NULL
GO

@ -1,2 +0,0 @@
ALTER TABLE [dbo].[session] DROP COLUMN [created]
GO

@ -1,2 +0,0 @@
ALTER TABLE [dbo].[session] ALTER COLUMN [ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL
GO

@ -1,36 +0,0 @@
DROP TABLE [dbo].[cache]
GO
DROP TABLE [dbo].[cache_shared]
GO
CREATE TABLE [dbo].[cache] (
[user_id] [int] NOT NULL ,
[cache_key] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[cache_shared] (
[cache_key] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL ,
[expires] [datetime] NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache] ADD
CONSTRAINT [DF_cache_user_id] DEFAULT ('0') FOR [user_id],
CONSTRAINT [DF_cache_cache_key] DEFAULT ('') FOR [cache_key],
GO
CREATE INDEX [IX_cache_expires] ON [dbo].[cache]([expires]) ON [PRIMARY]
GO
CREATE INDEX [IX_cache_shared_expires] ON [dbo].[cache_shared]([expires]) ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED (
[user_id],[cache_key]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[cache_shared] WITH NOCHECK ADD
PRIMARY KEY CLUSTERED (
[cache_key]
) ON [PRIMARY]
GO

@ -1,24 +0,0 @@
CREATE TABLE [dbo].[filestore] (
[file_id] [int] IDENTITY (1, 1) NOT NULL ,
[user_id] [int] NOT NULL ,
[filename] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[mtime] [int] NOT NULL ,
[data] [text] COLLATE Latin1_General_CI_AI NULL ,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[filestore] WITH NOCHECK ADD
CONSTRAINT [PK_filestore_file_id] PRIMARY KEY CLUSTERED
(
[file_id]
) ON [PRIMARY]
GO
CREATE INDEX [IX_filestore_user_id] ON [dbo].[filestore]([user_id]) ON [PRIMARY]
GO
ALTER TABLE [dbo].[filestore] ADD CONSTRAINT [FK_filestore_user_id]
FOREIGN KEY ([user_id]) REFERENCES [dbo].[users] ([user_id])
ON DELETE CASCADE ON UPDATE CASCADE
GO

@ -1,9 +0,0 @@
ALTER TABLE [dbo].[filestore] ADD COLUMN [context] [varchar] (32) COLLATE Latin1_General_CI_AI NOT NULL
GO
UPDATE [dbo].[filestore] SET [dbo].[context] = 'enigma'
GO
CREATE UNIQUE INDEX [IX_filestore_user_id_context_filename] ON [dbo].[filestore]([user_id],[context],[filename]) ON [PRIMARY]
GO

@ -1,18 +0,0 @@
ALTER TABLE [dbo].[cache] ALTER COLUMN
[cache_key] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL
GO
ALTER TABLE [dbo].[cache_shared] ALTER COLUMN
[cache_key] [varchar] (255) COLLATE Latin1_General_CS_AS NOT NULL
GO
ALTER TABLE [dbo].[cache_index] ALTER COLUMN
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL
GO
ALTER TABLE [dbo].[cache_messages] ALTER COLUMN
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL
GO
ALTER TABLE [dbo].[cache_thread] ALTER COLUMN
[mailbox] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL
GO
ALTER TABLE [dbo].[users] ALTER COLUMN
[username] [varchar] (128) COLLATE Latin1_General_CS_AS NOT NULL
GO

@ -1,4 +0,0 @@
ALTER TABLE [dbo].[users] ALTER COLUMN [language] [varchar] (16) COLLATE Latin1_General_CI_AI NULL
GO
ALTER TABLE [dbo].[dictionary] ALTER COLUMN [language] [varchar] (16) COLLATE Latin1_General_CI_AI NOT NULL
GO

@ -7,12 +7,13 @@
CREATE TABLE `session` (
`sess_id` varchar(128) NOT NULL,
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`ip` varchar(40) NOT NULL,
`vars` mediumtext NOT NULL,
PRIMARY KEY(`sess_id`),
INDEX `changed_index` (`changed`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `users`
@ -23,38 +24,38 @@ CREATE TABLE `users` (
`mail_host` varchar(128) NOT NULL,
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`last_login` datetime DEFAULT NULL,
`failed_login` datetime DEFAULT NULL,
`failed_login_counter` int(10) UNSIGNED DEFAULT NULL,
`language` varchar(16),
`language` varchar(5),
`preferences` longtext,
PRIMARY KEY(`user_id`),
UNIQUE `username` (`username`, `mail_host`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `cache`
CREATE TABLE `cache` (
`user_id` int(10) UNSIGNED NOT NULL,
`cache_key` varchar(128) BINARY NOT NULL,
`cache_key` varchar(128) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL,
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`expires` datetime DEFAULT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`user_id`, `cache_key`),
CONSTRAINT `user_id_fk_cache` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `expires_index` (`expires`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
INDEX `expires_index` (`expires`),
INDEX `user_cache_index` (`user_id`,`cache_key`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `cache_shared`
CREATE TABLE `cache_shared` (
`cache_key` varchar(255) BINARY NOT NULL,
`cache_key` varchar(255) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL,
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`expires` datetime DEFAULT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`cache_key`),
INDEX `expires_index` (`expires`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
INDEX `expires_index` (`expires`),
INDEX `cache_key_index` (`cache_key`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `cache_index`
@ -69,7 +70,7 @@ CREATE TABLE `cache_index` (
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `expires_index` (`expires`),
PRIMARY KEY (`user_id`, `mailbox`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `cache_thread`
@ -83,7 +84,7 @@ CREATE TABLE `cache_thread` (
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `expires_index` (`expires`),
PRIMARY KEY (`user_id`, `mailbox`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `cache_messages`
@ -99,7 +100,7 @@ CREATE TABLE `cache_messages` (
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `expires_index` (`expires`),
PRIMARY KEY (`user_id`, `mailbox`, `uid`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `contacts`
@ -119,7 +120,7 @@ CREATE TABLE `contacts` (
CONSTRAINT `user_id_fk_contacts` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `user_contacts_index` (`user_id`,`del`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `contactgroups`
@ -133,7 +134,7 @@ CREATE TABLE `contactgroups` (
CONSTRAINT `user_id_fk_contactgroups` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `contactgroups_user_index` (`user_id`,`del`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
CREATE TABLE `contactgroupmembers` (
`contactgroup_id` int(10) UNSIGNED NOT NULL,
@ -168,20 +169,19 @@ CREATE TABLE `identities` (
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `user_identities_index` (`user_id`, `del`),
INDEX `email_identities_index` (`email`, `del`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `dictionary`
CREATE TABLE `dictionary` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, -- redundant, for compat. with Galera Cluster
`user_id` int(10) UNSIGNED DEFAULT NULL, -- NULL here is for "shared dictionaries"
`language` varchar(16) NOT NULL,
`user_id` int(10) UNSIGNED DEFAULT NULL,
`language` varchar(5) NOT NULL,
`data` longtext NOT NULL,
CONSTRAINT `user_id_fk_dictionary` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE `uniqueness` (`user_id`, `language`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Table structure for table `searches`
@ -196,22 +196,8 @@ CREATE TABLE `searches` (
CONSTRAINT `user_id_fk_searches` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE `uniqueness` (`user_id`, `type`, `name`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
-- Table structure for table `filestore`
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
CREATE TABLE `filestore` (
`file_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(10) UNSIGNED NOT NULL,
`context` varchar(32) NOT NULL,
`filename` varchar(128) NOT NULL,
`mtime` int(10) NOT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`file_id`),
CONSTRAINT `user_id_fk_filestore` FOREIGN KEY (`user_id`)
REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE `uniqueness` (`user_id`, `context`, `filename`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
-- Table structure for table `system`
@ -219,8 +205,8 @@ CREATE TABLE `system` (
`name` varchar(64) NOT NULL,
`value` mediumtext,
PRIMARY KEY(`name`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;
INSERT INTO `system` (`name`, `value`) VALUES ('roundcube-version', '2020020101');
INSERT INTO system (name, value) VALUES ('roundcube-version', '2015030800');

@ -1,3 +0,0 @@
ALTER TABLE `users`
ADD `failed_login` datetime DEFAULT NULL,
ADD `failed_login_counter` int(10) UNSIGNED DEFAULT NULL;

@ -1 +0,0 @@
ALTER TABLE `session` DROP COLUMN `created`;

@ -1 +0,0 @@
ALTER TABLE `session` MODIFY `ip` varchar(40) NOT NULL;

@ -1,24 +0,0 @@
ALTER TABLE `dictionary` ADD COLUMN `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; -- redundant, for compat. with Galera Cluster
DROP TABLE `cache`;
DROP TABLE `cache_shared`;
CREATE TABLE `cache` (
`user_id` int(10) UNSIGNED NOT NULL,
`cache_key` varchar(128) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL,
`expires` datetime DEFAULT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`user_id`, `cache_key`),
CONSTRAINT `user_id_fk_cache` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `expires_index` (`expires`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
CREATE TABLE `cache_shared` (
`cache_key` varchar(255) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL,
`expires` datetime DEFAULT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`cache_key`),
INDEX `expires_index` (`expires`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;

@ -1,11 +0,0 @@
CREATE TABLE `filestore` (
`file_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(10) UNSIGNED NOT NULL,
`filename` varchar(128) NOT NULL,
`mtime` int(10) NOT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`file_id`),
CONSTRAINT `user_id_fk_filestore` FOREIGN KEY (`user_id`)
REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE `uniqueness` (`user_id`, `filename`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;

@ -1,7 +0,0 @@
ALTER TABLE `filestore` ADD COLUMN `context` varchar(32) NOT NULL;
UPDATE `filestore` SET `context` = 'enigma';
ALTER TABLE `filestore` DROP FOREIGN KEY `user_id_fk_filestore`;
ALTER TABLE `filestore` DROP INDEX `uniqueness`;
ALTER TABLE `filestore` ADD UNIQUE INDEX `uniqueness` (`user_id`, `context`, `filename`);
ALTER TABLE `filestore` ADD CONSTRAINT `user_id_fk_filestore` FOREIGN KEY (`user_id`)
REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;

@ -1,2 +0,0 @@
ALTER TABLE `cache` CHANGE `cache_key` `cache_key` varchar(128) BINARY NOT NULL;
ALTER TABLE `cache_shared` CHANGE `cache_key` `cache_key` varchar(255) BINARY NOT NULL;

@ -1,2 +0,0 @@
ALTER TABLE `users` MODIFY `language` varchar(16);
ALTER TABLE `dictionary` MODIFY `language` varchar(16) NOT NULL;

@ -1,21 +0,0 @@
ALTER TABLE `session` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `cache` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `cache_shared` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `cache_index` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `cache_thread` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `cache_messages` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `contacts` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `contactgroups` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `identities` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `dictionary` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `searches` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `filestore` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `system` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `users` CHANGE `username` `username` varchar(128) BINARY NOT NULL;
ALTER TABLE `cache` CHANGE `cache_key` `cache_key` varchar(128) BINARY NOT NULL;
ALTER TABLE `cache_shared` CHANGE `cache_key` `cache_key` varchar(255) BINARY NOT NULL;
ALTER TABLE `cache_index` CHANGE `mailbox` `mailbox` varchar(255) BINARY NOT NULL;
ALTER TABLE `cache_thread` CHANGE `mailbox` `mailbox` varchar(255) BINARY NOT NULL;
ALTER TABLE `cache_messages` CHANGE `mailbox` `mailbox` varchar(255) BINARY NOT NULL;

@ -7,9 +7,7 @@ CREATE TABLE "users" (
"mail_host" varchar(128) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"last_login" timestamp with time zone DEFAULT NULL,
"failed_login" timestamp with time zone DEFAULT NULL,
"failed_login_counter" integer DEFAULT NULL,
"language" varchar(16),
"language" varchar(5),
"preferences" long DEFAULT NULL,
CONSTRAINT "users_username_key" UNIQUE ("username", "mail_host")
);
@ -26,6 +24,7 @@ END;
CREATE TABLE "session" (
"sess_id" varchar(128) NOT NULL PRIMARY KEY,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"changed" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"ip" varchar(41) NOT NULL,
"vars" long NOT NULL
@ -126,21 +125,23 @@ CREATE TABLE "cache" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"cache_key" varchar(128) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
PRIMARY KEY ("user_id", "cache_key")
"data" long NOT NULL
);
CREATE INDEX "cache_user_id_idx" ON "cache" ("user_id", "cache_key");
CREATE INDEX "cache_expires_idx" ON "cache" ("expires");
CREATE TABLE "cache_shared" (
"cache_key" varchar(255) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
PRIMARY KEY ("cache_key")
"data" long NOT NULL
);
CREATE INDEX "cache_shared_cache_key_idx" ON "cache_shared" ("cache_key");
CREATE INDEX "cache_shared_expires_idx" ON "cache_shared" ("expires");
@ -186,7 +187,7 @@ CREATE INDEX "cache_messages_expires_idx" ON "cache_messages" ("expires");
CREATE TABLE "dictionary" (
"user_id" integer DEFAULT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"language" varchar(16) NOT NULL,
"language" varchar(5) NOT NULL,
"data" long DEFAULT NULL,
CONSTRAINT "dictionary_user_id_lang_key" UNIQUE ("user_id", "language")
);
@ -212,30 +213,9 @@ BEGIN
END;
/
CREATE TABLE "filestore" (
"file_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE ON UPDATE CASCADE,
"context" varchar(32) NOT NULL,
"filename" varchar(128) NOT NULL,
"mtime" integer NOT NULL,
"data" long,
CONSTRAINT "filestore_user_id_key" UNIQUE ("user_id", "context", "filename")
);
CREATE SEQUENCE "filestore_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "filestore_seq_trig"
BEFORE INSERT ON "filestore" FOR EACH ROW
BEGIN
:NEW."user_id" := "filestore_seq".nextval;
END;
/
CREATE TABLE "system" (
"name" varchar(64) NOT NULL PRIMARY KEY,
"value" long
);
INSERT INTO "system" ("name", "value") VALUES ('roundcube-version', '2020020101');
INSERT INTO "system" ("name", "value") VALUES ('roundcube-version', '2015030800');

@ -1,2 +0,0 @@
ALTER TABLE "users" ADD "failed_login" timestamp with time zone DEFAULT NULL;
ALTER TABLE "users" ADD "failed_login_counter" integer DEFAULT NULL;

@ -1 +0,0 @@
ALTER TABLE "session" DROP COLUMN "created";

@ -1 +0,0 @@
ALTER TABLE "session" MODIFY "ip" varchar(41) NOT NULL;

@ -1,23 +0,0 @@
DROP TABLE "cache";
DROP TABLE "cache_shared";
CREATE TABLE "cache" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"cache_key" varchar(128) NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
PRIMARY KEY ("user_id", "cache_key")
);
CREATE INDEX "cache_expires_idx" ON "cache" ("expires");
CREATE TABLE "cache_shared" (
"cache_key" varchar(255) NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
PRIMARY KEY ("cache_key")
);
CREATE INDEX "cache_shared_expires_idx" ON "cache_shared" ("expires");

@ -1,19 +0,0 @@
CREATE TABLE "filestore" (
"file_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE ON UPDATE CASCADE,
"filename" varchar(128) NOT NULL,
"mtime" integer NOT NULL,
"data" long,
CONSTRAINT "filestore_user_id_key" UNIQUE ("user_id", "filename")
);
CREATE SEQUENCE "filestore_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "filestore_seq_trig"
BEFORE INSERT ON "filestore" FOR EACH ROW
BEGIN
:NEW."user_id" := "filestore_seq".nextval;
END;
/

@ -1,4 +0,0 @@
ALTER TABLE "filestore" ADD COLUMN "context" varchar(32) NOT NULL;
UPDATE "filestore" SET "context" = 'enigma';
ALTER TABLE "filestore" DROP CONSTRAINT "filestore_user_id_key";
ALTER TABLE "filestore" ADD CONSTRAINT "filestore_user_id_key" UNIQUE ("user_id", "context", "filename");

@ -1,2 +0,0 @@
ALTER TABLE "users" MODIFY "language" varchar(16) NOT NULL;
ALTER TABLE "dictionary" MODIFY "language" varchar(16);

@ -22,9 +22,7 @@ CREATE TABLE users (
mail_host varchar(128) DEFAULT '' NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL,
last_login timestamp with time zone DEFAULT NULL,
failed_login timestamp with time zone DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
"language" varchar(16),
"language" varchar(5),
preferences text DEFAULT ''::text NOT NULL,
CONSTRAINT users_username_key UNIQUE (username, mail_host)
);
@ -37,6 +35,7 @@ CREATE TABLE users (
CREATE TABLE "session" (
sess_id varchar(128) DEFAULT '' PRIMARY KEY,
created timestamp with time zone DEFAULT now() NOT NULL,
changed timestamp with time zone DEFAULT now() NOT NULL,
ip varchar(41) NOT NULL,
vars text NOT NULL
@ -167,11 +166,12 @@ CREATE TABLE "cache" (
user_id integer NOT NULL
REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
cache_key varchar(128) DEFAULT '' NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL,
expires timestamp with time zone DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (user_id, cache_key)
data text NOT NULL
);
CREATE INDEX cache_user_id_idx ON "cache" (user_id, cache_key);
CREATE INDEX cache_expires_idx ON "cache" (expires);
--
@ -180,11 +180,13 @@ CREATE INDEX cache_expires_idx ON "cache" (expires);
--
CREATE TABLE "cache_shared" (
cache_key varchar(255) NOT NULL PRIMARY KEY,
cache_key varchar(255) NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL,
expires timestamp with time zone DEFAULT NULL,
data text NOT NULL
);
CREATE INDEX cache_shared_cache_key_idx ON "cache_shared" (cache_key);
CREATE INDEX cache_shared_expires_idx ON "cache_shared" (expires);
--
@ -246,7 +248,7 @@ CREATE INDEX cache_messages_expires_idx ON cache_messages (expires);
CREATE TABLE dictionary (
user_id integer DEFAULT NULL
REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
"language" varchar(16) NOT NULL,
"language" varchar(5) NOT NULL,
data text NOT NULL,
CONSTRAINT dictionary_user_id_language_key UNIQUE (user_id, "language")
);
@ -277,32 +279,6 @@ CREATE TABLE searches (
CONSTRAINT searches_user_id_key UNIQUE (user_id, "type", name)
);
--
-- Sequence "filestore_seq"
-- Name: filestore_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
CREATE SEQUENCE "filestore_seq"
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
--
-- Table "filestore"
-- Name: filestore; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE "filestore" (
file_id integer DEFAULT nextval('filestore_seq'::text) PRIMARY KEY,
user_id integer NOT NULL
REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
context varchar(32) NOT NULL,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL,
CONSTRAINT filestore_user_id_filename UNIQUE (user_id, context, filename)
);
--
-- Table "system"
@ -314,4 +290,4 @@ CREATE TABLE "system" (
value text
);
INSERT INTO "system" (name, value) VALUES ('roundcube-version', '2020020101');
INSERT INTO system (name, value) VALUES ('roundcube-version', '2015030800');

@ -1,2 +0,0 @@
ALTER TABLE "users" ADD failed_login timestamp with time zone DEFAULT NULL;
ALTER TABLE "users" ADD failed_login_counter integer DEFAULT NULL;

@ -1 +0,0 @@
ALTER TABLE "session" DROP COLUMN created;

@ -1 +0,0 @@
ALTER TABLE session ALTER COLUMN ip TYPE character varying(41);

@ -1,21 +0,0 @@
DROP TABLE "cache";
DROP TABLE "cache_shared";
CREATE TABLE "cache" (
user_id integer NOT NULL
REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
cache_key varchar(128) DEFAULT '' NOT NULL,
expires timestamp with time zone DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (user_id, cache_key)
);
CREATE INDEX cache_expires_idx ON "cache" (expires);
CREATE TABLE "cache_shared" (
cache_key varchar(255) NOT NULL PRIMARY KEY,
expires timestamp with time zone DEFAULT NULL,
data text NOT NULL
);
CREATE INDEX cache_shared_expires_idx ON "cache_shared" (expires);

@ -1,15 +0,0 @@
CREATE SEQUENCE "filestore_seq"
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
CREATE TABLE "filestore" (
file_id integer DEFAULT nextval('filestore_seq'::text) PRIMARY KEY,
user_id integer NOT NULL
REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL,
CONSTRAINT filestore_user_id_filename UNIQUE (user_id, filename)
);

@ -1,4 +0,0 @@
ALTER TABLE "filestore" ADD COLUMN context varchar(32) NOT NULL;
UPDATE "filestore" SET context = 'enigma';
ALTER TABLE "filestore" DROP CONSTRAINT "filestore_user_id_filename";
ALTER TABLE "filestore" ADD CONSTRAINT "filestore_user_id_context_filename" UNIQUE (user_id, context, filename);

@ -1,2 +0,0 @@
ALTER TABLE "dictionary" ALTER COLUMN "language" TYPE varchar(16);
ALTER TABLE "users" ALTER COLUMN "language" TYPE varchar(16);

@ -72,9 +72,7 @@ CREATE TABLE users (
mail_host varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
last_login datetime DEFAULT NULL,
failed_login datetime DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
language varchar(16),
language varchar(5),
preferences text NOT NULL default ''
);
@ -86,6 +84,7 @@ CREATE UNIQUE INDEX ix_users_username ON users(username, mail_host);
CREATE TABLE session (
sess_id varchar(128) NOT NULL PRIMARY KEY,
created datetime NOT NULL default '0000-00-00 00:00:00',
changed datetime NOT NULL default '0000-00-00 00:00:00',
ip varchar(40) NOT NULL default '',
vars text NOT NULL
@ -99,11 +98,11 @@ CREATE INDEX ix_session_changed ON session (changed);
CREATE TABLE dictionary (
user_id integer DEFAULT NULL,
language varchar(16) NOT NULL,
"language" varchar(5) NOT NULL,
data text NOT NULL
);
CREATE UNIQUE INDEX ix_dictionary_user_language ON dictionary (user_id, language);
CREATE UNIQUE INDEX ix_dictionary_user_language ON dictionary (user_id, "language");
--
-- Table structure for table searches
@ -126,11 +125,12 @@ CREATE UNIQUE INDEX ix_searches_user_type_name ON searches (user_id, type, name)
CREATE TABLE cache (
user_id integer NOT NULL default 0,
cache_key varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
expires datetime DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (user_id, cache_key)
data text NOT NULL
);
CREATE INDEX ix_cache_user_cache_key ON cache(user_id, cache_key);
CREATE INDEX ix_cache_expires ON cache(expires);
--
@ -139,11 +139,12 @@ CREATE INDEX ix_cache_expires ON cache(expires);
CREATE TABLE cache_shared (
cache_key varchar(255) NOT NULL,
created datetime NOT NULL default '0000-00-00 00:00:00',
expires datetime DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (cache_key)
data text NOT NULL
);
CREATE INDEX ix_cache_shared_cache_key ON cache_shared(cache_key);
CREATE INDEX ix_cache_shared_expires ON cache_shared(expires);
--
@ -191,21 +192,6 @@ CREATE TABLE cache_messages (
CREATE INDEX ix_cache_messages_expires ON cache_messages (expires);
--
-- Table structure for table filestore
--
CREATE TABLE filestore (
file_id integer NOT NULL PRIMARY KEY,
user_id integer NOT NULL,
context varchar(32) NOT NULL,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL
);
CREATE UNIQUE INDEX ix_filestore_user_id ON filestore(user_id, context, filename);
--
-- Table structure for table system
--
@ -215,4 +201,4 @@ CREATE TABLE system (
value text NOT NULL
);
INSERT INTO system (name, value) VALUES ('roundcube-version', '2020020101');
INSERT INTO system (name, value) VALUES ('roundcube-version', '2015030800');

@ -1,35 +0,0 @@
CREATE TABLE tmp_users (
user_id integer NOT NULL PRIMARY KEY,
username varchar(128) NOT NULL default '',
mail_host varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
last_login datetime DEFAULT NULL,
failed_login datetime DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
language varchar(5),
preferences text NOT NULL default ''
);
INSERT INTO tmp_users (user_id, username, mail_host, created, last_login, language, preferences)
SELECT user_id, username, mail_host, created, last_login, language, preferences FROM users;
DROP TABLE users;
CREATE TABLE users (
user_id integer NOT NULL PRIMARY KEY,
username varchar(128) NOT NULL default '',
mail_host varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
last_login datetime DEFAULT NULL,
failed_login datetime DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
language varchar(5),
preferences text NOT NULL default ''
);
INSERT INTO users (user_id, username, mail_host, created, last_login, language, preferences)
SELECT user_id, username, mail_host, created, last_login, language, preferences FROM tmp_users;
CREATE UNIQUE INDEX ix_users_username ON users(username, mail_host);
DROP TABLE tmp_users;

@ -1,9 +0,0 @@
DROP TABLE session;
CREATE TABLE session (
sess_id varchar(128) NOT NULL PRIMARY KEY,
changed datetime NOT NULL default '0000-00-00 00:00:00',
ip varchar(40) NOT NULL default '',
vars text NOT NULL
);
CREATE INDEX ix_session_changed ON session (changed);

@ -1,21 +0,0 @@
DROP TABLE cache;
DROP TABLE cache_shared;
CREATE TABLE cache (
user_id integer NOT NULL default 0,
cache_key varchar(128) NOT NULL default '',
expires datetime DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (user_id, cache_key)
);
CREATE INDEX ix_cache_expires ON cache(expires);
CREATE TABLE cache_shared (
cache_key varchar(255) NOT NULL,
expires datetime DEFAULT NULL,
data text NOT NULL,
PRIMARY KEY (cache_key)
);
CREATE INDEX ix_cache_shared_expires ON cache_shared(expires);

@ -1,9 +0,0 @@
CREATE TABLE filestore (
file_id integer PRIMARY KEY,
user_id integer NOT NULL,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL
);
CREATE UNIQUE INDEX ix_filestore_user_id ON filestore(user_id, filename);

@ -1,29 +0,0 @@
CREATE TABLE tmp_filestore (
file_id integer PRIMARY KEY,
user_id integer NOT NULL,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL
);
INSERT INTO tmp_filestore (file_id, user_id, filename, mtime, data)
SELECT file_id, user_id, filename, mtime, data FROM filestore;
DROP TABLE filestore;
CREATE TABLE filestore (
file_id integer NOT NULL PRIMARY KEY,
user_id integer NOT NULL,
context varchar(32) NOT NULL,
filename varchar(128) NOT NULL,
mtime integer NOT NULL,
data text NOT NULL
);
INSERT INTO filestore (file_id, user_id, filename, mtime, data, context)
SELECT file_id, user_id, filename, mtime, data, 'enigma' FROM tmp_filestore;
CREATE UNIQUE INDEX ix_filestore_user_id ON filestore(user_id, context, filename);
DROP TABLE tmp_filestore;

@ -1,57 +0,0 @@
CREATE TABLE tmp_users (
user_id integer NOT NULL PRIMARY KEY,
username varchar(128) NOT NULL default '',
mail_host varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
last_login datetime DEFAULT NULL,
failed_login datetime DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
language varchar(16),
preferences text NOT NULL default ''
);
INSERT INTO tmp_users (user_id, username, mail_host, created, last_login, failed_login, failed_login_counter, language, preferences)
SELECT user_id, username, mail_host, created, last_login, failed_login, failed_login_counter, language, preferences FROM users;
DROP TABLE users;
CREATE TABLE users (
user_id integer NOT NULL PRIMARY KEY,
username varchar(128) NOT NULL default '',
mail_host varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
last_login datetime DEFAULT NULL,
failed_login datetime DEFAULT NULL,
failed_login_counter integer DEFAULT NULL,
language varchar(16),
preferences text NOT NULL default ''
);
INSERT INTO users (user_id, username, mail_host, created, last_login, failed_login, failed_login_counter, language, preferences)
SELECT user_id, username, mail_host, created, last_login, failed_login, failed_login_counter, language, preferences FROM tmp_users;
CREATE UNIQUE INDEX ix_users_username ON users(username, mail_host);
DROP TABLE tmp_users;
DROP TABLE users;
CREATE TABLE tmp_dictionary (
user_id integer DEFAULT NULL,
language varchar(16) NOT NULL,
data text NOT NULL
);
INSERT INTO tmp_dictionary (user_id, language, data) SELECT user_id, language, data FROM dictionary;
CREATE TABLE dictionary (
user_id integer DEFAULT NULL,
language varchar(16) NOT NULL,
data text NOT NULL
);
INSERT INTO dictionary (user_id, language, data) SELECT user_id, language, data FROM tmp_dictionary;
CREATE UNIQUE INDEX ix_dictionary_user_language ON dictionary (user_id, language);
DROP TABLE tmp_dictionary;

@ -14,23 +14,18 @@ and cd into that directory. From there, run the following command in a shell:
./bin/installto.sh <TARGET-FOLDER>
For <TARGET-FOLDER> you specify the path to the Roundcube installation
which should be updated. The update script will then copy all new files to the
For <TARGET-FOLDER> you specify the path to the Roundcube installation
which should be updated. The update script will then copy all new files to the
target location and check and update the configuration and database schema.
After all is done, the temporary folder with the new Roundcube files can be
After all is done, the temporary folder with the new Roundcube files can be
removed again.
WARNING: Make sure files have proper owner/group for your setup. If you use
tar to extract the package, `--no-same-owner` option might be helpful.
WARNING: See Post-Upgrade Activities section below.
WARNING: If you use MySQL < 5.7.7 or MariaDB < 10.2.2 make sure to configure it with:
innodb_large_prefix=true
innodb_file_format=Barracuda
Updating manually
-----------------
If you don't have shell access to the Roundcube installation or if not running
If you don't have shell access to the Roundcube installation or if not running
it on a unix system, you need to do the following operations by hand:
1. Replace index.php and all files in
@ -46,24 +41,15 @@ it on a unix system, you need to do the following operations by hand:
./skins/
./plugins/
./vendor/
4. Update dependencies:
4a. If you previously installed plugins through composer, update dependencies
by running `php composer.phar update --no-dev`.
by running `php composer.phar update --no-dev`
4b. Install/update dependencies using composer:
- get composer from https://getcomposer.org/download/
- rename the composer.json-dist file into composer.json
- if you want to use LDAP address books, enable the LDAP libraries in your
composer.json file by moving the items from "suggest" to the "require"
section (remove the explanation texts after the version!).
- run `php composer.phar install --no-dev`.
4c. If you use git sources or the release package without dependencies
update javascript dependencies by executing `bin/install-jsdeps.sh` script.
4d. If you use git sources compile css files for the Elastic skin (required
lessc >= 1.5.0):
$ cd skins/elastic
$ lessc -x styles/styles.less > styles/styles.css
$ lessc -x styles/print.less > styles/print.css
$ lessc -x styles/embed.less > styles/embed.css
- run `php composer.phar install --no-dev`
5. Run `./bin/update.sh` from the commandline OR
open http://url-to-roundcube/installer/ in a browser and choose "3 Test config".
To enable the latter one, you have to temporary set 'enable_installer'
@ -77,14 +63,12 @@ it on a unix system, you need to do the following operations by hand:
Post-Upgrade Activities
-----------------------
1. Check system requirements in INSTALL file.
1. Check .htaccess settings (some php settings could become required)
2. If you're using build-in addressbook, run indexing script /bin/indexcontacts.sh.
3. When upgrading from version older than 0.6-beta you should make sure
your folder settings contain namespace prefix. For example Courier users
should add INBOX. prefix to folder names in main configuration file.
4. When upgrading from version older than 1.4.0 make sure old files
in configured temp_dir are removed. Since this version we use constant filename
prefix and do not remove files not starting with "RCMTEMP".
4. Check system requirements in INSTALL file.
SQLite database upgrade
-----------------------

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/cleandb.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2010, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -12,6 +13,7 @@
| |
| PURPOSE: |
| Finally remove all db records marked as deleted some time ago |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
@ -21,9 +23,56 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require INSTALL_PATH.'program/include/clisetup.php';
// mapping for table name => primary key
$primary_keys = array(
'contacts' => "contact_id",
'contactgroups' => "contactgroup_id",
);
// connect to DB
$RCMAIL = rcube::get_instance();
$db = $RCMAIL->get_dbh();
$db->db_connect('w');
if (!$db->is_connected() || $db->is_error()) {
rcube::raise_error("No DB connection", false, true);
}
if (!empty($_SERVER['argv'][1]))
$days = intval($_SERVER['argv'][1]);
else
$days = 7;
rcmail_utils::db_clean($days);
// remove all deleted records older than two days
$threshold = date('Y-m-d 00:00:00', time() - $days * 86400);
foreach (array('contacts','contactgroups','identities') as $table) {
$sqltable = $db->table_name($table, true);
// also delete linked records
// could be skipped for databases which respect foreign key constraints
if ($db->db_provider == 'sqlite'
&& ($table == 'contacts' || $table == 'contactgroups')
) {
$pk = $primary_keys[$table];
$memberstable = $db->table_name('contactgroupmembers');
$db->query(
"DELETE FROM " . $db->quote_identifier($memberstable).
" WHERE `$pk` IN (".
"SELECT `$pk` FROM $sqltable".
" WHERE `del` = 1 AND `changed` < ?".
")",
$threshold);
echo $db->affected_rows() . " records deleted from '$memberstable'\n";
}
// delete outdated records
$db->query("DELETE FROM $sqltable WHERE `del` = 1 AND `changed` < ?", $threshold);
echo $db->affected_rows() . " records deleted from '$table'\n";
}
?>

@ -5,42 +5,42 @@ VERSION='2.4.8'
COMPILER_URL="https://github.com/yui/yuicompressor/releases/download/v${VERSION}/yuicompressor-${VERSION}.zip"
do_shrink() {
rm -f "$2"
java -jar $JAR_DIR/yuicompressor.jar -v -o "$2" "$1"
rm -f "$2"
java -jar $JAR_DIR/yuicompressor.jar -v -o "$2" "$1"
}
if [ ! -w "$JAR_DIR" ]; then
JAR_DIR=$PWD
JAR_DIR=$PWD
fi
if java -version >/dev/null 2>&1; then
:
:
else
echo "Java not found. Please ensure that the 'java' program is in your PATH."
exit 1
echo "Java not found. Please ensure that the 'java' program is in your PATH."
exit 1
fi
if [ ! -r "$JAR_DIR/yuicompressor.jar" ]; then
if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
wget "$COMPILER_URL" -O "/tmp/$$.zip"
elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
curl -L "$COMPILER_URL" -o "/tmp/$$.zip"
else
echo "Please download $COMPILER_URL and extract compiler.jar to $JAR_DIR/."
exit 1
fi
(cd $JAR_DIR && unzip "/tmp/$$.zip" && mv "yuicompressor-${VERSION}.jar" "yuicompressor.jar")
rm -f "/tmp/$$.zip"
if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
wget "$COMPILER_URL" -O "/tmp/$$.zip"
elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
curl "$COMPILER_URL" -o "/tmp/$$.zip"
else
echo "Please download $COMPILER_URL and extract compiler.jar to $JAR_DIR/."
exit 1
fi
(cd $JAR_DIR && unzip "/tmp/$$.zip" && mv "yuicompressor-${VERSION}.jar" "yuicompressor.jar")
rm -f "/tmp/$$.zip"
fi
# compress single file from argument
if [ $# -gt 0 ]; then
CSS_FILE="$1"
CSS_FILE="$1"
echo "Shrinking $CSS_FILE"
echo "Shrinking $CSS_FILE"
minfile=`echo $CSS_FILE | sed -e 's/\.css$/\.min\.css/'`
do_shrink "$CSS_FILE" "$minfile"
exit
do_shrink "$CSS_FILE" "$minfile"
exit
fi
DIRS="$PWD/../skins/* $PWD/../plugins/* $PWD/../plugins/*/skins/*"

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/decrypt.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2005-2009, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -12,6 +13,7 @@
| |
| PURPOSE: |
| Decrypt the encrypted parts of the HTTP Received: headers |
| |
+-----------------------------------------------------------------------+
| Author: Tomas Tevesz <ice@extreme.hu> |
+-----------------------------------------------------------------------+
@ -55,11 +57,11 @@ define('INSTALL_PATH', realpath(__DIR__ .'/..') . '/');
require INSTALL_PATH . 'program/include/clisetup.php';
if ($argc < 2) {
die("Usage: " . basename($argv[0]) . " encrypted-hdr-part [encrypted-hdr-part ...]\n");
die("Usage: " . basename($argv[0]) . " encrypted-hdr-part [encrypted-hdr-part ...]\n");
}
$RCMAIL = rcube::get_instance();
for ($i = 1; $i < $argc; $i++) {
printf("%s\n", $RCMAIL->decrypt($argv[$i]));
printf("%s\n", $RCMAIL->decrypt($argv[$i]));
};

@ -3,9 +3,10 @@
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/deluser.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2014, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -25,44 +26,23 @@ require_once INSTALL_PATH . 'program/include/clisetup.php';
function print_usage()
{
print "Usage: deluser.sh [--host=HOST][--age=DAYS][--dry-run] [username]\n";
print "Usage: deluser.sh [--host=mail_host] username\n";
print "--host=HOST The IMAP hostname or IP the given user is related to\n";
print "--age=DAYS Delete all users who have not logged in for more than X days\n";
print "--dry-run List users but do not delete them (for use with --age)\n";
}
function _die($msg, $usage=false)
{
fwrite(STDERR, $msg . "\n");
fputs(STDERR, $msg . "\n");
if ($usage) print_usage();
exit(1);
}
$rcmail = rcube::get_instance();
$rcmail = rcmail::get_instance();
// get arguments
$args = rcube_utils::get_opt(array('h' => 'host', 'a' => 'age', 'd' => 'dry-run:bool'));
if (!empty($args['age']) && ($age = intval($args['age']))) {
$db = $rcmail->get_dbh();
$db->db_connect('r');
$query = $db->query("SELECT `username`, `mail_host` FROM " . $db->table_name('users', true)
. " WHERE `last_login` < " . $db->now($age * -1 * 86400)
. ($args['host'] ? " AND `mail_host` = " . $db->quote($args['host']) : '')
);
while ($user = $db->fetch_assoc($query)) {
if (!empty($args['dry-run'])) {
printf("%s (%s)\n", $user['username'], $user['mail_host']);
continue;
}
system(sprintf("php %s/deluser.sh --host=%s %s", INSTALL_PATH . 'bin', $user['mail_host'], $user['username']));
}
exit(1);
}
$args = rcube_utils::get_opt(array('h' => 'host'));
$username = trim($args[0]);
if (empty($username)) {
_die("Missing required parameters", true);
}
@ -95,7 +75,7 @@ if (!$db->is_connected() || $db->is_error()) {
_die("No DB connection\n" . $db->is_error());
}
// find user in local database
// find user in loca database
$user = rcube_user::query($username, $args['host']);
if (!$user) {
@ -142,3 +122,4 @@ else {
echo "Successfully deleted user $user->ID\n";
}
}

@ -0,0 +1,97 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| bin/dumpschema.sh |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2005-2009, 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: |
| Dumps database schema in XML format using MDB2_Schema |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require INSTALL_PATH.'program/include/clisetup.php';
/** callback function for schema dump **/
function print_schema($dump)
{
foreach ((array)$dump as $part)
echo $dump . "\n";
}
$config = new rcube_config();
// don't allow public access if not in devel_mode
if (!$config->get('devel_mode') && $_SERVER['REMOTE_ADDR']) {
header("HTTP/1.0 401 Access denied");
die("Access denied!");
}
$options = array(
'use_transactions' => false,
'log_line_break' => "\n",
'idxname_format' => '%s',
'debug' => false,
'quote_identifier' => true,
'force_defaults' => false,
'portability' => false,
);
$dsnw = $config->get('db_dsnw');
$dsn_array = MDB2::parseDSN($dsnw);
// set options for postgres databases
if ($dsn_array['phptype'] == 'pgsql') {
$options['disable_smart_seqname'] = true;
$options['seqname_format'] = '%s';
}
$schema =& MDB2_Schema::factory($dsnw, $options);
$schema->db->supported['transactions'] = false;
// send as text/xml when opened in browser
if ($_SERVER['REMOTE_ADDR'])
header('Content-Type: text/xml');
if (PEAR::isError($schema)) {
$error = $schema->getMessage() . ' ' . $schema->getUserInfo();
}
else {
$dump_config = array(
// 'output_mode' => 'file',
'output' => 'print_schema',
);
$definition = $schema->getDefinitionFromDatabase();
$definition['charset'] = 'utf8';
if (PEAR::isError($definition)) {
$error = $definition->getMessage() . ' ' . $definition->getUserInfo();
}
else {
$operation = $schema->dumpDatabase($definition, $dump_config, MDB2_SCHEMA_DUMP_STRUCTURE);
if (PEAR::isError($operation)) {
$error = $operation->getMessage() . ' ' . $operation->getUserInfo();
}
}
}
$schema->disconnect();
if ($error && !$_SERVER['REMOTE_ADDR'])
fputs(STDERR, $error);
?>

@ -0,0 +1,233 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| bin/exportgettext.sh |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2011, The Roundcube Dev Team |
| Licensed under the GNU General Public License |
| |
| PURPOSE: |
| Export PHP-based localization files to PO files for gettext |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require INSTALL_PATH.'program/include/clisetup.php';
if ($argc < 2) {
die("Usage: " . basename($argv[0]) . " SRCDIR DESTDIR\n");
}
$srcdir = unslashify(realpath($argv[1]));
$destdir = unslashify($argv[2]);
$layout = 'launchpad'; # or 'narro';
$langcode_map = array(
'hy_AM' => 'hy',
'ar_SA' => 'ar',
'az_AZ' => 'az',
'bg_BG' => 'bg',
'bs_BA' => 'bs',
'ca_ES' => 'ca',
'cs_CZ' => 'cs',
'cy_GB' => 'cy',
'da_DK' => 'da',
'et_EE' => 'et',
'el_GR' => 'el',
'eu_ES' => 'eu',
'fa_IR' => 'fa',
'ga_IE' => 'ga',
'ka_GE' => 'ka',
'gl_ES' => 'gl',
'he_IL' => 'he',
'hi_IN' => 'hi',
'hr_HR' => 'hr',
'ja_JP' => 'ja',
'ko_KR' => 'ko',
'km_KH' => 'km',
'ms_MY' => 'ms',
'mr_IN' => 'mr',
'ml_IN' => 'ml',
'pl_PL' => 'pl',
'si_LK' => 'si',
'sl_SI' => 'sl',
'sq_AL' => 'sq',
'sr_CS' => 'sr',
'sv_SE' => 'sv',
'uk_UA' => 'uk',
'vi_VN' => 'vi',
);
// converting roundcube localization dir
if (is_dir($srcdir.'/en_US')) {
load_en_US($srcdir.'/en_US');
foreach (glob($srcdir.'/*') as $locdir) {
if (is_dir($locdir)) {
$lang = basename($locdir);
//echo "$locdir => $destdir$lang\n";
convert_dir($locdir, $destdir . ($layout != 'launchpad' ? $lang : ''));
}
}
}
// converting single localization directory
else if (is_dir($srcdir)) {
if (is_file($srcdir.'/en_US.inc')) // plugin localization
load_en_US($srcdir.'/en_US.inc');
else
load_en_US(realpath($srcdir.'/../en_US')); // single language
convert_dir($srcdir, $destdir);
}
// converting a single file
else if (is_file($srcdir)) {
//load_en_US();
convert_file($srcdir, $destdir);
}
/**
* Load en_US localization which is used to build msgids
*/
function load_en_US($fn)
{
$texts = array();
if (is_dir($fn)) {
foreach (glob($fn.'/*.inc') as $ifn) {
include($ifn);
$texts = array_merge($texts, (array)$labels, (array)$messages);
}
}
else if (is_file($fn)) {
include($fn);
$texts = array_merge($texts, (array)$labels, (array)$messages);
}
$GLOBALS['en_US'] = $texts;
}
/**
* Convert all .inc files in the given src directory
*/
function convert_dir($indir, $outdir)
{
global $layout;
if (!is_dir($outdir)) // attempt to create destination dir
mkdir($outdir, 0777, true);
foreach (glob($indir.'/*.inc') as $fn) {
$filename = basename($fn);
// create subdir for each template (launchpad rules)
if ($layout == 'launchpad' && preg_match('/^(labels|messages)/', $filename, $m)) {
$lang = end(explode('/', $indir));
$destdir = $outdir . '/' . $m[1];
if (!is_dir($destdir))
mkdir($destdir, 0777, true);
$outfn = $destdir . '/' . $lang . '.po';
}
else {
$outfn = $outdir . '/' . preg_replace('/\.[a-z0-9]+$/i', '', basename($fn)) . '.po';
}
convert_file($fn, $outfn);
}
}
/**
* Convert the given Roundcube localization file into a gettext .po file
*/
function convert_file($fn, $outfn)
{
global $layout, $langcode_map;
$basename = basename($fn);
$srcname = str_replace(INSTALL_PATH, '', $fn);
$product = preg_match('!plugins/(\w+)!', $srcname, $m) ? 'roundcube-plugin-' . $m[1] : 'roundcubemail';
$lang = preg_match('!/([a-z]{2}(_[A-Z]{2})?)[./]!', $outfn, $m) ? $m[1] : '';
$labels = $messages = $seen = array();
if (is_dir($outfn))
$outfn .= '/' . $basename . '.po';
// launchpad requires the template file to have the same name as the directory
if (strstr($outfn, '/en_US') && $layout == 'launchpad') {
$a = explode('/', $outfn);
array_pop($a);
$templ = end($a);
$a[] = $templ . '.pot';
$outfn = join('/', $a);
$is_pot = true;
}
// launchpad is very picky about file names
else if ($layout == 'launchpad' && preg_match($regex = '!/([a-z]{2})_([A-Z]{2})!', $outfn, $m)) {
if ($shortlang = $langcode_map[$lang])
$outfn = preg_replace($regex, '/'.$shortlang, $outfn);
else if ($m[1] == strtolower($m[2]))
$outfn = preg_replace($regex, '/\1', $outfn);
}
include($fn);
$texts = array_merge($labels, $messages);
// write header
$header = <<<EOF
# Converted from Roundcube PHP localization files
# Copyright (C) 2011 The Roundcube Dev Team
# This file is distributed under the same license as the Roundcube package.
#
#: %s
msgid ""
msgstr ""
"Project-Id-Version: %s\\n"
"Report-Msgid-Bugs-To: \\n"
"%s: %s\\n"
"Last-Translator: \\n"
"Language-Team: Translations <hello@roundcube.net>\\n"
"Language: %s\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
EOF;
$out = sprintf($header, $srcname, $product, $is_pot ? "POT-Creation-Date" : "PO-Revision-Date", date('c'), $shortlang ? $shortlang : $lang);
$out .= "\n";
$messages = array();
foreach ((array)$texts as $label => $msgstr) {
$msgid = $is_pot ? $msgstr : ($GLOBALS['en_US'][$label] ?: $label);
$messages[$msgid][] = $label;
}
foreach ($messages as $msgid => $labels) {
$out .= "\n";
foreach ($labels as $label)
$out .= "#: $srcname:$label\n";
$msgstr = $texts[$label];
$out .= 'msgid ' . gettext_quote($msgid) . "\n";
$out .= 'msgstr ' . gettext_quote(!$is_pot ? $msgstr : '') . "\n";
}
if ($outfn == '-')
echo $out;
else {
echo "$fn\t=>\t$outfn\n";
file_put_contents($outfn, $out);
}
}
function gettext_quote($str)
{
$out = "";
$lines = explode("\n", wordwrap(stripslashes($str)));
$last = count($lines) - 1;
foreach ($lines as $i => $line)
$out .= '"' . addcslashes($line, '"') . ($i < $last ? ' ' : '') . "\"\n";
return rtrim($out);
}
?>

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/gc.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -12,6 +13,7 @@
| |
| PURPOSE: |
| Trigger garbage collecting routines manually (e.g. via cronjob) |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+

@ -0,0 +1,196 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| bin/importgettext.sh |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2011, The Roundcube Dev Team |
| Licensed under the GNU General Public License |
| |
| PURPOSE: |
| Import localizations from gettext PO format |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require INSTALL_PATH.'program/include/clisetup.php';
if ($argc < 2) {
die("Usage: " . basename($argv[0]) . " SRCDIR\n");
}
$srcdir = unslashify(realpath($argv[1]));
if (is_dir($srcdir)) {
$out = import_dir($srcdir);
}
else if (is_file($srcdir)) {
$out = import_file($srcdir);
}
// write output files
foreach ($out as $outfn => $texts) {
$lang = preg_match('!/([a-z]{2}(_[A-Z]{2})?)[./]!', $outfn, $m) ? $m[1] : '';
$varname = strpos($outfn, 'messages.inc') !== false ? 'messages' : 'labels';
$header = <<<EOF
<?php
/*
+-----------------------------------------------------------------------+
| localization/%s/%-51s|
| |
| Language file of the Roundcube Webmail client |
| Copyright (C) %s, The Roundcube Dev Team |
| Licensed under the GNU General Public License |
| |
+-----------------------------------------------------------------------+
| Author: %-62s|
+-----------------------------------------------------------------------+
*/
$%s = array();
EOF;
$author = preg_replace('/\s*<Unknown>/i', '', $texts['_translator']);
$output = sprintf($header, $lang, $varname.'.inc', date('Y'), $author, $varname);
foreach ($texts as $label => $value) {
if (is_array($value)) { var_dump($outfn, $label, $value); exit; }
if ($label[0] != '_' && strlen($value))
$output .= sprintf("\$%s['%s'] = '%s';\n", $varname, $label, strtr(addcslashes($value, "'"), array("\r" => '', "\n" => '\n')));
}
$output .= "\n";
$dir = dirname($outfn);
@mkdir($dir, 0755, true);
if (file_put_contents($outfn, $output))
echo "-> $outfn\n";
}
/**
* Convert all .po files in the given src directory
*/
function import_dir($indir)
{
$out = array();
foreach (glob($indir.'/*.po') as $fn) {
$out = array_merge_recursive($out, import_file($fn));
}
return $out;
}
/**
* Convert the given .po file into a Roundcube localization array
*/
function import_file($fn)
{
$out = array();
$lines = file($fn);
$language = '';
$translator = '';
// get language code from file name
if (preg_match('/-([a-z_]+).po$/i', $fn, $m))
$language = expand_langcode($m[1]);
$is_header = true;
$msgid = null;
$msgstr = '';
$dests = array();
foreach ($lines as $i => $line) {
$line = trim($line);
// parse header
if ($is_header && $line[0] == '"') {
list($key, $val) = explode(": ", preg_replace('/\\\n$/', '', trim($line, '"')), 2);
switch (strtolower($key)) {
case 'language':
$language = expand_langcode($val);
break;
case 'last-translator':
$translator = $val;
break;
}
}
// empty line
if ($line == '') {
if ($msgid && $dests) {
foreach ($dests as $dest) {
list($file, $label) = explode(':', $dest);
$out[$file][$label] = $msgstr;
$out[$file]['_translator'] = $translator;
}
}
$msgid = null;
$msgstr = '';
$dests = array();
}
// meta line
if ($line[0] == '#') {
$value = trim(substr($line, 2));
if ($line[1] == ':')
$dests[] = str_replace('en_US', $language, $value);
}
else if (strpos($line, 'msgid') === 0) {
$msgid = gettext_decode(substr($line, 6));
if (!empty($msgid))
$is_header = false;
}
else if (strpos($line, 'msgstr') === 0) {
$msgstr = gettext_decode(substr($line, 7));
}
else if ($msgid && $line[0] == '"') {
$msgstr .= gettext_decode($line);
}
else if ($msgid !== null && $line[0] == '"') {
$msgid .= gettext_decode($line);
}
}
if ($msgid && $dests) {
foreach ($dests as $dest) {
list($file, $label) = explode(':', $dest);
$out[$file][$label] = $msgstr;
$out[$file]['_translator'] = $translator;
}
}
return $language ? $out : array();
}
function gettext_decode($str)
{
return stripslashes(trim($str, '"'));
}
/**
* Translate two-chars language codes to our internally used language identifiers
*/
function expand_langcode($lang)
{
static $rcube_language_aliases, $rcube_languages;
if (!$rcube_language_aliases)
include(INSTALL_PATH . 'program/localization/index.inc');
if ($rcube_language_aliases[$lang])
return $rcube_language_aliases[$lang];
else if (strlen($lang) == 2 && !isset($rcube_languages[$lang]))
return strtolower($lang) . '_' . strtoupper($lang);
else
return $lang;
}
?>

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/indexcontacts.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2011, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -23,4 +24,31 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require_once INSTALL_PATH.'program/include/clisetup.php';
ini_set('memory_limit', -1);
rcmail_utils::indexcontacts();
// connect to DB
$RCMAIL = rcube::get_instance();
$db = $RCMAIL->get_dbh();
$db->db_connect('w');
if (!$db->is_connected() || $db->is_error()) {
rcube::raise_error("No DB connection", false, true);
}
// iterate over all users
$sql_result = $db->query("SELECT `user_id` FROM " . $db->table_name('users', true) . " ORDER BY `user_id`");
while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
echo "Indexing contacts for user " . $sql_arr['user_id'] . "...";
$contacts = new rcube_contacts($db, $sql_arr['user_id']);
$contacts->set_pagesize(9999);
$result = $contacts->list_records();
while ($result->count && ($row = $result->next())) {
unset($row['words']);
$contacts->update($row['ID'], $row);
}
echo "done.\n";
}
?>

@ -1,39 +0,0 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) Kolab Systems AG |
| |
| 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: |
| Create database schema |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require_once INSTALL_PATH . 'program/include/clisetup.php';
// get arguments
$opts = rcube_utils::get_opt(array(
'd' => 'dir',
));
if (empty($opts['dir'])) {
rcube::raise_error("Database schema directory not specified (--dir).", false, true);
}
// Check if directory exists
if (!file_exists($opts['dir'])) {
rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
}
rcmail_utils::db_init($opts['dir']);

@ -1,385 +0,0 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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: |
| Utility script to fetch and install all 3rd party javascript |
| libraries used in Roundcube from source. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <thomas@roundcube.net> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require_once INSTALL_PATH . 'program/include/clisetup.php';
if (!function_exists('exec')) {
rcube::raise_error("PHP exec() function is required. Check disable_functions in php.ini.", false, true);
}
$cfgfile = INSTALL_PATH . 'jsdeps.json';
$SOURCES = json_decode(file_get_contents($cfgfile), true);
if (empty($SOURCES['dependencies'])) {
rcube::raise_error("Failed to read dependencies list from $cfgfile", false, true);
}
$CURL = trim(`which curl`);
$WGET = trim(`which wget`);
$UNZIP = trim(`which unzip`);
if (($CACHEDIR = getenv("CACHEDIR")) && is_writeable($CACHEDIR)) {
// use $CACHEDIR
}
else if (is_writeable(INSTALL_PATH . 'temp/js_cache') || @mkdir(INSTALL_PATH . 'temp/js_cache', 0774, true)) {
$CACHEDIR = INSTALL_PATH . 'temp/js_cache';
}
else {
$CACHEDIR = sys_get_temp_dir();
}
//////////////// License definitions
$LICENSES = array();
$LICENSES['MIT'] = <<<EOM
* Licensed under the MIT licenses
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
EOM;
$LICENSES['GPLv3'] = <<<EOG
* 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 (GNU GPL) 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.
*
* As additional permission under GNU GPL version 3 section 7, you
* may distribute non-source (e.g., minimized or compacted) forms of
* that code without the copy of the GNU GPL normally required by
* section 4, provided you include this license notice and a URL
* through which recipients can access the Corresponding Source.
EOG;
$LICENSES['LGPL'] = <<<EOL
* The JavaScript code in this page is free software: you can
* redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
EOL;
//////////////// Functions
/**
* Fetch package file from source
*/
function fetch_from_source($package, $useCache = true, &$filetype = null)
{
global $CURL, $WGET;
$cache_file = extract_filetype($package, $filetype);
if (!is_readable($cache_file) || !$useCache) {
if (empty($CURL) && empty($WGET)) {
rcube::raise_error("Required 'wget' or 'curl' program not found.", false, true);
}
$url = str_replace('$v', $package['version'], $package['url']);
echo "Fetching $url\n";
if ($CURL)
exec(sprintf('%s -L -s %s -o %s', $CURL, escapeshellarg($url), $cache_file), $out, $retval);
else
exec(sprintf('%s -q %s -O %s', $WGET, escapeshellarg($url), $cache_file), $out, $retval);
// Try Github API as a fallback (#6248)
if ($retval !== 0 && $package['api_url']) {
$url = str_replace('$v', $package['version'], $package['api_url']);
$header = 'Accept:application/vnd.github.v3.raw';
rcube::raise_error("Fetching failed. Using Github API on $url");
if ($CURL)
exec(sprintf('%s -L -H %s -s %s -o %s', $CURL, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval);
else
exec(sprintf('%s --header %s -q %s -O %s', $WGET, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval);
}
if ($retval !== 0) {
rcube::raise_error("Failed to download source file from $url", false, true);
}
}
return $cache_file;
}
/**
* Returns package source file location and type
*/
function extract_filetype($package, &$filetype = null)
{
global $CACHEDIR;
$filetype = pathinfo($package['url'], PATHINFO_EXTENSION) ?: 'tmp';
$cache_file = $CACHEDIR . '/' . $package['lib'] . '-' . $package['version'] . '.' . $filetype;
// Make sure it is a zip file
if (file_exists($cache_file)) {
$magic = file_get_contents($cache_file, false, null, 0, 4);
if ($magic === "PK\003\004") {
$filetype = 'zip';
}
}
return $cache_file;
}
/**
* Create a destination javascript file with copyright and license header
*/
function compose_destfile($package, $srcfile)
{
global $LICENSES;
$header = sprintf("/**\n * %s - v%s\n *\n", $package['name'], $package['version']);
if (!empty($package['source'])) {
$header .= " * @source " . str_replace('$v', $package['version'], $package['source']) . "\n";
$header .= " *\n";
}
if (!empty($package['license']) && isset($LICENSES[$package['license']])) {
$header .= " * @licstart The following is the entire license notice for the\n";
$header .= " * JavaScript code in this file.\n";
$header .= " *\n";
if (!empty($package['copyright'])) {
$header .= " * " . $package['copyright'] . "\n";
$header .= " *\n";
}
$header .= $LICENSES[$package['license']];
$header .= " *\n";
$header .= " * @licend The above is the entire license notice\n";
$header .= " * for the JavaScript code in this file.\n";
}
$header .= " */\n";
if (file_put_contents(INSTALL_PATH . $package['dest'], $header . file_get_contents($srcfile))) {
echo "Wrote file " . INSTALL_PATH . $package['dest'] . "\n";
}
else {
rcube::raise_error("Failed to write destination file " . INSTALL_PATH . $package['dest'], false, true);
}
}
/**
* Extract a Zip archive into the destination specified by the package config
*/
function extract_zipfile($package, $srcfile)
{
global $UNZIP, $CACHEDIR;
if (empty($UNZIP)) {
rcube::raise_error("Required 'unzip' program not found.", false, true);
}
$destdir = INSTALL_PATH . $package['dest'];
if (!is_dir($destdir)) {
mkdir($destdir, 0775, true);
}
if (!is_writeable($destdir)) {
rcube::raise_error("Cannot write to destination directory: $destdir", false, true);
}
// pick files from zip archive
if (!empty($package['pick'])) {
foreach ($package['pick'] as $pattern) {
echo "Extracting files $pattern into $destdir\n";
exec(sprintf('%s -o %s %s -d %s', $UNZIP, escapeshellarg($srcfile), escapeshellarg($pattern), $destdir), $out, $retval);
if ($retval !== 0) {
rcube::raise_error("Failed to unpack $pattern; " . implode('; ' . $out));
}
}
}
// unzip the archive and map source to dest files/directories
else if (!empty($package['map'])) {
$extract = $CACHEDIR . '/' . $package['lib'] . '-extract';
if (!is_dir($extract)) {
mkdir($extract, 0774, true);
}
$zip_command = '%s -' . ($package['flat'] ? 'j' : 'o') . ' %s -d %s';
exec(sprintf($zip_command, $UNZIP, escapeshellarg($srcfile), $extract), $out, $retval);
// get the root folder of the extracted package
$extract_tree = glob("$extract/*", GLOB_ONLYDIR);
$sourcedir = count($extract_tree) ? $extract_tree[0] : $extract;
foreach ($package['map'] as $src => $dest) {
echo "Installing $sourcedir/$src into $destdir/$dest\n";
$dest_file = $destdir . '/' . $dest;
$src_file = $sourcedir . '/' . $src;
// make sure the destination's parent directory exists
if (strpos($dest, '/') !== false) {
$parentdir = dirname($dest_file);
if (!is_dir($parentdir)) {
mkdir($parentdir, 0775, true);
}
}
// avoid copying source directory as a child into destination
if (is_dir($src_file) && is_dir($dest_file)) {
exec(sprintf('rm -rf %s', $dest_file));
}
exec(sprintf('mv -f %s %s', $src_file, $dest_file), $out, $retval);
if ($retval !== 0) {
rcube::raise_error("Failed to move $src into $dest_file; " . implode('; ' . $out));
}
// Remove sourceMappingURL
else if (isset($package['sourcemap']) && $package['sourcemap'] === false) {
if ($content = file($dest_file)) {
$index = count($content);
if (preg_match('|sourceMappingURL=|', $content[$index-1])) {
array_pop($content);
file_put_contents($dest_file, implode('', $content));
}
}
}
}
// remove temp extraction dir
exec('rm -rf ' . $extract);
}
// extract the archive into the destination directory
else {
echo "Extracting zip archive into $destdir\n";
exec(sprintf('%s -o %s -d %s', $UNZIP, escapeshellarg($srcfile), $destdir), $out, $retval);
if ($retval !== 0) {
rcube::raise_error("Failed to unzip $srcfile; " . implode('; ' . $out));
}
}
// remove some files from the destination
if (!empty($package['omit'])) {
foreach ((array)$package['omit'] as $glob) {
exec(sprintf('rm -rf %s/%s', $destdir, escapeshellarg($glob)));
}
}
// prepend license header to extracted files
if (!empty($package['addlicense'])) {
foreach ((array)$package['addlicense'] as $filename) {
$pkg = $package;
$pkg['dest'] = $package['dest'] . '/' . $filename;
compose_destfile($pkg, $destdir . '/' . $filename);
}
}
}
/**
* Delete the package destination file/dir
*/
function delete_destfile($package)
{
$destdir = INSTALL_PATH . ($package['rm'] ?: $package['dest']);
if (file_exists($destdir)) {
if (PHP_OS === 'Windows') {
exec(sprintf("rd /s /q %s", escapeshellarg($destdir)));
}
else {
exec(sprintf("rm -rf %s", escapeshellarg($destdir)));
}
}
}
//////////////// Execution
$args = rcube_utils::get_opt(array('f' => 'force:bool', 'd' => 'delete:bool', 'g' => 'get:bool', 'e' => 'extract:bool'))
+ array('force' => false, 'delete' => false, 'get' => false, 'extract' => false);
$WHAT = $args[0];
$useCache = !$args['force'] && !$args['get'];
if (!$args['get'] && !$args['extract'] && !$args['delete']) {
$args['get'] = $args['extract'] = 1;
}
foreach ($SOURCES['dependencies'] as $package) {
if (!isset($package['name'])) {
$package['name'] = $package['lib'];
}
if ($WHAT && $package['lib'] !== $WHAT) {
continue;
}
if ($args['delete']) {
delete_destfile($package);
continue;
}
if ($args['get']) {
$srcfile = fetch_from_source($package, $useCache, $filetype);
}
else {
$srcfile = extract_filetype($package, $filetype);
}
if (!empty($package['sha1']) && ($sum = sha1_file($srcfile)) !== $package['sha1']) {
rcube::raise_error("Incorrect sha1 sum of $srcfile. Expected: {$package['sha1']}, got: $sum", false, true);
}
if ($args['extract']) {
echo "Installing {$package['name']}...\n";
if ($filetype === 'zip') {
extract_zipfile($package, $srcfile);
}
else {
compose_destfile($package, $srcfile);
}
echo "Done.\n";
}
}

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/installto.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2014, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -22,127 +23,65 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require_once INSTALL_PATH . 'program/include/clisetup.php';
if (!function_exists('system')) {
rcube::raise_error("PHP system() function is required. Check disable_functions in php.ini.", false, true);
}
$target_dir = unslashify(end($_SERVER['argv']));
$accept = in_array('-y', $_SERVER['argv']) ? 'y' : null;
$target_dir = unslashify($_SERVER['argv'][1]);
if (empty($target_dir) || !is_dir(realpath($target_dir)))
rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh [-y] <TARGET>", false, true);
rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh <TARGET>", false, true);
// read version from iniset.php
$iniset = @file_get_contents($target_dir . '/program/include/iniset.php');
if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z0-9-]*)/', $iniset, $m))
rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true);
if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)/', $iniset, $m))
rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true);
$oldversion = $m[1];
if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>'))
rcube::raise_error("Target installation already in version $oldversion.", false, true);
if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>='))
rcube::raise_error("Installation at target location is up-to-date!", false, true);
if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '==')) {
echo "Target installation already in version $oldversion. Do you want to update again? (y/N)\n";
}
else {
echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n";
}
$input = $accept ?: trim(fgets(STDIN));
echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n";
$input = trim(fgets(STDIN));
if (strtolower($input) == 'y') {
echo "Copying files to target location...";
$adds = array();
$dirs = array('bin','SQL','plugins','skins','program');
if (is_dir(INSTALL_PATH . 'vendor') && !is_file("$target_dir/composer.json")) {
$dirs[] = 'vendor';
}
if (file_exists("$target_dir/installer")) {
$dirs[] = 'installer';
}
foreach ($dirs as $dir) {
// @FIXME: should we use --delete for all directories?
$delete = in_array($dir, array('program', 'vendor', 'installer')) ? '--delete ' : '';
$command = "rsync -aC --out-format=%n " . $delete . INSTALL_PATH . "$dir/ $target_dir/$dir/";
if (system($command, $ret) === false || $ret > 0) {
rcube::raise_error("Failed to execute command: $command", false, true);
}
}
foreach (array('index.php','config/defaults.inc.php','composer.json-dist','jsdeps.json','CHANGELOG','README.md','UPGRADING','LICENSE','INSTALL') as $file) {
$command = "rsync -a --out-format=%n " . INSTALL_PATH . "$file $target_dir/$file";
if (file_exists(INSTALL_PATH . $file) && (system($command, $ret) === false || $ret > 0)) {
rcube::raise_error("Failed to execute command: $command", false, true);
}
$err = false;
echo "Copying files to target location...";
$dirs = array('program','installer','bin','SQL','plugins','skins');
if (is_dir(INSTALL_PATH . 'vendor') && !is_file(INSTALL_PATH . 'composer.json')) {
$dirs[] = 'vendor';
}
foreach ($dirs as $dir) {
if (!system("rsync -avC " . INSTALL_PATH . "$dir/* $target_dir/$dir/")) {
$err = true;
break;
}
// Copy .htaccess or .user.ini if needed
foreach (array('.htaccess','.user.ini') as $file) {
if (file_exists(INSTALL_PATH . $file)) {
if (!file_exists("$target_dir/$file") || file_get_contents(INSTALL_PATH . $file) != file_get_contents("$target_dir/$file")) {
if (copy(INSTALL_PATH . $file, "$target_dir/$file.new")) {
echo "$file.new\n";
$adds[] = "NOTICE: New $file file saved as $file.new.";
}
}
}
}
// remove old (<1.0) .htaccess file
@unlink("$target_dir/program/.htaccess");
echo "done.\n\n";
if (is_dir("$target_dir/skins/default")) {
echo "Removing old default skin...";
system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default");
foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) {
$plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir);
if (is_dir("$target_dir/$plugin_skin_dir/classic")) {
system("rm -rf $target_dir/$plugin_skin_dir/default");
}
}
echo "done.\n\n";
}
// Warn about situation when using "complete" package to update "custom" installation (#7087)
// Note: "Complete" package do not include jsdeps.json nor install-jsdeps.sh
if (file_exists("$target_dir/jsdeps.json") && !file_exists(INSTALL_PATH . "jsdeps.json")) {
$adds[] = "WARNING: JavaScript dependencies update skipped.";
}
// check if js-deps are up-to-date
else if (file_exists("$target_dir/jsdeps.json") && file_exists("$target_dir/bin/install-jsdeps.sh")) {
$jsdeps = json_decode(file_get_contents("$target_dir/jsdeps.json"));
$package = $jsdeps->dependencies[0];
$dest_file = $target_dir . '/' . $package->dest;
if (!file_exists($dest_file) || sha1_file($dest_file) !== $package->sha1) {
echo "Installing JavaScript dependencies...";
system("cd $target_dir && bin/install-jsdeps.sh");
echo "done.\n\n";
}
}
foreach (array('index.php','.htaccess','config/defaults.inc.php','composer.json-dist','CHANGELOG','README.md','UPGRADING','LICENSE','INSTALL') as $file) {
if (!system("rsync -av " . INSTALL_PATH . "$file $target_dir/$file")) {
$err = true;
break;
}
else {
$adds[] = "NOTICE: JavaScript dependencies installation skipped.";
}
if (file_exists("$target_dir/installer")) {
$adds[] = "NOTICE: The 'installer' directory still exists. You should remove it after the upgrade.";
}
if (!empty($adds)) {
echo implode("\n", $adds) . "\n\n";
}
}
// remove old (<1.0) .htaccess file
@unlink("$target_dir/program/.htaccess");
echo "done.\n\n";
if (is_dir("$target_dir/skins/default")) {
echo "Removing old default skin...";
system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default");
foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) {
$plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir);
if (is_dir("$target_dir/$plugin_skin_dir/classic"))
system("rm -rf $target_dir/$plugin_skin_dir/default");
}
echo "done.\n\n";
}
if (!$err) {
echo "Running update script at target...\n";
system("cd $target_dir && php bin/update.sh --version=$oldversion" . ($accept ? ' -y' : ''));
system("cd $target_dir && php bin/update.sh --version=$oldversion");
echo "All done.\n";
}
}
else {
echo "Update cancelled. See ya!\n";
}
else
echo "Update cancelled. See ya!\n";
?>

@ -2,61 +2,63 @@
PWD=`dirname "$0"`
JS_DIR="$PWD/../program/js"
JAR_DIR='/tmp'
LANG_IN='ECMASCRIPT5'
CLOSURE_COMPILER_URL='http://dl.google.com/closure-compiler/compiler-latest.zip'
LANG_IN='ECMASCRIPT3'
# latest version requires Java 7, we'll use an older one
#CLOSURE_COMPILER_URL='http://dl.google.com/closure-compiler/compiler-latest.zip'
CLOSURE_COMPILER_URL='http://dl.google.com/closure-compiler/compiler-20131014.zip'
do_shrink() {
rm -f "$2"
# copy the first comment block with license information for LibreJS
grep -q '@lic' $1 && sed -n '/\/\*/,/\*\// { p; /\*\//q; }' $1 > $2
java -jar $JAR_DIR/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js="$1" --language_in="$3" >> $2
rm -f "$2"
# copy the first comment block with license information for LibreJS
grep -q '@lic' $1 && sed -n '/\/\*/,/\*\// { p; /\*\//q; }' $1 > $2
java -jar $JAR_DIR/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js="$1" --language_in="$3" >> $2
}
if [ ! -d "$JS_DIR" ]; then
echo "Directory $JS_DIR not found."
exit 1
echo "Directory $JS_DIR not found."
exit 1
fi
if [ ! -w "$JAR_DIR" ]; then
JAR_DIR=$PWD
JAR_DIR=$PWD
fi
if java -version >/dev/null 2>&1; then
:
:
else
echo "Java not found. Please ensure that the 'java' program is in your PATH."
exit 1
echo "Java not found. Please ensure that the 'java' program is in your PATH."
exit 1
fi
if [ ! -r "$JAR_DIR/compiler.jar" ]; then
if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
wget "$CLOSURE_COMPILER_URL" -O "/tmp/$$.zip"
elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
curl "$CLOSURE_COMPILER_URL" -o "/tmp/$$.zip"
else
echo "Please download $CLOSURE_COMPILER_URL and extract compiler.jar to $JAR_DIR/."
exit 1
fi
unzip -p "/tmp/$$.zip" "*.jar" > "$JAR_DIR/compiler.jar"
rm -f "/tmp/$$.zip"
if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
wget "$CLOSURE_COMPILER_URL" -O "/tmp/$$.zip"
elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then
curl "$CLOSURE_COMPILER_URL" -o "/tmp/$$.zip"
else
echo "Please download $CLOSURE_COMPILER_URL and extract compiler.jar to $JAR_DIR/."
exit 1
fi
(cd $JAR_DIR && unzip "/tmp/$$.zip" "compiler.jar")
rm -f "/tmp/$$.zip"
fi
# compress single file from argument
if [ $# -gt 0 ]; then
JS_DIR=`dirname "$1"`
JS_FILE="$1"
JS_DIR=`dirname "$1"`
JS_FILE="$1"
if [ $# -gt 1 ]; then
LANG_IN="$2"
fi
if [ $# -gt 1 ]; then
LANG_IN="$2"
fi
echo "Shrinking $JS_FILE"
echo "Shrinking $JS_FILE"
minfile=`echo $JS_FILE | sed -e 's/\.js$/\.min\.js/'`
do_shrink "$JS_FILE" "$minfile" "$LANG_IN"
exit
do_shrink "$JS_FILE" "$minfile" "$LANG_IN"
exit
fi
DIRS="$PWD/../program/js $PWD/../skins/* $PWD/../plugins/* $PWD/../plugins/*/skins/* $PWD/../plugins/managesieve/codemirror/lib"
DIRS="$PWD/../program/js $PWD/../skins/* $PWD/../plugins/* $PWD/../plugins/*/skins/*"
# default: compress application scripts
for dir in $DIRS; do
for file in $dir/*.js; do

@ -19,5 +19,6 @@ OUTPUTFORMAT=HTML
TEMPLATE=responsive-twig
# make documentation
$BIN_PHPDOC -d $PATH_PROJECT,$PATH_FRAMEWORK -t $PATH_DOCS --title "$TITLE" \
--defaultpackagename $PACKAGES --template=$TEMPLATE
$BIN_PHPDOC -d $PATH_PROJECT,$PATH_FRAMEWORK -t $PATH_DOCS --title "$TITLE" --defaultpackagename $PACKAGES \
--template=$TEMPLATE

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/moduserprefs.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -23,43 +24,59 @@ require_once INSTALL_PATH.'program/include/clisetup.php';
function print_usage()
{
print "Usage: moduserprefs.sh [options] pref-name [pref-value]\n";
print "Options:\n";
print " --user=user-id User ID in local database\n";
print " --config=path Location of additional configuration file\n";
print " --delete Unset the given preference\n";
print " --type=type Pref-value type: int, bool, string\n";
print "Usage: moduserprefs.sh [--user=user-id] pref-name [pref-value|--delete]\n";
print "--user User ID in local database\n";
print "--delete Unset the given preference\n";
}
// get arguments
$args = rcube_utils::get_opt(array(
'u' => 'user',
'd' => 'delete:bool',
't' => 'type',
'c' => 'config',
));
$args = rcube_utils::get_opt(array('u' => 'user', 'd' => 'delete'));
if ($_SERVER['argv'][1] == 'help') {
print_usage();
exit;
print_usage();
exit;
}
else if (empty($args[0]) || (empty($args[1]) && empty($args['delete']))) {
print "Missing required parameters.\n";
print_usage();
exit;
else if (empty($args[0]) || (!isset($args[1]) && !$args['delete'])) {
print "Missing required parameters.\n";
print_usage();
exit;
}
$pref_name = trim($args[0]);
$pref_value = $args['delete'] ? null : trim($args[1]);
if ($pref_value === null) {
$args['type'] = null;
}
// connect to DB
$rcmail = rcube::get_instance();
$db = $rcmail->get_dbh();
$db->db_connect('w');
if (!$db->is_connected() || $db->is_error())
die("No DB connection\n" . $db->is_error());
$query = '1=1';
if ($args['user'])
$query = '`user_id` = ' . intval($args['user']);
// iterate over all users
$sql_result = $db->query("SELECT * FROM " . $db->table_name('users', true) . " WHERE $query");
while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
echo "Updating prefs for user " . $sql_arr['user_id'] . "...";
$user = new rcube_user($sql_arr['user_id'], $sql_arr);
$prefs = $old_prefs = $user->get_prefs();
$prefs[$pref_name] = $pref_value;
if ($args['config']) {
$rcube = rcube::get_instance();
$rcube->config->load_from_file($args['config']);
if ($prefs != $old_prefs) {
$user->save_prefs($prefs, true);
echo "saved.\n";
}
else {
echo "nothing changed.\n";
}
}
rcmail_utils::mod_pref($pref_name, $pref_value, $args['user'], $args['type']);
?>

@ -1,18 +1,5 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <thomas@roundcube.net> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
ini_set('memory_limit', -1);
@ -21,84 +8,89 @@ require_once INSTALL_PATH.'program/include/clisetup.php';
function print_usage()
{
print "Usage: msgexport -h imap-host -u user-name -m mailbox name\n";
print "--host IMAP host\n";
print "--user IMAP user name\n";
print "--mbox Folder name, set to '*' for all\n";
print "--file Output file\n";
print "Usage: msgexport -h imap-host -u user-name -m mailbox name\n";
print "--host IMAP host\n";
print "--user IMAP user name\n";
print "--mbox Folder name, set to '*' for all\n";
print "--file Output file\n";
}
function vputs($str)
{
$out = $GLOBALS['args']['file'] ? STDOUT : STDERR;
fwrite($out, $str);
$out = $GLOBALS['args']['file'] ? STDOUT : STDERR;
fwrite($out, $str);
}
function progress_update($pos, $max)
{
$percent = round(100 * $pos / $max);
vputs(sprintf("%3d%% [%-51s] %d/%d\033[K\r", $percent, @str_repeat('=', $percent / 2) . '>', $pos, $max));
$percent = round(100 * $pos / $max);
vputs(sprintf("%3d%% [%-51s] %d/%d\033[K\r", $percent, @str_repeat('=', $percent / 2) . '>', $pos, $max));
}
function export_mailbox($mbox, $filename)
{
global $IMAP;
global $IMAP;
$IMAP->set_folder($mbox);
$IMAP->set_folder($mbox);
$index = $IMAP->index($mbox, null, 'ASC');
$count = $index->count();
$index = $index->get();
vputs("Getting message list of {$mbox}...");
vputs("$count messages\n");
if ($filename) {
if (!($out = fopen($filename, 'w'))) {
vputs("Cannot write to output file\n");
return;
}
vputs("Writing to $filename\n");
}
else {
$out = STDOUT;
}
for ($i = 0; $i < $count; $i++) {
$headers = $IMAP->get_message_headers($index[$i]);
$from = current(rcube_mime::decode_address_list($headers->from, 1, false));
fwrite($out, sprintf("From %s %s UID %d\n", $from['mailto'], $headers->date, $headers->uid));
$IMAP->get_raw_body($headers->uid, $out);
fwrite($out, "\n\n\n");
progress_update($i+1, $count);
}
vputs("\ncomplete.\n");
if ($filename) {
fclose($out);
}
vputs("Getting message list of {$mbox}...");
vputs("$count messages\n");
if ($filename)
{
if (!($out = fopen($filename, 'w')))
{
vputs("Cannot write to output file\n");
return;
}
vputs("Writing to $filename\n");
}
else
$out = STDOUT;
for ($i = 0; $i < $count; $i++)
{
$headers = $IMAP->get_message_headers($index[$i]);
$from = current(rcube_mime::decode_address_list($headers->from, 1, false));
fwrite($out, sprintf("From %s %s UID %d\n", $from['mailto'], $headers->date, $headers->uid));
$IMAP->get_raw_body($headers->uid, $out);
fwrite($out, "\n\n\n");
progress_update($i+1, $count);
}
vputs("\ncomplete.\n");
if ($filename)
fclose($out);
}
// get arguments
$opts = array('h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file');
$args = rcube_utils::get_opt($opts) + array('host' => 'localhost', 'mbox' => 'INBOX');
if ($_SERVER['argv'][1] == 'help') {
print_usage();
exit;
if ($_SERVER['argv'][1] == 'help')
{
print_usage();
exit;
}
else if (!$args['host']) {
vputs("Missing required parameters.\n");
print_usage();
exit;
else if (!$args['host'])
{
vputs("Missing required parameters.\n");
print_usage();
exit;
}
// prompt for username if not set
if (empty($args['user'])) {
vputs("IMAP user: ");
$args['user'] = trim(fgets(STDIN));
if (empty($args['user']))
{
vputs("IMAP user: ");
$args['user'] = trim(fgets(STDIN));
}
// prompt for password
@ -107,39 +99,45 @@ $args['pass'] = rcube_utils::prompt_silent("Password: ");
// parse $host URL
$a_host = parse_url($args['host']);
if ($a_host['host']) {
$host = $a_host['host'];
$imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
if ($a_host['host'])
{
$host = $a_host['host'];
$imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
}
else {
$host = $args['host'];
$imap_port = 143;
else
{
$host = $args['host'];
$imap_port = 143;
}
// instantiate IMAP class
$IMAP = new rcube_imap(null);
// try to connect to IMAP server
if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) {
vputs("IMAP login successful.\n");
if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl))
{
vputs("IMAP login successful.\n");
$filename = null;
$mailboxes = $args['mbox'] == '*' ? $IMAP->list_folders(null) : array($args['mbox']);
$filename = null;
$mailboxes = $args['mbox'] == '*' ? $IMAP->list_folders(null) : array($args['mbox']);
foreach ($mailboxes as $mbox) {
if ($args['file'])
$filename = preg_replace('/\.[a-z0-9]{3,4}$/i', '', $args['file']) . asciiwords($mbox) . '.mbox';
else if ($args['mbox'] == '*')
$filename = asciiwords($mbox) . '.mbox';
foreach ($mailboxes as $mbox)
{
if ($args['file'])
$filename = preg_replace('/\.[a-z0-9]{3,4}$/i', '', $args['file']) . asciiwords($mbox) . '.mbox';
else if ($args['mbox'] == '*')
$filename = asciiwords($mbox) . '.mbox';
if ($args['mbox'] == '*' && in_array(strtolower($mbox), array('junk','spam','trash'))) {
continue;
}
if ($args['mbox'] == '*' && in_array(strtolower($mbox), array('junk','spam','trash')))
continue;
export_mailbox($mbox, $filename);
}
export_mailbox($mbox, $filename);
}
}
else {
vputs("IMAP login failed.\n");
else
{
vputs("IMAP login failed.\n");
}
?>

@ -1,18 +1,5 @@
#!/usr/bin/env php
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <thomas@roundcube.net> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
ini_set('memory_limit', -1);
@ -21,11 +8,11 @@ require_once INSTALL_PATH.'program/include/clisetup.php';
function print_usage()
{
print "Usage: msgimport -h imap-host -u user-name -m mailbox -f message-file\n";
print "--host IMAP host\n";
print "--user IMAP user name\n";
print "--mbox Target mailbox\n";
print "--file Message file to upload\n";
print "Usage: msgimport -h imap-host -u user-name -m mailbox -f message-file\n";
print "--host IMAP host\n";
print "--user IMAP user name\n";
print "--mbox Target mailbox\n";
print "--file Message file to upload\n";
}
@ -33,80 +20,94 @@ function print_usage()
$opts = array('h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file');
$args = rcube_utils::get_opt($opts) + array('host' => 'localhost', 'mbox' => 'INBOX');
if ($_SERVER['argv'][1] == 'help') {
print_usage();
exit;
if ($_SERVER['argv'][1] == 'help')
{
print_usage();
exit;
}
else if (!($args['host'] && $args['file'])) {
print "Missing required parameters.\n";
print_usage();
exit;
else if (!($args['host'] && $args['file']))
{
print "Missing required parameters.\n";
print_usage();
exit;
}
else if (!is_file($args['file'])) {
rcube::raise_error("Cannot read message file.", false, true);
else if (!is_file($args['file']))
{
rcube::raise_error("Cannot read message file.", false, true);
}
// prompt for username if not set
if (empty($args['user'])) {
//fwrite(STDOUT, "Please enter your name\n");
echo "IMAP user: ";
$args['user'] = trim(fgets(STDIN));
if (empty($args['user']))
{
//fwrite(STDOUT, "Please enter your name\n");
echo "IMAP user: ";
$args['user'] = trim(fgets(STDIN));
}
// prompt for password
if (empty($args['pass'])) {
$args['pass'] = rcube_utils::prompt_silent("Password: ");
if (empty($args['pass']))
{
$args['pass'] = rcube_utils::prompt_silent("Password: ");
}
// parse $host URL
$a_host = parse_url($args['host']);
if ($a_host['host']) {
$host = $a_host['host'];
$imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
if ($a_host['host'])
{
$host = $a_host['host'];
$imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
}
else {
$host = $args['host'];
$imap_port = 143;
else
{
$host = $args['host'];
$imap_port = 143;
}
// instantiate IMAP class
$IMAP = new rcube_imap(null);
// try to connect to IMAP server
if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) {
print "IMAP login successful.\n";
print "Uploading messages...\n";
$count = 0;
$message = $lastline = '';
$fp = fopen($args['file'], 'r');
while (($line = fgets($fp)) !== false) {
if (preg_match('/^From\s+-/', $line) && $lastline == '') {
if (!empty($message)) {
if ($IMAP->save_message($args['mbox'], rtrim($message)))
$count++;
else
rcube::raise_error("Failed to save message to {$args['mbox']}", false, true);
$message = '';
}
continue;
}
$message .= $line;
$lastline = rtrim($line);
}
if (!empty($message) && $IMAP->save_message($args['mbox'], rtrim($message)))
$count++;
// upload message from file
if ($count)
print "$count messages successfully added to {$args['mbox']}.\n";
else
print "Adding messages failed!\n";
if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl))
{
print "IMAP login successful.\n";
print "Uploading messages...\n";
$count = 0;
$message = $lastline = '';
$fp = fopen($args['file'], 'r');
while (($line = fgets($fp)) !== false)
{
if (preg_match('/^From\s+-/', $line) && $lastline == '')
{
if (!empty($message))
{
if ($IMAP->save_message($args['mbox'], rtrim($message)))
$count++;
else
rcube::raise_error("Failed to save message to {$args['mbox']}", false, true);
$message = '';
}
continue;
}
$message .= $line;
$lastline = rtrim($line);
}
if (!empty($message) && $IMAP->save_message($args['mbox'], rtrim($message)))
$count++;
// upload message from file
if ($count)
print "$count messages successfully added to {$args['mbox']}.\n";
else
print "Adding messages failed!\n";
}
else {
rcube::raise_error("IMAP login failed.", false, true);
else
{
rcube::raise_error("IMAP login failed.", false, true);
}
?>

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/package2composer.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -12,6 +13,7 @@
| |
| PURPOSE: |
| Convert a plugin's package.xml file into a composer.json description |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <thomas@roundcube.net> |
+-----------------------------------------------------------------------+
@ -40,7 +42,7 @@ $data = array(
'version' => strval($package->version->release),
'authors' => array(),
'repositories' => array(
array('type' => 'composer', 'url' => 'https://plugins.roundcube.net'),
array('type' => 'composer', 'url' => 'http://plugins.roundcube.net'),
),
'require' => array(
'php' => '>=5.3.0',
@ -95,7 +97,7 @@ else if (defined('JSON_PRETTY_PRINT')) {
echo json_encode($data, $flags);
}
else {
fwrite(STDERR,
fputs(STDERR,
"FAILED! composer.phar not found in current directory.
Please download it from http://getcomposer.org/download/ or with
@ -104,3 +106,4 @@ Please download it from http://getcomposer.org/download/ or with
}
echo "\n";

@ -39,6 +39,6 @@ done
# remove empty localization files
for file in $PWD/../program/localization/*/labels.inc; do grep -q -E '\$labels' $file || rm $file; done
for file in $PWD/../program/localization/*/timezones.inc; do grep -q -E '\$labels' $file || rm $file; done
for file in $PWD/../program/localization/*/messages.inc; do grep -q -E '\$messages' $file || rm $file; done
for file in $PWD/../plugins/*/localization/*.inc; do grep -q -E '\$(labels|messages)' $file || rm $file; done

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/update.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2010-2015, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -23,271 +24,238 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
require_once INSTALL_PATH . 'program/include/clisetup.php';
// get arguments
$opts = rcube_utils::get_opt(array('v' => 'version', 'y' => 'accept:bool'));
$opts = rcube_utils::get_opt(array('v' => 'version', 'y' => 'accept'));
// ask user if no version is specified
if (!$opts['version']) {
echo "What version are you upgrading from? Type '?' if you don't know.\n";
if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z0-9-]*$/', $input)) {
$opts['version'] = $input;
}
else {
$opts['version'] = RCMAIL_VERSION;
}
echo "What version are you upgrading from? Type '?' if you don't know.\n";
if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z-]*$/', $input))
$opts['version'] = $input;
else
$opts['version'] = RCMAIL_VERSION;
}
$RCI = rcmail_install::get_instance();
$RCI->load_config();
if ($RCI->configured) {
$success = true;
if (($messages = $RCI->check_config($opts['version'])) || $RCI->legacy_config) {
$success = false;
$err = 0;
$success = true;
if (($messages = $RCI->check_config()) || $RCI->legacy_config) {
$success = false;
$err = 0;
// list old/replaced config options
if (is_array($messages['replaced'])) {
echo "WARNING: Replaced config options:\n";
echo "(These config options have been replaced or renamed)\n";
foreach ($messages['replaced'] as $msg) {
echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n";
$err++;
}
echo "\n";
}
// list old/replaced config options
if (is_array($messages['replaced'])) {
echo "WARNING: Replaced config options:\n";
echo "(These config options have been replaced or renamed)\n";
// list obsolete config options (just a notice)
if (is_array($messages['obsolete'])) {
echo "NOTICE: Obsolete config options:\n";
echo "(You still have some obsolete or inexistent properties set. This isn't a problem but should be noticed)\n";
foreach ($messages['replaced'] as $msg) {
echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n";
$err++;
}
}
foreach ($messages['obsolete'] as $msg) {
echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n";
$err++;
}
echo "\n";
}
// list obsolete config options (just a notice)
if (is_array($messages['obsolete'])) {
echo "NOTICE: Obsolete config options:\n";
echo "(You still have some obsolete or inexistent properties set."
. " This isn't a problem but should be noticed)\n";
if (!$err && $RCI->legacy_config) {
echo "WARNING: Your configuration needs to be migrated!\n";
echo "We changed the configuration files structure and your two config files main.inc.php and db.inc.php have to be merged into one single file.\n";
$err++;
}
foreach ($messages['obsolete'] as $msg) {
echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n";
$err++;
}
}
// ask user to update config files
if ($err) {
if (!$opts['accept']) {
echo "Do you want me to fix your local configuration? (y/N)\n";
$input = trim(fgets(STDIN));
}
if (!$err && $RCI->legacy_config) {
echo "WARNING: Your configuration needs to be migrated!\n";
echo "We changed the configuration files structure and your two config files "
. "main.inc.php and db.inc.php have to be merged into one single file.\n";
$err++;
}
// positive: let's merge the local config with the defaults
if ($opts['accept'] || strtolower($input) == 'y') {
$error = $written = false;
// ask user to update config files
if ($err) {
if (!$opts['accept']) {
echo "Do you want me to fix your local configuration? (y/N)\n";
$input = trim(fgets(STDIN));
}
// backup current config
echo ". backing up the current config file(s)...\n";
// positive: merge the local config with the defaults
if ($opts['accept'] || strtolower($input) == 'y') {
$error = $written = false;
echo ". backing up the current config file(s)...\n";
foreach (array('config', 'main', 'db') as $file) {
if (file_exists(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php')) {
if (!copy(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php', RCMAIL_CONFIG_DIR . '/' . $file . '.old.php')) {
$error = true;
}
}
}
if (!$error) {
$RCI->merge_config();
echo ". writing " . RCMAIL_CONFIG_DIR . "/config.inc.php...\n";
$written = $RCI->save_configfile($RCI->create_config());
}
// Success!
if ($written) {
echo "Done.\n";
echo "Your configuration files are now up-to-date!\n";
if ($messages['missing']) {
echo "But you still need to add the following missing options:\n";
foreach ($messages['missing'] as $msg) {
echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n";
}
}
if ($RCI->legacy_config) {
foreach (array('main', 'db') as $file) {
@unlink(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php');
}
}
}
else {
echo "Failed to write config file(s)!\n";
echo "Grant write privileges to the current user or update the files manually "
. "according to the above messages.\n";
}
}
else {
echo "Please update your config files manually according to the above messages.\n";
foreach (array('config', 'main', 'db') as $file) {
if (file_exists(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php')) {
if (!copy(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php', RCMAIL_CONFIG_DIR . '/' . $file . '.old.php')) {
$error = true;
}
}
}
// list of config options with changed default (just a notice)
if (!empty($messages['defaults'])) {
echo "WARNING: Changed defaults (These config options have new default values):\n";
foreach ($messages['defaults'] as $opt) {
echo "- '{$opt}'\n";
}
if (!$error) {
$RCI->merge_config();
echo ". writing " . RCMAIL_CONFIG_DIR . "/config.inc.php...\n";
$written = $RCI->save_configfile($RCI->create_config());
}
// check dependencies based on the current configuration
if (is_array($messages['dependencies'])) {
echo "WARNING: Dependency check failed!\n";
echo "(Some of your configuration settings require other options to be configured "
. "or additional PHP modules to be installed)\n";
// Success!
if ($written) {
echo "Done.\n";
echo "Your configuration files are now up-to-date!\n";
foreach ($messages['dependencies'] as $msg) {
echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n";
}
if ($messages['missing']) {
echo "But you still need to add the following missing options:\n";
foreach ($messages['missing'] as $msg)
echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n";
}
echo "Please fix your config files and run this script again!\n";
echo "See ya.\n";
if ($RCI->legacy_config) {
foreach (array('main', 'db') as $file) {
@unlink(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php');
}
}
}
else {
echo "Failed to write config file(s)!\n";
echo "Grant write privileges to the current user or update the files manually according to the above messages.\n";
}
}
else {
echo "Please update your config files manually according to the above messages.\n";
}
}
// check file type detection
if ($RCI->check_mime_detection()) {
echo "WARNING: File type detection doesn't work properly!\n";
echo "Please check the 'mime_magic' config option or the finfo functions of PHP and run this script again.\n";
}
if ($RCI->check_mime_extensions()) {
echo "WARNING: Mimetype to file extension mapping doesn't work properly!\n";
echo "Please check the 'mime_types' config option and run this script again.\n";
}
// check dependencies based on the current configuration
if (is_array($messages['dependencies'])) {
echo "WARNING: Dependency check failed!\n";
echo "(Some of your configuration settings require other options to be configured or additional PHP modules to be installed)\n";
// check database schema
if ($RCI->config['db_dsnw']) {
echo "Executing database schema update.\n";
$success = rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $opts['version'],
array('errors' => true));
foreach ($messages['dependencies'] as $msg) {
echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n";
}
echo "Please fix your config files and run this script again!\n";
echo "See ya.\n";
}
// update composer dependencies
if (is_file(INSTALL_PATH . 'composer.json') && is_readable(INSTALL_PATH . 'composer.json-dist')) {
$composer_data = json_decode(file_get_contents(INSTALL_PATH . 'composer.json'), true);
$composer_template = json_decode(file_get_contents(INSTALL_PATH . 'composer.json-dist'), true);
$comsposer_json = null;
// update the require section with the new dependencies
if (is_array($composer_data['require']) && is_array($composer_template['require'])) {
$composer_data['require'] = array_merge($composer_data['require'], $composer_template['require']);
// remove obsolete packages
$old_packages = array(
'pear-pear.php.net/net_socket',
'pear-pear.php.net/auth_sasl',
'pear-pear.php.net/net_idna2',
'pear-pear.php.net/mail_mime',
'pear-pear.php.net/net_smtp',
'pear-pear.php.net/crypt_gpg',
'pear-pear.php.net/net_sieve',
'pear/mail_mime-decode',
'roundcube/net_sieve',
'endroid/qrcode',
);
foreach ($old_packages as $pkg) {
if (array_key_exists($pkg, $composer_data['require'])) {
unset($composer_data['require'][$pkg]);
}
}
}
// update the repositories section with the new dependencies
if (is_array($composer_template['repositories'])) {
if (!is_array($composer_data['repositories'])) {
$composer_data['repositories'] = array();
}
foreach ($composer_template['repositories'] as $repo) {
$rkey = $repo['type'] . preg_replace('/^https?:/', '', $repo['url']) . $repo['package']['name'];
$existing = false;
foreach ($composer_data['repositories'] as $k => $_repo) {
if ($rkey == $_repo['type'] . preg_replace('/^https?:/', '', $_repo['url']) . $_repo['package']['name']) {
// switch to https://
if (isset($_repo['url']) && strpos($_repo['url'], 'http://') === 0) {
$composer_data['repositories'][$k]['url'] = 'https:' . substr($_repo['url'], 5);
}
$existing = true;
break;
}
// remove old repos
if (strpos($_repo['url'], 'git://git.kolab.org') === 0) {
unset($composer_data['repositories'][$k]);
}
else if ($_repo['type'] == 'package' && $_repo['package']['name'] == 'Net_SMTP') {
unset($composer_data['repositories'][$k]);
}
}
if (!$existing) {
$composer_data['repositories'][] = $repo;
}
}
$composer_data['repositories'] = array_values($composer_data['repositories']);
}
// check file type detection
if ($RCI->check_mime_detection()) {
echo "WARNING: File type detection doesn't work properly!\n";
echo "Please check the 'mime_magic' config option or the finfo functions of PHP and run this script again.\n";
}
if ($RCI->check_mime_extensions()) {
echo "WARNING: Mimetype to file extension mapping doesn't work properly!\n";
echo "Please check the 'mime_types' config option and run this script again.\n";
}
// check database schema
if ($RCI->config['db_dsnw']) {
echo "Executing database schema update.\n";
system("php " . INSTALL_PATH . "bin/updatedb.sh --package=roundcube --version=" . $opts['version']
. " --dir=" . INSTALL_PATH . "SQL", $res);
$success = !$res;
}
// update composer dependencies
if (is_file(INSTALL_PATH . 'composer.json') && is_readable(INSTALL_PATH . 'composer.json-dist')) {
$composer_data = json_decode(file_get_contents(INSTALL_PATH . 'composer.json'), true);
$composer_template = json_decode(file_get_contents(INSTALL_PATH . 'composer.json-dist'), true);
$comsposer_json = null;
// update the require section with the new dependencies
if (is_array($composer_data['require']) && is_array($composer_template['require'])) {
$composer_data['require'] = array_merge($composer_data['require'], $composer_template['require']);
/* TO BE ADDED LATER
$old_packages = array();
for ($old_packages as $pkg) {
if (array_key_exists($composer_data['require'], $pkg)) {
unset($composer_data['require'][$pkg]);
}
}
*/
}
// use the JSON encoder from the Composer package
if (is_file('composer.phar')) {
include 'phar://composer.phar/src/Composer/Json/JsonFile.php';
$comsposer_json = \Composer\Json\JsonFile::encode($composer_data);
}
// PHP 5.4's json_encode() does the job, too
else if (defined('JSON_PRETTY_PRINT')) {
$comsposer_json = json_encode($composer_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
else {
$success = false;
$comsposer_json = null;
// update the repositories section with the new dependencies
if (is_array($composer_template['repositories'])) {
if (!is_array($composer_data['repositories'])) {
$composer_data['repositories'] = array();
}
foreach ($composer_template['repositories'] as $repo) {
$rkey = $repo['type'] . preg_replace('/^https?:/', '', $repo['url']) . $repo['package']['name'];
$existing = false;
foreach ($composer_data['repositories'] as $k => $_repo) {
if ($rkey == $_repo['type'] . preg_replace('/^https?:/', '', $_repo['url']) . $_repo['package']['name']) {
$existing = true;
break;
}
// remove old repos
else if (strpos($_repo['url'], 'git://git.kolab.org') === 0) {
unset($composer_data['repositories'][$k]);
}
}
// write updated composer.json back to disk
if ($comsposer_json && is_writeable(INSTALL_PATH . 'composer.json')) {
$success &= (bool)file_put_contents(INSTALL_PATH . 'composer.json', $comsposer_json);
if (!$existing) {
$composer_data['repositories'][] = $repo;
}
else {
echo "WARNING: unable to update composer.json!\n";
echo "Please replace the 'require' section in your composer.json with the following:\n";
}
$require_json = '';
foreach ($composer_data['require'] as $pkg => $ver) {
$require_json .= sprintf(' "%s": "%s",'."\n", $pkg, $ver);
}
echo ' "require": {'."\n";
echo rtrim($require_json, ",\n");
echo "\n }\n\n";
}
$composer_data['repositories'] = array_values($composer_data['repositories']);
}
echo "NOTICE: Update dependencies by running `php composer.phar update --no-dev`\n";
// use the JSON encoder from the Composer package
if (is_file('composer.phar')) {
include 'phar://composer.phar/src/Composer/Json/JsonFile.php';
$comsposer_json = \Composer\Json\JsonFile::encode($composer_data);
}
// PHP 5.4's json_encode() does the job, too
else if (defined('JSON_PRETTY_PRINT')) {
$comsposer_json = json_encode($composer_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
else {
$success = false;
$comsposer_json = null;
}
// index contacts for fulltext searching
if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) {
rcmail_utils::indexcontacts();
// write updated composer.json back to disk
if ($comsposer_json && is_writeable(INSTALL_PATH . 'composer.json')) {
$success &= (bool)file_put_contents(INSTALL_PATH . 'composer.json', $comsposer_json);
}
else {
echo "WARNING: unable to update composer.json!\n";
echo "Please replace the 'require' section in your composer.json with the following:\n";
$require_json = '';
foreach ($composer_data['require'] as $pkg => $ver) {
$require_json .= sprintf(' "%s": "%s",'."\n", $pkg, $ver);
}
if ($success) {
echo "This instance of Roundcube is up-to-date.\n";
echo "Have fun!\n";
echo ' "require": {'."\n";
echo rtrim($require_json, ",\n");
echo "\n }\n\n";
}
echo "NOTE: Update dependencies by running `php composer.phar update --no-dev`\n";
}
// index contacts for fulltext searching
if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) {
system("php " . INSTALL_PATH . 'bin/indexcontacts.sh');
}
if ($success) {
echo "This instance of Roundcube is up-to-date.\n";
echo "Have fun!\n";
}
}
else {
echo "This instance of Roundcube is not yet configured!\n";
echo "Open http://url-to-roundcube/installer/ in your browser and follow the instuctions.\n";
echo "This instance of Roundcube is not yet configured!\n";
echo "Open http://url-to-roundcube/installer/ in your browser and follow the instuctions.\n";
}
?>

@ -2,9 +2,10 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/updatecss.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2010-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -117,3 +118,5 @@ function get_files($dir)
return $files;
}
?>

@ -2,10 +2,11 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| bin/updatedb.sh |
| |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) Kolab Systems AG |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2010-2012, The Roundcube Dev Team |
| Copyright (C) 2010-2012, Kolab Systems AG |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -36,4 +37,142 @@ if (empty($opts['package'])) {
rcube::raise_error("Database schema package name not specified (--package).", false, true);
}
rcmail_utils::db_update($opts['dir'], $opts['package'], $opts['version'], array('errors' => true));
// Check if directory exists
if (!file_exists($opts['dir'])) {
rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
}
$RC = rcube::get_instance();
$DB = rcube_db::factory($RC->config->get('db_dsnw'));
$DB->set_debug((bool)$RC->config->get('sql_debug'));
// Connect to database
$DB->db_connect('w');
if (!$DB->is_connected()) {
rcube::raise_error("Error connecting to database: " . $DB->is_error(), false, true);
}
// Read DB schema version from database (if 'system' table exists)
if (in_array($DB->table_name('system'), (array)$DB->list_tables())) {
$DB->query("SELECT `value`"
." FROM " . $DB->table_name('system', true)
." WHERE `name` = ?",
$opts['package'] . '-version');
$row = $DB->fetch_array();
$version = preg_replace('/[^0-9]/', '', $row[0]);
}
// DB version not found, but release version is specified
if (!$version && $opts['version']) {
// Map old release version string to DB schema version
// Note: This is for backward compat. only, do not need to be updated
$map = array(
'0.1-stable' => 1,
'0.1.1' => 2008030300,
'0.2-alpha' => 2008040500,
'0.2-beta' => 2008060900,
'0.2-stable' => 2008092100,
'0.2.1' => 2008092100,
'0.2.2' => 2008092100,
'0.3-stable' => 2008092100,
'0.3.1' => 2009090400,
'0.4-beta' => 2009103100,
'0.4' => 2010042300,
'0.4.1' => 2010042300,
'0.4.2' => 2010042300,
'0.5-beta' => 2010100600,
'0.5' => 2010100600,
'0.5.1' => 2010100600,
'0.5.2' => 2010100600,
'0.5.3' => 2010100600,
'0.5.4' => 2010100600,
'0.6-beta' => 2011011200,
'0.6' => 2011011200,
'0.7-beta' => 2011092800,
'0.7' => 2011111600,
'0.7.1' => 2011111600,
'0.7.2' => 2011111600,
'0.7.3' => 2011111600,
'0.7.4' => 2011111600,
'0.8-beta' => 2011121400,
'0.8-rc' => 2011121400,
'0.8.0' => 2011121400,
'0.8.1' => 2011121400,
'0.8.2' => 2011121400,
'0.8.3' => 2011121400,
'0.8.4' => 2011121400,
'0.8.5' => 2011121400,
'0.8.6' => 2011121400,
'0.9-beta' => 2012080700,
);
$version = $map[$opts['version']];
}
// Assume last version before the 'system' table was added
if (empty($version)) {
$version = 2012080700;
}
$dir = $opts['dir'] . '/' . $DB->db_provider;
if (!file_exists($dir)) {
rcube::raise_error("DDL Upgrade files for " . $DB->db_provider . " driver not found.", false, true);
}
$dh = opendir($dir);
$result = array();
while ($file = readdir($dh)) {
if (preg_match('/^([0-9]+)\.sql$/', $file, $m) && $m[1] > $version) {
$result[] = $m[1];
}
}
sort($result, SORT_NUMERIC);
foreach ($result as $v) {
echo "Updating database schema ($v)... ";
$error = update_db_schema($opts['package'], $v, "$dir/$v.sql");
if ($error) {
echo "[FAILED]\n";
rcube::raise_error("Error in DDL upgrade $v: $error", false, true);
}
echo "[OK]\n";
}
function update_db_schema($package, $version, $file)
{
global $DB;
// read DDL file
if ($sql = file_get_contents($file)) {
if (!$DB->exec_script($sql)) {
return $DB->is_error();
}
}
// escape if 'system' table does not exist
if ($version < 2013011000) {
return;
}
$system_table = $DB->table_name('system', true);
$DB->query("UPDATE " . $system_table
." SET `value` = ?"
." WHERE `name` = ?",
$version, $package . '-version');
if (!$DB->is_error() && !$DB->affected_rows()) {
$DB->query("INSERT INTO " . $system_table
." (`name`, `value`) VALUES (?, ?)",
$package . '-version', $version);
}
return $DB->is_error();
}
?>

@ -3,29 +3,37 @@
"description": "The Roundcube Webmail suite",
"license": "GPL-3.0+",
"repositories": [
{
"type": "pear",
"url": "https://pear.php.net/"
},
{
"type": "composer",
"url": "https://plugins.roundcube.net"
"url": "https://plugins.roundcube.net/"
},
{
"type": "vcs",
"url": "https://git.kolab.org/diffusion/PNL/php-net_ldap.git"
}
],
"require": {
"php": ">=5.4.0",
"pear/pear-core-minimal": "~1.10.1",
"pear/auth_sasl": "~1.1.0",
"pear/net_idna2": "~0.2.0",
"pear/mail_mime": "~1.10.0",
"pear/net_smtp": "~1.8.1",
"pear/crypt_gpg": "~1.6.3",
"pear/net_sieve": "~1.4.3",
"php": ">=5.3.7",
"roundcube/plugin-installer": "~0.1.6",
"masterminds/html5": "~2.5.0",
"endroid/qr-code": "~1.6.5"
"pear-pear.php.net/net_socket": "~1.0.12",
"pear-pear.php.net/auth_sasl": "~1.0.6",
"pear-pear.php.net/net_idna2": "~0.1.1",
"pear-pear.php.net/net_sieve": "~1.3.4",
"pear-pear.php.net/mail_mime": "~1.9.0",
"pear-pear.php.net/net_smtp": "~1.7.1",
"patchwork/utf8": "~1.2.3"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6 || ^7"
"pear-pear.php.net/crypt_gpg": "*",
"phpunit/phpunit": "*"
},
"suggest": {
"kolab/net_ldap3": "~1.1.1 required for connecting to LDAP",
"mkopinsky/zxcvbn-php": "^4.4.2 required for Zxcvbn password strength driver"
}
"pear-pear.php.net/net_ldap2": "~2.1.0 required for connecting to LDAP address books",
"kolab/Net_LDAP3": "dev-master required for connecting to LDAP address books"
},
"minimum-stability": "dev"
}

@ -9,7 +9,7 @@
| from defaults.inc.php to this file to override the defaults. |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -21,17 +21,15 @@ $config = array();
// Database connection string (DSN) for read+write operations
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
// Currently supported db_providers: mysql, pgsql, sqlite, mssql, sqlsrv, oracle
// Currently supported db_providers: mysql, pgsql, sqlite, mssql or sqlsrv
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
// NOTE: for SQLite use absolute path (Linux): 'sqlite:////full/path/to/sqlite.db?mode=0646'
// or (Windows): 'sqlite:///C:/full/path/to/sqlite.db'
// NOTE: for SQLite use absolute path: 'sqlite:////full/path/to/sqlite.db?mode=0646'
$config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
// The IMAP host chosen to perform the log-in.
// The mail host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// Enter hostname with prefix ssl:// to use Implicit TLS, or use
// prefix tls:// to use STARTTLS.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
@ -41,8 +39,8 @@ $config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
$config['default_host'] = 'localhost';
// SMTP server host (for sending mails).
// Enter hostname with prefix ssl:// to use Implicit TLS, or use
// prefix tls:// to use STARTTLS.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// If left blank, the PHP mail() function is used
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
@ -50,20 +48,19 @@ $config['default_host'] = 'localhost';
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
// To specify differnt SMTP servers for different IMAP hosts provide an array
// of IMAP host (no prefix or port) and SMTP server e.g. array('imap.example.com' => 'smtp.example.net')
$config['smtp_server'] = 'localhost';
$config['smtp_server'] = '';
// SMTP port. Use 25 for cleartext, 465 for Implicit TLS, or 587 for STARTTLS (default)
$config['smtp_port'] = 587;
// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
// deprecated SSL over SMTP (aka SMTPS))
$config['smtp_port'] = 25;
// SMTP username (if required) if you use %u as the username Roundcube
// will use the current username for login
$config['smtp_user'] = '%u';
$config['smtp_user'] = '';
// SMTP password (if required) if you use %p as the password Roundcube
// will use the current user's password for login
$config['smtp_pass'] = '%p';
$config['smtp_pass'] = '';
// provide an URL where a user can get support for this Roundcube installation
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
@ -72,9 +69,9 @@ $config['support_url'] = '';
// Name your service. This is displayed on the login screen and in the window title
$config['product_name'] = 'Roundcube Webmail';
// This key is used to encrypt the users imap password which is stored
// in the session record. For the default cipher method it must be
// exactly 24 characters long.
// this key is used to encrypt the users imap password which is stored
// in the session record (and the client cookie if remember password is enabled).
// please provide a string of exactly 24 chars.
// YOUR KEY MUST BE DIFFERENT THAN THE SAMPLE VALUE FOR SECURITY REASONS
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
@ -85,4 +82,4 @@ $config['plugins'] = array(
);
// skin name: folder from skins/
$config['skin'] = 'elastic';
$config['skin'] = 'larry';

@ -1,15 +1,11 @@
<?php
// ---------------------------------------------------------------------
// WARNING: Do not edit this file! Copy configuration to config.inc.php.
// ---------------------------------------------------------------------
/*
+-----------------------------------------------------------------------+
| Default settings for all configuration options |
| Main configuration file with default settings |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) 2005-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@ -25,14 +21,9 @@ $config = array();
// Database connection string (DSN) for read+write operations
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
// Currently supported db_providers: mysql, pgsql, sqlite, mssql, sqlsrv, oracle
// Currently supported db_providers: mysql, pgsql, sqlite, mssql or sqlsrv
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
// Note: for SQLite use absolute path (Linux): 'sqlite:////full/path/to/sqlite.db?mode=0646'
// or (Windows): 'sqlite:///C:/full/path/to/sqlite.db'
// Note: Various drivers support various additional arguments for connection,
// for Mysql: key, cipher, cert, capath, ca, verify_server_cert,
// for Postgres: application_name, sslmode, sslcert, sslkey, sslrootcert, sslcrl, sslcompression, service.
// e.g. 'mysql://roundcube:@localhost/roundcubemail?verify_server_cert=false'
// NOTE: for SQLite use absolute path: 'sqlite:////full/path/to/sqlite.db?mode=0646'
$config['db_dsnw'] = 'mysql://roundcube:@localhost/roundcubemail';
// Database DSN for read-only operations (if empty write database will be used)
@ -71,7 +62,10 @@ $config['db_max_allowed_packet'] = null;
// LOGGING/DEBUGGING
// ----------------------------------
// log driver: 'syslog', 'stdout' or 'file'.
// system error reporting, sum of: 1 = log; 4 = show
$config['debug_level'] = 1;
// log driver: 'syslog' or 'file'.
$config['log_driver'] = 'file';
// date format for log entries
@ -82,9 +76,6 @@ $config['log_date_format'] = 'd-M-Y H:i:s O';
// set to 0 to avoid session IDs being logged.
$config['log_session_id'] = 8;
// Default extension used for log file name
$config['log_file_ext'] = '.log';
// Syslog ident string to use, if using the 'syslog' log driver.
$config['syslog_id'] = 'roundcube';
@ -93,49 +84,38 @@ $config['syslog_id'] = 'roundcube';
$config['syslog_facility'] = LOG_USER;
// Activate this option if logs should be written to per-user directories.
// Data will only be logged if a directory <log_dir>/<username>/ exists and is writable.
// Data will only be logged if a directry <log_dir>/<username>/ exists and is writable.
$config['per_user_logging'] = false;
// Log sent messages to <log_dir>/sendmail.log or to syslog
// Log sent messages to <log_dir>/sendmail or to syslog
$config['smtp_log'] = true;
// Log successful/failed logins to <log_dir>/userlogins.log or to syslog
// Log successful/failed logins to <log_dir>/userlogins or to syslog
$config['log_logins'] = false;
// Log session debug information/authentication errors to <log_dir>/session.log or to syslog
$config['session_debug'] = false;
// Log session authentication errors to <log_dir>/session or to syslog
$config['log_session'] = false;
// Log SQL queries to <log_dir>/sql.log or to syslog
// Log SQL queries to <log_dir>/sql or to syslog
$config['sql_debug'] = false;
// Log IMAP conversation to <log_dir>/imap.log or to syslog
// Log IMAP conversation to <log_dir>/imap or to syslog
$config['imap_debug'] = false;
// Log LDAP conversation to <log_dir>/ldap.log or to syslog
// Log LDAP conversation to <log_dir>/ldap or to syslog
$config['ldap_debug'] = false;
// Log SMTP conversation to <log_dir>/smtp.log or to syslog
// Log SMTP conversation to <log_dir>/smtp or to syslog
$config['smtp_debug'] = false;
// Log Memcache conversation to <log_dir>/memcache.log or to syslog
$config['memcache_debug'] = false;
// Log APC conversation to <log_dir>/apc.log or to syslog
$config['apc_debug'] = false;
// Log Redis conversation to <log_dir>/redis.log or to syslog
$config['redis_debug'] = false;
// ----------------------------------
// IMAP
// ----------------------------------
// The IMAP host chosen to perform the log-in.
// The mail host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// Enter hostname with prefix ssl:// to use Implicit TLS, or use
// prefix tls:// to use STARTTLS.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
@ -149,9 +129,8 @@ $config['default_host'] = 'localhost';
// TCP port used for IMAP connections
$config['default_port'] = 143;
// IMAP authentication method (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null).
// Use 'IMAP' to authenticate with IMAP LOGIN command.
// By default the most secure method (from supported) will be selected.
// IMAP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null to use
// best server supported one)
$config['imap_auth_type'] = null;
// IMAP socket context options
@ -164,7 +143,6 @@ $config['imap_auth_type'] = null;
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ),
// );
// Note: These can be also specified as an array of options indexed by hostname
$config['imap_conn_options'] = null;
// IMAP connection timeout, in seconds. Default: 0 (use default_socket_timeout)
@ -180,18 +158,12 @@ $config['imap_auth_pw'] = null;
// Otherwise it will be determined automatically
$config['imap_delimiter'] = null;
// If you know your imap's folder vendor, you can specify it here.
// Otherwise it will be determined automatically. Use lower-case
// identifiers, e.g. 'dovecot', 'cyrus', 'gimap', 'hmail', 'uw-imap'.
$config['imap_vendor'] = null;
// If IMAP server doesn't support NAMESPACE extension, but you're
// using shared folders or personal root folder is non-empty, you'll need to
// set these options. All can be strings or arrays of strings.
// Note: Folders need to be ended with directory separator, e.g. "INBOX."
// (special directory "~" is an exception to this rule)
// Note: These can be used also to overwrite server's namespaces
// Note: Set these to FALSE to disable access to specified namespace
// Folders need to be ended with directory separator, e.g. "INBOX."
// (special directory "~" is an exception to this rule)
// These can be used also to overwrite server's namespaces
$config['imap_ns_personal'] = null;
$config['imap_ns_other'] = null;
$config['imap_ns_shared'] = null;
@ -203,7 +175,7 @@ $config['imap_force_caps'] = false;
// By default list of subscribed folders is determined using LIST-EXTENDED
// extension if available. Some servers (dovecot 1.x) returns wrong results
// for shared namespaces in this case. https://github.com/roundcube/roundcubemail/issues/2474
// for shared namespaces in this case. http://trac.roundcube.net/ticket/1486225
// Enable this option to force LSUB command usage instead.
// Deprecated: Use imap_disabled_caps = array('LIST-EXTENDED')
$config['imap_force_lsub'] = false;
@ -212,16 +184,6 @@ $config['imap_force_lsub'] = false;
// Enable this option to force listing of folders in all namespaces
$config['imap_force_ns'] = false;
// Some servers return hidden folders (name starting witha dot)
// from user home directory. IMAP RFC does not forbid that.
// Enable this option to hide them and disable possibility to create such.
$config['imap_skip_hidden_folders'] = false;
// Some servers do not support folders with both folders and messages inside
// If your server supports that use true, if it does not, use false.
// By default it will be determined automatically (once per user session).
$config['imap_dual_use_folders'] = null;
// List of disabled imap extensions.
// Use if your IMAP server has broken implementation of some feature
// and you can't remove it from CAPABILITY string on server-side.
@ -229,11 +191,11 @@ $config['imap_dual_use_folders'] = null;
// Note: Because the list is cached, re-login is required after change.
$config['imap_disabled_caps'] = array();
// Log IMAP session identifiers after each IMAP login.
// Log IMAP session identifers after each IMAP login.
// This is used to relate IMAP session with Roundcube user sessions
$config['imap_log_session'] = false;
// Type of IMAP indexes cache. Supported values: 'db', 'apc' and 'memcache' or 'memcached'.
// Type of IMAP indexes cache. Supported values: 'db', 'apc' and 'memcache'.
$config['imap_cache'] = null;
// Enables messages cache. Only 'db' cache is supported.
@ -258,8 +220,8 @@ $config['messages_cache_threshold'] = 50;
// ----------------------------------
// SMTP server host (for sending mails).
// Enter hostname with prefix ssl:// to use Implicit TLS, or use
// prefix tls:// to use STARTTLS.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// If left blank, the PHP mail() function is used
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
@ -267,24 +229,23 @@ $config['messages_cache_threshold'] = 50;
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
// To specify differnt SMTP servers for different IMAP hosts provide an array
// of IMAP host (no prefix or port) and SMTP server e.g. array('imap.example.com' => 'smtp.example.net')
$config['smtp_server'] = 'localhost';
$config['smtp_server'] = '';
// SMTP port. Use 25 for cleartext, 465 for Implicit TLS, or 587 for STARTTLS (default)
$config['smtp_port'] = 587;
// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
// deprecated SSL over SMTP (aka SMTPS))
$config['smtp_port'] = 25;
// SMTP username (if required) if you use %u as the username Roundcube
// will use the current username for login
$config['smtp_user'] = '%u';
$config['smtp_user'] = '';
// SMTP password (if required) if you use %p as the password Roundcube
// will use the current user's password for login
$config['smtp_pass'] = '%p';
$config['smtp_pass'] = '';
// SMTP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or empty to use
// best server supported one)
$config['smtp_auth_type'] = null;
$config['smtp_auth_type'] = '';
// Optional SMTP authentication identifier to be used as authorization proxy
$config['smtp_auth_cid'] = null;
@ -314,7 +275,6 @@ $config['smtp_timeout'] = 0;
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ),
// );
// Note: These can be also specified as an array of options indexed by hostname
$config['smtp_conn_options'] = null;
@ -322,55 +282,12 @@ $config['smtp_conn_options'] = null;
// LDAP
// ----------------------------------
// Type of LDAP cache. Supported values: 'db', 'apc' and 'memcache' or 'memcached'.
// Type of LDAP cache. Supported values: 'db', 'apc' and 'memcache'.
$config['ldap_cache'] = 'db';
// Lifetime of LDAP cache. Possible units: s, m, h, d, w
$config['ldap_cache_ttl'] = '10m';
// ----------------------------------
// CACHE(S)
// ----------------------------------
// Use these hosts for accessing memcached
// Define any number of hosts in the form of hostname:port or unix:///path/to/socket.file
// Example: array('localhost:11211', '192.168.1.12:11211', 'unix:///var/tmp/memcached.sock');
$config['memcache_hosts'] = null;
// Controls the use of a persistent connections to memcache servers
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_pconnect'] = true;
// Value in seconds which will be used for connecting to the daemon
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_timeout'] = 1;
// Controls how often a failed server will be retried (value in seconds).
// Setting this parameter to -1 disables automatic retry.
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_retry_interval'] = 15;
// Use these hosts for accessing Redis.
// Currently only one host is supported. Cluster support may come in a future release.
// You can pass 4 fields, host, port (optional), database (optional) and password (optional).
// Unset fields will be set to the default values host=127.0.0.1, port=6379.
// Examples:
// array('localhost:6379');
// array('192.168.1.1:6379:1:secret');
// array('unix:///var/run/redis/redis-server.sock:1:secret');
$config['redis_hosts'] = null;
// Maximum size of an object in memcache (in bytes). Default: 2MB
$config['memcache_max_allowed_packet'] = '2M';
// Maximum size of an object in APC cache (in bytes). Default: 2MB
$config['apc_max_allowed_packet'] = '2M';
// Maximum size of an object in Redis cache (in bytes). Default: 2MB
$config['redis_max_allowed_packet'] = '2M';
// ----------------------------------
// SYSTEM
// ----------------------------------
@ -379,7 +296,7 @@ $config['redis_max_allowed_packet'] = '2M';
// ONLY ENABLE IT IF YOU'RE REALLY SURE WHAT YOU'RE DOING!
$config['enable_installer'] = false;
// don't allow these settings to be overridden by the user
// don't allow these settings to be overriden by the user
$config['dont_override'] = array();
// List of disabled UI elements/actions
@ -393,37 +310,10 @@ $config['advanced_prefs'] = array();
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
$config['support_url'] = '';
// Logo image replacement. Specifies location of the image as:
// - URL relative to the document root of this Roundcube installation
// - full URL with http:// or https:// prefix
// - URL relative to the current skin folder (when starts with a '/')
//
// An array can be used to specify different logos for specific template files
// The array key specifies the place(s) the logo should be applied to and
// is made up of (up to) 3 parts:
// - skin name prefix (always with colon, can be replaced with *)
// - template name (or * for all templates)
// - logo type - it is used for logos used on multiple templates
// the available types include '[favicon]' for favicon, '[print]' for logo on all print
// templates (e.g. messageprint, contactprint) and '[small]' for small screen logo in supported skins
//
// Example config for skin_logo
/*
array(
// show the image /images/logo_login_small.png for the Login screen in the Elastic skin on small screens
"elastic:login[small]" => "/images/logo_login_small.png",
// show the image /images/logo_login.png for the Login screen in the Elastic skin
"elastic:login" => "/images/logo_login.png",
// show the image /images/logo_small.png in the Elastic skin
"elastic:*[small]" => "/images/logo_small.png",
// show the image /images/larry.png in the Larry skin
"larry:*" => "/images/larry.png",
// show the image /images/logo_login.png on the login template in all skins
"login" => "/images/logo_login.png",
// show the image /images/logo_print.png for all print type logos in all skins
"[print]" => "/images/logo_print.png",
);
*/
// replace Roundcube logo with this image
// specify an URL relative to the document root of this Roundcube installation
// an array can be used to specify different logos for specific template files, '*' for default logo
// for example array("*" => "/images/roundcube_logo.png", "messageprint" => "/images/roundcube_logo_print.png")
$config['skin_logo'] = null;
// automatically create a new Roundcube user when log-in the first time.
@ -447,10 +337,9 @@ $config['temp_dir'] = RCUBE_INSTALL_PATH . 'temp/';
// possible units: s, m, h, d, w
$config['temp_dir_ttl'] = '48h';
// Enforce connections over https
// With this option enabled, all non-secure connections will be redirected.
// It can be also a port number, hostname or hostname:port if they are
// different than default HTTP_HOST:443
// enforce connections over https
// with this option enabled, all non-secure connections will be redirected.
// set the port for the ssl connection as value of this option if it differs from the default 443
$config['force_https'] = false;
// tell PHP that it should work as under secure connection
@ -470,24 +359,11 @@ $config['login_autocomplete'] = 0;
// UPDATE users SET username = LOWER(username);
$config['login_lc'] = 2;
// Maximum length (in bytes) of logon username and password.
$config['login_username_maxlen'] = 1024;
$config['login_password_maxlen'] = 1024;
// Logon username filter. Regular expression for use with preg_match().
// Example: '/^[a-z0-9_@.-]+$/'
$config['login_username_filter'] = null;
// Brute-force attacks prevention.
// The value specifies maximum number of failed logon attempts per minute.
$config['login_rate_limit'] = 3;
// Includes should be interpreted as PHP files
$config['skin_include_php'] = false;
// display product name and software version on login screen
// 0 - hide product name and version number, 1 - show product name only, 2 - show product name and version number
$config['display_product_info'] = 1;
// display software version on login screen
$config['display_version'] = false;
// Session lifetime in minutes
$config['session_lifetime'] = 10;
@ -504,54 +380,48 @@ $config['session_auth_name'] = null;
// Session path. Defaults to PHP session.cookie_path setting.
$config['session_path'] = null;
// Session samesite. Defaults to PHP session.cookie_samesite setting.
// Requires PHP >= 7.3.0, see https://wiki.php.net/rfc/same-site-cookie for more info
// Possible values: null (default), 'Lax', or 'Strict'
$config['session_samesite'] = null;
// Backend to use for session storage. Can either be 'db' (default), 'redis', 'memcache', or 'php'
//
// If set to 'memcache' or 'memcached', a list of servers need to be specified in 'memcache_hosts'
// Make sure the Memcache extension (https://pecl.php.net/package/memcache) version >= 2.0.0
// or the Memcached extension (https://pecl.php.net/package/memcached) version >= 2.0.0 is installed.
//
// If set to 'redis', a server needs to be specified in 'redis_hosts'
// Make sure the Redis extension (https://pecl.php.net/package/redis) version >= 2.0.0 is installed.
//
// Backend to use for session storage. Can either be 'db' (default), 'memcache' or 'php'
// If set to 'memcache', a list of servers need to be specified in 'memcache_hosts'
// Make sure the Memcache extension (http://pecl.php.net/package/memcache) version >= 2.0.0 is installed
// Setting this value to 'php' will use the default session save handler configured in PHP
$config['session_storage'] = 'db';
// List of trusted proxies
// X_FORWARDED_* and X_REAL_IP headers are only accepted from these IPs
$config['proxy_whitelist'] = array();
// Use these hosts for accessing memcached
// Define any number of hosts in the form of hostname:port or unix:///path/to/socket.file
$config['memcache_hosts'] = null; // e.g. array( 'localhost:11211', '192.168.1.12:11211', 'unix:///var/tmp/memcached.sock' );
// Controls the use of a persistent connections to memcache servers
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_pconnect'] = true;
// List of trusted host names
// Attackers can modify Host header of the HTTP request causing $_SERVER['SERVER_NAME']
// or $_SERVER['HTTP_HOST'] variables pointing to a different host, that could be used
// to collect user names and passwords. Some server configurations prevent that, but not all.
// An empty list accepts any host name. The list can contain host names
// or PCRE patterns (without // delimiters, that will be added automatically).
$config['trusted_host_patterns'] = array();
// Value in seconds which will be used for connecting to the daemon
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_timeout'] = 1;
// Controls how often a failed server will be retried (value in seconds).
// Setting this parameter to -1 disables automatic retry.
// See http://php.net/manual/en/memcache.addserver.php
$config['memcache_retry_interval'] = 15;
// check client IP in session authorization
$config['ip_check'] = false;
// List of trusted proxies
// X_FORWARDED_* and X_REAL_IP headers are only accepted from these IPs
$config['proxy_whitelist'] = array();
// check referer of incoming requests
$config['referer_check'] = false;
// X-Frame-Options HTTP header value sent to prevent from Clickjacking.
// Possible values: sameorigin|deny|allow-from <uri>.
// Set to false in order to disable sending the header.
// Possible values: sameorigin|deny. Set to false in order to disable sending them
$config['x_frame_options'] = 'sameorigin';
// This key is used for encrypting purposes, like storing of imap password
// in the session. For historical reasons it's called DES_key, but it's used
// with any configured cipher_method (see below).
// For the default cipher_method a required key length is 24 characters.
// this key is used to encrypt the users imap password which is stored
// in the session record (and the client cookie if remember password is enabled).
// please provide a string of exactly 24 chars.
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
// Encryption algorithm. You can use any method supported by OpenSSL.
// Default is set for backward compatibility to DES-EDE3-CBC,
// but you can choose e.g. AES-256-CBC which we consider a better choice.
$config['cipher_method'] = 'DES-EDE3-CBC';
// Automatically add this domain to user names for login
// Only for IMAP servers that require full e-mail addresses for login
// Specify an array with 'host' => 'domain' values to support multiple hosts
@ -578,40 +448,29 @@ $config['username_domain_forced'] = false;
// For example %n = mail.domain.tld, %t = domain.tld
$config['mail_domain'] = '';
// Password character set, to change the password for user
// authentication or for password change operations
$config['password_charset'] = 'UTF-8';
// Password charset.
// Use it if your authentication backend doesn't support UTF-8.
// Defaults to ISO-8859-1 for backward compatibility
$config['password_charset'] = 'ISO-8859-1';
// How many seconds must pass between emails sent by a user
$config['sendmail_delay'] = 0;
// Message size limit. Note that SMTP server(s) may use a different value.
// This limit is verified when user attaches files to a composed message.
// Size in bytes (possible unit suffix: K, M, G)
$config['max_message_size'] = '100M';
// Maximum number of recipients per message. Default: 0 (no limit)
$config['max_recipients'] = 0;
// Maximum number of recipients per message (including To, Cc, Bcc).
// Default: 0 (no limit)
$config['max_recipients'] = 0;
// Maximum number of recipients per message exluding Bcc header.
// This is a soft limit, which means we only display a warning to the user.
// Default: 5
$config['max_disclosed_recipients'] = 5;
// Maximum allowed number of members of an address group. Default: 0 (no limit)
// Maximum allowednumber of members of an address group. Default: 0 (no limit)
// If 'max_recipients' is set this value should be less or equal
$config['max_group_members'] = 0;
$config['max_group_members'] = 0;
// Name your service. This is displayed on the login screen and in the window title
$config['product_name'] = 'Roundcube Webmail';
// Add this user-agent to message headers when sending
$config['useragent'] = 'Roundcube Webmail/'.RCUBE_VERSION;
$config['useragent'] = 'Roundcube Webmail/'.RCMAIL_VERSION;
// try to load host-specific configuration
// see https://github.com/roundcube/roundcubemail/wiki/Configuration:-Multi-Domain-Setup
// for more details
// see http://trac.roundcube.net/wiki/Howto_Config for more details
$config['include_host_config'] = false;
// path to a text file which will be added to each sent message
@ -631,6 +490,10 @@ $config['http_received_header'] = false;
// when tracking down issues.
$config['http_received_header_encrypt'] = false;
// This string is used as a delimiter for message headers when sending
// a message via mail() function. Leave empty for auto-detection
$config['mail_header_delimiter'] = NULL;
// number of chars allowed for line when wrapping text.
// text wrapping is done when composing/sending messages
$config['line_length'] = 72;
@ -655,12 +518,9 @@ $config['identities_level'] = 0;
$config['identity_image_size'] = 64;
// Mimetypes supported by the browser.
// Attachments of these types will open in a preview window.
// Either a comma-separated list or an array. Default list includes:
// text/plain,text/html,
// image/jpeg,image/gif,image/png,image/bmp,image/tiff,image/webp,
// application/x-javascript,application/pdf,application/x-shockwave-flash
$config['client_mimetypes'] = null;
// attachments of these types will open in a preview window
// either a comma-separated list or an array: 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/pdf'
$config['client_mimetypes'] = null; # null == default
// Path to a local mime magic database file for PHPs finfo extension.
// Set to null if the default path should be used.
@ -696,7 +556,7 @@ $config['no_save_sent_messages'] = false;
// Improve system security by using special URL with security token.
// This can be set to a number defining token length. Default: 16.
// Warning: This requires http server configuration. Sample:
// RewriteRule ^/roundcubemail/[a-zA-Z0-9]{16}/(.*) /roundcubemail/$1 [PT]
// RewriteRule ^/roundcubemail/[a-f0-9]{16}/(.*) /roundcubemail/$1 [PT]
// Alias /roundcubemail /var/www/roundcubemail/
// Note: Use assets_path to not prevent the browser from caching assets
$config['use_secure_urls'] = false;
@ -734,7 +594,7 @@ $config['message_sort_col'] = '';
$config['message_sort_order'] = 'DESC';
// These cols are shown in the message list. Available cols are:
// subject, from, to, fromto, cc, replyto, date, size, status, flag, attachment, priority
// subject, from, to, fromto, cc, replyto, date, size, status, flag, attachment, 'priority'
$config['list_cols'] = array('subject', 'status', 'fromto', 'date', 'size', 'flag', 'attachment');
// the default locale setting (leave empty for auto-detection)
@ -779,7 +639,7 @@ $config['sent_mbox'] = 'Sent';
// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
$config['trash_mbox'] = 'Trash';
// automatically create the above listed default folders on user login
// automatically create the above listed default folders on first login
$config['create_default_folders'] = false;
// protect the default folders from renames, deletes, and subscription changes
@ -792,6 +652,8 @@ $config['show_real_foldernames'] = false;
$config['quota_zero_as_unlimited'] = false;
// Make use of the built-in spell checker. It is based on GoogieSpell.
// Since Google only accepts connections over https your PHP installatation
// requires to be compiled with Open SSL support
$config['enable_spellcheck'] = true;
// Enables spellchecker exceptions dictionary.
@ -829,6 +691,9 @@ $config['spellcheck_ignore_nums'] = false;
// Makes that words with symbols will be ignored (e.g. g@@gle)
$config['spellcheck_ignore_syms'] = false;
// Use this char/string to separate recipients when composing a new message
$config['recipients_separator'] = ',';
// Number of lines at the end of a message considered to contain the signature.
// Increase this value if signatures are not properly detected and colored
$config['sig_max_lines'] = 15;
@ -839,6 +704,11 @@ $config['max_pagesize'] = 200;
// Minimal value of user's 'refresh_interval' setting (in seconds)
$config['min_refresh_interval'] = 60;
// Enables files upload indicator. Requires APC installed and enabled apc.rfc1867 option.
// By default refresh time is set to 1 second. You can set this value to true
// or any integer value indicating number of seconds.
$config['upload_progress'] = false;
// Specifies for how many seconds the Undo button will be available
// after object delete action. Currently used with supporting address book sources.
// Setting it to 0, disables the feature.
@ -850,19 +720,17 @@ $config['compose_responses_static'] = array(
// array('name' => 'Canned Response 2', 'text' => 'Static Response Two'),
);
// List of HKP key servers for PGP public key lookups in Enigma/Mailvelope
// Note: Lookup is client-side, so the server must support Cross-Origin Resource Sharing
$config['keyservers'] = array('keys.openpgp.org');
// ----------------------------------
// ADDRESSBOOK SETTINGS
// ----------------------------------
// This indicates which type of address book to use. Possible choises:
// 'sql' - built-in sql addressbook enabled (default),
// '' - built-in sql addressbook disabled.
// Still LDAP or plugin-added addressbooks will be available.
// BC Note: The value can actually be anything except 'sql', it does not matter.
// 'sql' (default), 'ldap' and ''.
// If set to 'ldap' then it will look at using the first writable LDAP
// address book as the primary address book and it will not display the
// SQL address book in the 'Address Book' view.
// If set to '' then no address book will be displayed or only the
// addressbook which is created by a plugin (like CardDAV).
$config['address_book_type'] = 'sql';
// In order to enable public ldap search, configure an array like the Verisign
@ -895,7 +763,6 @@ $config['ldap_public']['Verisign'] = array(
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
// Note: Host can also be a full URI e.g. ldaps://hostname.local:636 (for SSL)
'hosts' => array('directory.verisign.com'),
'port' => 389,
'use_tls' => false,
@ -919,10 +786,6 @@ $config['ldap_public']['Verisign'] = array(
// DN and password to bind as before searching for bind DN, if anonymous search is not allowed
'search_bind_dn' => '',
'search_bind_pw' => '',
// Base DN and filter used for resolving the user's domain root DN which feeds the %dc variables
// Leave empty to skip this lookup and derive the root DN from the username domain
'domain_base_dn' => '',
'domain_filter' => '',
// Optional map of replacement strings => attributes used when binding for an individual address book
'search_bind_attrib' => array(), // e.g. array('%udc' => 'ou')
// Default for %dn variable if search doesn't return DN value
@ -953,11 +816,8 @@ $config['ldap_public']['Verisign'] = array(
'required_fields' => array('cn', 'sn', 'mail'),
'search_fields' => array('mail', 'cn'), // fields to search in
// mapping of contact fields to directory attributes
// 1. for every attribute one can specify the number of values (limit) allowed.
// default is 1, a wildcard * means unlimited
// 2. another possible parameter is separator character for composite fields
// 3. it's possible to define field format for write operations, e.g. for date fields
// example: 'birthday:date[YmdHis\\Z]'
// for every attribute one can specify the number of values (limit) allowed.
// default is 1, a wildcard * means unlimited
'fieldmap' => array(
// Roundcube => LDAP:limit
'name' => 'cn',
@ -1007,9 +867,9 @@ $config['ldap_public']['Verisign'] = array(
// Used where addressbook contains aliases to objects elsewhere in the LDAP tree.
// definition for contact groups (uncomment if no groups are supported)
// for the groups base_dn, the user replacements %fu, %u, %d and %dc work as for base_dn (see above)
// for the groups base_dn, the user replacements %fu, %u, $d and %dc work as for base_dn (see above)
// if the groups base_dn is empty, the contact base_dn is used for the groups as well
// -> in this case, assure that groups and contacts are separated due to the concernig filters!
// -> in this case, assure that groups and contacts are separated due to the concernig filters!
'groups' => array(
'base_dn' => '',
'scope' => 'sub', // Search mode: sub|base|list
@ -1092,12 +952,8 @@ $config['contact_search_name'] = '{name} <{email}>';
// Use this charset as fallback for message decoding
$config['default_charset'] = 'ISO-8859-1';
// Skin name: folder from skins/
$config['skin'] = 'elastic';
// Limit skins available for the user.
// Note: When not empty, it should include the default skin set in 'skin' option.
$config['skins_allowed'] = array();
// skin name: folder from skins/
$config['skin'] = 'larry';
// Enables using standard browser windows (that can be handled as tabs)
// instead of popup windows
@ -1120,17 +976,17 @@ $config['addressbook_sort_col'] = 'surname';
$config['addressbook_name_listing'] = 0;
// use this timezone to display date/time
// valid timezone identifiers are listed here: php.net/manual/en/timezones.php
// valid timezone identifers are listed here: php.net/manual/en/timezones.php
// 'auto' will use the browser's timezone settings
$config['timezone'] = 'auto';
// prefer displaying HTML messages
$config['prefer_html'] = true;
// display remote resources (inline images, styles)
// display remote inline images
// 0 - Never, always ask
// 1 - Ask if sender is not in address book
// 2 - Always allow
// 2 - Always show inline images
$config['show_images'] = 0;
// open messages in new window
@ -1140,11 +996,7 @@ $config['message_extwin'] = false;
$config['compose_extwin'] = false;
// compose html formatted messages by default
// 0 - never,
// 1 - always,
// 2 - on reply to HTML message,
// 3 - on forward or reply to HTML message
// 4 - always, except when replying to plain text message
// 0 - never, 1 - always, 2 - on reply to HTML message, 3 - on forward or reply to HTML message
$config['htmleditor'] = 0;
// save copies of compose messages in the browser's local storage
@ -1157,15 +1009,12 @@ $config['prettydate'] = true;
// save compose message every 300 seconds (5min)
$config['draft_autosave'] = 300;
// Interface layout. Default: 'widescreen'.
// 'widescreen' - three columns
// 'desktop' - two columns, preview on bottom
// 'list' - two columns, no preview
$config['layout'] = 'widescreen';
// default setting if preview pane is enabled
$config['preview_pane'] = false;
// Mark as read when viewing a message (delay in seconds)
// Set to -1 if messages should not be marked as read
$config['mail_read_time'] = 0;
// Mark as read when viewed in preview pane (delay in seconds)
// Set to -1 if messages in preview pane should not be marked as read
$config['preview_pane_mark_read'] = 0;
// Clear Trash on logout
$config['logout_purge'] = false;
@ -1202,7 +1051,7 @@ $config['refresh_interval'] = 60;
// If true all folders will be checked for recent messages
$config['check_all_folders'] = false;
// If true, after message/contact delete/move, the next message/contact will be displayed
// If true, after message delete/move, the next message will be displayed
$config['display_next'] = true;
// Default messages listing mode. One of 'threads' or 'list'.
@ -1217,7 +1066,6 @@ $config['autoexpand_threads'] = 0;
// -1 - don't cite the original message
// 0 - place cursor below the original message
// 1 - place cursor above original message (top posting)
// 2 - place cursor above original message (top posting), but do not indent the quote
$config['reply_mode'] = 0;
// When replying strip original signature from message
@ -1235,9 +1083,6 @@ $config['show_sig'] = 1;
// the signature below the quoted text (sig_below = true).
$config['sig_below'] = false;
// Enables adding of standard separator to the signature
$config['sig_separator'] = true;
// Use MIME encoding (quoted-printable) for 8bit characters in message body
$config['force_7bit'] = false;
@ -1250,6 +1095,12 @@ $config['search_mods'] = null; // Example: array('*' => array('subject'=>1, 'fr
// Defaults of the addressbook search field configuration.
$config['addressbook_search_mods'] = null; // Example: array('name'=>1, 'firstname'=>1, 'surname'=>1, 'email'=>1, '*'=>1);
// 'Delete always'
// This setting reflects if mail should be always deleted
// when moving to Trash fails. This is necessary in some setups
// when user is over quota and Trash is included in the quota.
$config['delete_always'] = false;
// Directly delete messages in Junk instead of moving to Trash
$config['delete_junk'] = false;

@ -0,0 +1,27 @@
<?php
/*
+-----------------------------------------------------------------------+
| Roundcube Webmail Selenium Tests Entry Point |
| |
| Copyright (C) 2005-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: |
| This is the public entry point for all HTTP requests to the |
| Roundcube webmail application loading the 'tests' environment. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <thomas@roundcube.net> |
+-----------------------------------------------------------------------+
*/
define('INSTALL_PATH', realpath(__DIR__) . '/');
$GLOBALS['env'] = 'test';
// include index.php from application root directory
include INSTALL_PATH . 'index.php';

@ -1,10 +1,10 @@
<?php
/**
/*
+-------------------------------------------------------------------------+
| Roundcube Webmail IMAP Client |
| Version 1.5-git |
| Version 1.1.12 |
| |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) 2005-2016, 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 (with exceptions |
@ -40,11 +40,11 @@
require_once 'program/include/iniset.php';
// init application, start session, init output class, etc.
$RCMAIL = rcmail::get_instance(0, $GLOBALS['env']);
$RCMAIL = rcmail::get_instance($GLOBALS['env']);
// Make the whole PHP output non-cacheable (#1487797)
$RCMAIL->output->nocacheing_headers();
$RCMAIL->output->common_headers(!empty($_SESSION['user_id']));
$RCMAIL->output->common_headers();
// turn on output buffering
ob_start();
@ -62,33 +62,21 @@ if ($err_str = $RCMAIL->db->is_error()) {
rcmail::raise_error(array(
'code' => 603,
'type' => 'db',
'message' => $err_str), false, true);
'message' => $err_str), FALSE, TRUE);
}
// error steps
if ($RCMAIL->action == 'error' && !empty($_GET['_code'])) {
rcmail::raise_error(array('code' => hexdec($_GET['_code'])), false, true);
rcmail::raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE);
}
// check if https is required (for login) and redirect if necessary
if (empty($_SESSION['user_id']) && ($force_https = $RCMAIL->config->get('force_https', false))) {
// force_https can be true, <hostname>, <hostname>:<port>, <port>
if (!is_bool($force_https)) {
list($host, $port) = explode(':', $force_https);
$https_port = is_bool($force_https) ? 443 : $force_https;
if (is_numeric($host) && empty($port)) {
$port = $host;
$host = '';
}
}
if (!rcube_utils::https_check($port ?: 443)) {
if (empty($host)) {
$host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']);
}
if ($port && $port != 443) {
$host .= ':' . $port;
}
if (!rcube_utils::https_check($https_port)) {
$host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']);
$host .= ($https_port != 443 ? ':' . $https_port : '');
header('Location: https://' . $host . $_SERVER['REQUEST_URI']);
exit;
@ -103,19 +91,17 @@ $RCMAIL->action = $startup['action'];
// try to log in
if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
$request_valid = $_SESSION['temp'] && $RCMAIL->check_request();
$pass_charset = $RCMAIL->config->get('password_charset', 'UTF-8');
// purge the session in case of new login when a session already exists
if ($request_valid) {
$RCMAIL->kill_session();
}
$RCMAIL->kill_session();
$auth = $RCMAIL->plugins->exec_hook('authenticate', array(
'host' => $RCMAIL->autoselect_host(),
'user' => trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)),
'pass' => rcube_utils::get_input_value('_pass', rcube_utils::INPUT_POST, true, $pass_charset),
'valid' => $request_valid,
'cookiecheck' => true,
'host' => $RCMAIL->autoselect_host(),
'user' => trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)),
'pass' => rcube_utils::get_input_value('_pass', rcube_utils::INPUT_POST, true,
$RCMAIL->config->get('password_charset', 'ISO-8859-1')),
'cookiecheck' => true,
'valid' => $request_valid,
));
// Login
@ -158,18 +144,17 @@ if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
}
else {
if (!$auth['valid']) {
$error_code = rcmail::ERROR_INVALID_REQUEST;
$error_code = RCMAIL::ERROR_INVALID_REQUEST;
}
else {
$error_code = is_numeric($auth['error']) ? $auth['error'] : $RCMAIL->login_error();
}
$error_labels = array(
rcmail::ERROR_STORAGE => 'storageerror',
rcmail::ERROR_COOKIES_DISABLED => 'cookiesdisabled',
rcmail::ERROR_INVALID_REQUEST => 'invalidrequest',
rcmail::ERROR_INVALID_HOST => 'invalidhost',
rcmail::ERROR_RATE_LIMIT => 'accountlocked',
RCMAIL::ERROR_STORAGE => 'storageerror',
RCMAIL::ERROR_COOKIES_DISABLED => 'cookiesdisabled',
RCMAIL::ERROR_INVALID_REQUEST => 'invalidrequest',
RCMAIL::ERROR_INVALID_HOST => 'invalidhost',
);
$error_message = !empty($auth['error']) && !is_numeric($auth['error']) ? $auth['error'] : ($error_labels[$error_code] ?: 'loginfailed');
@ -182,15 +167,13 @@ if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
$RCMAIL->plugins->exec_hook('login_failed', array(
'code' => $error_code, 'host' => $auth['host'], 'user' => $auth['user']));
if (!isset($_SESSION['user_id'])) {
$RCMAIL->kill_session();
}
$RCMAIL->kill_session();
}
}
// end session
else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id'])) {
$RCMAIL->request_security_check(rcube_utils::INPUT_GET | rcube_utils::INPUT_POST);
$RCMAIL->request_security_check($mode = rcube_utils::INPUT_GET);
$userdata = array(
'user' => $_SESSION['username'],
@ -209,14 +192,24 @@ else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id'])) {
else if ($RCMAIL->task != 'login' && $_SESSION['user_id']) {
if (!$RCMAIL->session->check_auth()) {
$RCMAIL->kill_session();
$session_error = 'sessionerror';
$session_error = true;
}
}
// not logged in -> show login page
if (empty($RCMAIL->user->ID)) {
if ($session_error || $_REQUEST['_err'] === 'session' || ($session_error = $RCMAIL->session_error())) {
$OUTPUT->show_message($session_error ?: 'sessionerror', 'error', null, true, -1);
// log session failures
$task = rcube_utils::get_input_value('_task', rcube_utils::INPUT_GPC);
if ($task && !in_array($task, array('login','logout'))
&& !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])
) {
$RCMAIL->session->log("Aborted session $sess_id; no valid session data found");
$session_error = true;
}
if ($session_error || $_REQUEST['_err'] == 'session') {
$OUTPUT->show_message('sessionerror', 'error', null, true, -1);
}
if ($OUTPUT->ajax_call || $OUTPUT->get_env('framed')) {
@ -226,28 +219,19 @@ if (empty($RCMAIL->user->ID)) {
// check if installer is still active
if ($RCMAIL->config->get('enable_installer') && is_readable('./installer/index.php')) {
$OUTPUT->add_footer(html::div(array('id' => 'login-addon', 'style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"),
$OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"),
html::tag('h2', array('style' => "margin-top:0.2em"), "Installer script is still accessible") .
html::p(null, "The install script of your Roundcube installation is still stored in its default location!") .
html::p(null, "Please <b>remove</b> the whole <tt>installer</tt> folder from the Roundcube directory because
html::p(null, "Please <b>remove</b> the whole <tt>installer</tt> folder from the Roundcube directory because .
these files may expose sensitive configuration data like server passwords and encryption keys
to the public. Make sure you cannot access the <a href=\"./installer/\">installer script</a> from your browser.")
));
}
$plugin = $RCMAIL->plugins->exec_hook('unauthenticated', array(
'task' => 'login',
'error' => $session_error,
// Return 401 only on failed logins (#7010)
'http_code' => empty($session_error) && !empty($error_message) ? 401 : 200
));
$plugin = $RCMAIL->plugins->exec_hook('unauthenticated', array('task' => 'login', 'error' => $session_error));
$RCMAIL->set_task($plugin['task']);
if ($plugin['http_code'] == 401) {
header('HTTP/1.0 401 Unauthorized');
}
$OUTPUT->send($plugin['task']);
}
else {
@ -258,7 +242,7 @@ else {
$disabled_actions = (array) $RCMAIL->config->get('disabled_actions');
if (in_array($RCMAIL->task . '.' . ($RCMAIL->action ?: 'index'), $disabled_actions)) {
rcube::raise_error(array(
'code' => 404, 'type' => 'php',
'code' => 403, 'type' => 'php',
'message' => "Action disabled"), true, true);
}
}
@ -285,7 +269,7 @@ if (is_file($incfile = INSTALL_PATH . 'program/steps/'.$RCMAIL->task.'/func.inc'
}
// allow 5 "redirects" to another action
$redirects = 0;
$redirects = 0; $incstep = null;
while ($redirects < 5) {
// execute a plugin action
if (preg_match('/^plugin\./', $RCMAIL->action)) {

@ -1,19 +1,5 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
if (!class_exists('rcmail_install', false) || !is_object($RCI)) {
die("Not allowed! Please open installer/index.php instead.");
}
@ -29,20 +15,17 @@ $required_php_exts = array(
'XML' => 'xml',
'JSON' => 'json',
'PDO' => 'PDO',
'Multibyte' => 'mbstring',
'OpenSSL' => 'openssl',
'Filter' => 'filter',
'Ctype' => 'ctype',
);
$optional_php_exts = array(
'FileInfo' => 'fileinfo',
'Libiconv' => 'iconv',
'Multibyte' => 'mbstring',
'OpenSSL' => 'openssl',
'Mcrypt' => 'mcrypt',
'Intl' => 'intl',
'Exif' => 'exif',
'LDAP' => 'ldap',
'GD' => 'gd',
'Imagick' => 'imagick',
'Zip' => 'zip',
);
$required_libs = array(
@ -62,12 +45,15 @@ $ini_checks = array(
'session.auto_start' => 0,
'mbstring.func_overload' => 0,
'suhosin.session.encrypt' => 0,
'magic_quotes_runtime' => 0,
'magic_quotes_sybase' => 0,
);
$optional_checks = array(
// required for utils/modcss.inc, should we require this?
'allow_url_fopen' => 1,
'date.timezone' => '-VALID-',
'register_globals' => 0, // #1489157
);
$source_urls = array(
@ -75,7 +61,9 @@ $source_urls = array(
'Session' => 'http://www.php.net/manual/en/book.session.php',
'PCRE' => 'http://www.php.net/manual/en/book.pcre.php',
'FileInfo' => 'http://www.php.net/manual/en/book.fileinfo.php',
'Libiconv' => 'http://www.php.net/manual/en/book.iconv.php',
'Multibyte' => 'http://www.php.net/manual/en/book.mbstring.php',
'Mcrypt' => 'http://www.php.net/manual/en/book.mcrypt.php',
'OpenSSL' => 'http://www.php.net/manual/en/book.openssl.php',
'JSON' => 'http://www.php.net/manual/en/book.json.php',
'DOM' => 'http://www.php.net/manual/en/book.dom.php',
@ -84,11 +72,6 @@ $source_urls = array(
'oci8' => 'http://www.php.net/manual/en/book.oci8.php',
'PDO' => 'http://www.php.net/manual/en/book.pdo.php',
'LDAP' => 'http://www.php.net/manual/en/book.ldap.php',
'GD' => 'http://www.php.net/manual/en/book.image.php',
'Imagick' => 'http://www.php.net/manual/en/book.imagick.php',
'Zip' => 'http://www.php.net/manual/en/book.zip.php',
'Filter' => 'http://www.php.net/manual/en/book.filter.php',
'Ctype' => 'http://www.php.net/manual/en/book.ctype.php',
'pdo_mysql' => 'http://www.php.net/manual/en/ref.pdo-mysql.php',
'pdo_pgsql' => 'http://www.php.net/manual/en/ref.pdo-pgsql.php',
'pdo_sqlite' => 'http://www.php.net/manual/en/ref.pdo-sqlite.php',
@ -108,10 +91,16 @@ echo '<input type="hidden" name="_step" value="' . ($RCI->configured ? 3 : 2) .
<h3>Checking PHP version</h3>
<?php
define('MIN_PHP_VERSION', '5.4.0');
define('MIN_PHP_VERSION', '5.3.7');
if (version_compare(PHP_VERSION, MIN_PHP_VERSION, '>=')) {
$RCI->pass('Version', 'PHP ' . PHP_VERSION . ' detected');
} else {
if (PHP_MAJOR_VERSION != 5) {
$RCI->fail('Version', 'PHP5 is required, ' . PHP_VERSION . ' detected');
}
else {
$RCI->pass('Version', 'PHP ' . PHP_VERSION . ' detected');
}
}
else {
$RCI->fail('Version', 'PHP Version ' . MIN_PHP_VERSION . ' or greater is required ' . PHP_VERSION . ' detected');
}
?>

@ -1,13 +1,14 @@
/*
+-----------------------------------------------------------------------+
| Roundcube installer client function |
| Roundcube installer cleint function |
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) The Roundcube Dev Team |
| This file is part of the Roundcube web development suite |
| Copyright (C) 2009-2012, 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. |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
@ -16,7 +17,7 @@
function toggleblock(id, link)
{
var block = document.getElementById(id);
return false;
}
@ -27,14 +28,14 @@ function addhostfield()
var row = document.createElement('div');
var input = document.createElement('input');
var link = document.createElement('a');
input.name = '_default_host[]';
input.size = '30';
link.href = '#';
link.onclick = function() { removehostfield(this.parentNode); return false };
link.className = 'removelink';
link.innerHTML = 'remove';
row.appendChild(input);
row.appendChild(link);
container.appendChild(row);

@ -1,23 +1,14 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
if (!class_exists('rcmail_install', false) || !is_object($RCI)) {
die("Not allowed! Please open installer/index.php instead.");
}
?>
<form action="index.php" method="post">
<input type="hidden" name="_step" value="2" />
<?php
// register these boolean fields
$RCI->bool_config_props = array(
'ip_check' => 1,
@ -25,6 +16,8 @@ $RCI->bool_config_props = array(
'auto_create_user' => 1,
'smtp_log' => 1,
'prefer_html' => 1,
'preview_pane' => 1,
'debug_level' => 1,
);
// allow the current user to get to the next step
@ -43,20 +36,10 @@ if (!empty($_POST['submit'])) {
echo '</p>';
}
else {
if (($dir = sys_get_temp_dir()) && @is_writable($dir)) {
echo '<iframe name="getconfig" style="display:none"></iframe>';
echo '<form id="getconfig_form" action="index.php" method="get" target="getconfig" style="display:none">';
echo '<input name="_getconfig" value="2" /></form>';
$button_txt = html::quote('Save in ' . $dir);
$save_button = '&nbsp;<input type="button" onclick="document.getElementById(\'getconfig_form\').submit()" value="' . $button_txt . '" />';
}
echo '<p class="notice">Copy or download the following configuration and save it';
echo ' as <tt><b>config.inc.php</b></tt> within the <tt>'.RCUBE_CONFIG_DIR.'</tt> directory of your Roundcube installation.<br/>';
echo ' Make sure that there are no characters outside the <tt>&lt;?php ?&gt;</tt> brackets when saving the file.';
echo '&nbsp;<input type="button" onclick="location.href=\'index.php?_getconfig=1\'" value="Download" />';
echo $save_button;
if ($RCI->legacy_config) {
echo '<br/><br/>Afterwards, please <b>remove</b> the old configuration files <tt>main.inc.php</tt> and <tt>db.inc.php</tt> from the config directory.';
@ -69,7 +52,7 @@ if (!empty($_POST['submit'])) {
}
echo '<p class="hint">Of course there are more options to configure.
Have a look at the defaults.inc.php file or visit <a href="https://github.com/roundcube/roundcubemail/wiki/Configuration" target="_blank">Howto_Config</a> to find out.</p>';
Have a look at the defaults.inc.php file or visit <a href="http://trac.roundcube.net/wiki/Howto_Config" target="_blank">Howto_Config</a> to find out.</p>';
echo '<p><input type="button" onclick="location.href=\'./index.php?_step=3\'" value="CONTINUE" /></p>';
@ -78,9 +61,6 @@ if (!empty($_POST['submit'])) {
}
?>
<form action="index.php" method="post">
<input type="hidden" name="_step" value="2" />
<fieldset>
<legend>General configuration</legend>
<dl class="configblock">
@ -104,7 +84,7 @@ $input_support = new html_inputfield(array('name' => '_support_url', 'size' => 5
echo $input_support->show($RCI->getprop('support_url'));
?>
<div>Provide a URL where a user can get support for this Roundcube installation.<br/>PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!</div>
<div>Provide an URL where a user can get support for this Roundcube installation.<br/>PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!</div>
<p class="hint">Enter an absolute URL (including http://) to a support page/form or a mailto: link.</p>
</dd>
@ -140,7 +120,8 @@ echo $input_deskey->show($RCI->getprop('des_key'));
?>
<div>This key is used to encrypt the users imap password before storing in the session record</div>
<p class="hint">It's a random generated string to ensure that every installation has its own key.</p>
<p class="hint">It's a random generated string to ensure that every installation has its own key.
If you enter it manually please provide a string of exactly 24 chars.</p>
</dd>
<dt class="propname">ip_check</dt>
@ -209,16 +190,31 @@ echo $input_ilevel->show($RCI->getprop('identities_level'), 0);
<legend>Logging & Debugging</legend>
<dl class="loggingblock">
<dt class="propname">debug_level</dt>
<dd>
<?php
$value = $RCI->getprop('debug_level');
$check_debug = new html_checkbox(array('name' => '_debug_level[]'));
echo $check_debug->show(($value & 1) ? 1 : 0 , array('value' => 1, 'id' => 'cfgdebug1'));
echo '<label for="cfgdebug1">Log errors</label><br />';
echo $check_debug->show(($value & 4) ? 4 : 0, array('value' => 4, 'id' => 'cfgdebug4'));
echo '<label for="cfgdebug4">Print errors (to the browser)</label><br />';
?>
</dd>
<dt class="propname">log_driver</dt>
<dd>
<?php
$select_log_driver = new html_select(array('name' => '_log_driver', 'id' => "cfglogdriver"));
$select_log_driver->add(array('file', 'syslog', 'stdout'), array('file', 'syslog', 'stdout'));
$select_log_driver->add(array('file', 'syslog'), array('file', 'syslog'));
echo $select_log_driver->show($RCI->getprop('log_driver', 'file'));
?>
<div>How to do logging? 'file' - write to files in the log directory, 'syslog' - use the syslog facility, 'stdout' writes to the process' STDOUT file descriptor.</div>
<div>How to do logging? 'file' - write to files in the log directory, 'syslog' - use the syslog facility.</div>
</dd>
<dt class="propname">log_dir</dt>
@ -289,7 +285,7 @@ foreach ($RCI->supported_dbs as $database => $ext) {
$input_dbhost = new html_inputfield(array('name' => '_dbhost', 'size' => 20, 'id' => "cfgdbhost"));
$input_dbname = new html_inputfield(array('name' => '_dbname', 'size' => 20, 'id' => "cfgdbname"));
$input_dbuser = new html_inputfield(array('name' => '_dbuser', 'size' => 20, 'id' => "cfgdbuser"));
$input_dbpass = new html_inputfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass"));
$input_dbpass = new html_passwordfield(array('name' => '_dbpass', 'size' => 20, 'id' => "cfgdbpass"));
$dsnw = rcube_db::parse_dsn($RCI->getprop('db_dsnw'));
@ -458,12 +454,12 @@ echo $text_junkmbox->show($RCI->getprop('junk_mbox'));
<?php
$text_smtphost = new html_inputfield(array('name' => '_smtp_server', 'size' => 30, 'id' => "cfgsmtphost"));
echo $text_smtphost->show($RCI->getprop('smtp_server', 'localhost'));
echo $text_smtphost->show($RCI->getprop('smtp_server'));
?>
<div>Use this host for sending mails</div>
<p class="hint">To use SSL connection, set ssl://smtp.host.com.</p>
<p class="hint">To use SSL connection, set ssl://smtp.host.com. If left blank, the PHP mail() function is used</p>
</dd>
<dt class="propname">smtp_port</dt>
@ -474,7 +470,7 @@ $text_smtpport = new html_inputfield(array('name' => '_smtp_port', 'size' => 6,
echo $text_smtpport->show($RCI->getprop('smtp_port'));
?>
<div>SMTP port (default is 587)</div>
<div>SMTP port (default is 25; 465 for SSL; 587 for submission)</div>
</dd>
<dt class="propname">smtp_user/smtp_pass</dt>
@ -482,7 +478,7 @@ echo $text_smtpport->show($RCI->getprop('smtp_port'));
<?php
$text_smtpuser = new html_inputfield(array('name' => '_smtp_user', 'size' => 20, 'id' => "cfgsmtpuser"));
$text_smtppass = new html_inputfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass"));
$text_smtppass = new html_passwordfield(array('name' => '_smtp_pass', 'size' => 20, 'id' => "cfgsmtppass"));
echo $text_smtpuser->show($RCI->getprop('smtp_user'));
echo $text_smtppass->show($RCI->getprop('smtp_pass'));
@ -595,6 +591,17 @@ echo $check_htmlview->show(intval($RCI->getprop('prefer_html')));
<label for="cfghtmlview">Prefer displaying HTML messages</label><br />
</dd>
<dt class="propname">preview_pane <span class="userconf">*</span></dt>
<dd>
<?php
$check_prevpane = new html_checkbox(array('name' => '_preview_pane', 'id' => "cfgprevpane", 'value' => 1));
echo $check_prevpane->show(intval($RCI->getprop('preview_pane')));
?>
<label for="cfgprevpane">If preview pane is enabled</label><br />
</dd>
<dt class="propname">htmleditor <span class="userconf">*</span></dt>
<dd>
<label for="cfghtmlcompose">Compose HTML formatted messages</label>
@ -671,7 +678,8 @@ echo $select_param_folding->show(strval($RCI->getprop('mime_param_folding')));
<?php
$plugins = $RCI->list_plugins();
foreach ($plugins as $p) {
foreach($plugins as $p)
{
$p_check = new html_checkbox(array('name' => '_plugins_'.$p['name'], 'id' => 'cfgplugin_'.$p['name'], 'value' => $p['name']));
echo '<dt class="propname"><label>';
echo $p_check->show($p['enabled'] ? $p['name'] : 0);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

@ -1,11 +1,11 @@
<?php
/**
/*
+-------------------------------------------------------------------------+
| Roundcube Webmail setup tool |
| Version 1.5-git |
| Version 1.1.12 |
| |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) 2009-2016, 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 (with exceptions |
@ -36,11 +36,27 @@
+-------------------------------------------------------------------------+
*/
ini_set('error_reporting', E_ALL &~ (E_NOTICE | E_STRICT));
ini_set('display_errors', 1);
define('INSTALL_PATH', realpath(__DIR__ . '/../').'/');
define('RCUBE_INSTALL_PATH', INSTALL_PATH);
define('RCUBE_CONFIG_DIR', INSTALL_PATH . 'config/');
require INSTALL_PATH . 'program/include/iniset.php';
$include_path = INSTALL_PATH . 'program/lib' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'program/include' . PATH_SEPARATOR;
$include_path .= ini_get('include_path');
set_include_path($include_path);
// include composer autoloader (if available)
if (@file_exists(INSTALL_PATH . 'vendor/autoload.php')) {
require INSTALL_PATH . 'vendor/autoload.php';
}
require_once 'Roundcube/bootstrap.php';
// deprecated aliases (to be removed)
require_once 'bc.php';
if (function_exists('session_start'))
session_start();
@ -50,13 +66,7 @@ $RCI->load_config();
if (isset($_GET['_getconfig'])) {
$filename = 'config.inc.php';
if (!empty($_SESSION['config']) && $_GET['_getconfig'] == 2) {
$path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $filename;
@unlink($path);
file_put_contents($path, $_SESSION['config']);
exit;
}
else if (!empty($_SESSION['config'])) {
if (!empty($_SESSION['config'])) {
header('Content-type: text/plain');
header('Content-Disposition: attachment; filename="'.$filename.'"');
echo $_SESSION['config'];
@ -106,7 +116,7 @@ if ($RCI->configured && empty($_REQUEST['_step'])) {
</div>
<div id="topnav">
<a href="https://github.com/roundcube/roundcubemail/wiki/Installation">How-to Wiki</a>
<a href="http://trac.roundcube.net/wiki/Howto_Install">How-to Wiki</a>
</div>
<div id="content">
@ -148,7 +158,7 @@ if ($RCI->configured && empty($_REQUEST['_step'])) {
foreach (array('Check environment', 'Create config', 'Test config') as $i => $item) {
$j = $i + 1;
$link = ($RCI->step >= $j || $RCI->configured) ? '<a href="./index.php?_step='.$j.'">' . rcube::Q($item) . '</a>' : rcube::Q($item);
$link = ($RCI->step >= $j || $RCI->configured) ? '<a href="./index.php?_step='.$j.'">' . Q($item) . '</a>' : Q($item);
printf('<li class="step%d%s">%s</li>', $j+1, $RCI->step > $j ? ' passed' : ($RCI->step == $j ? ' current' : ''), $link);
}
?>

@ -141,11 +141,6 @@ th {
text-align: left;
}
td > label {
min-width: 6em;
display: inline-block;
}
ul li {
margin: 0.3em 0 0.4em -1em;
}

@ -1,17 +1,4 @@
<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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. |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
if (!class_exists('rcmail_install', false) || !is_object($RCI)) {
die("Not allowed! Please open installer/index.php instead.");
@ -139,7 +126,7 @@ if ($RCI->configured) {
else {
$RCI->fail('DSN (write)', $db_error_msg);
echo '<p class="hint">Make sure that the configured database exists and that the user has write privileges<br />';
echo 'DSN: ' . rcube::Q($RCI->config['db_dsnw']) . '</p>';
echo 'DSN: ' . $RCI->config['db_dsnw'] . '</p>';
}
}
else {
@ -152,15 +139,15 @@ else {
// initialize db with schema found in /SQL/*
if ($db_working && $_POST['initdb']) {
if (!$RCI->init_db($DB)) {
if (!($success = $RCI->init_db($DB))) {
$db_working = false;
echo '<p class="warning">Please try to inizialize the database manually as described in the INSTALL guide.
Make sure that the configured database extists and that the user as write privileges</p>';
Make sure that the configured database extists and that the user as write privileges</p>';
}
}
else if ($db_working && $_POST['updatedb']) {
if (!$RCI->update_db($_POST['version'])) {
if (!($success = $RCI->update_db($_POST['version']))) {
echo '<p class="warning">Database schema update failed.</p>';
}
}
@ -178,7 +165,7 @@ if ($db_working) {
echo '<ul style="margin:0"><li>' . join("</li>\n<li>", $err) . "</li></ul>";
$select = $RCI->versions_select(array('name' => 'version'));
$select->add('0.9 or newer', '');
echo '<p class="suggestion">You should run the update queries to get the schema fixed.<br/><br/>Version to update from: ' . $select->show('') . '&nbsp;<input type="submit" name="updatedb" value="Update" /></p>';
echo '<p class="suggestion">You should run the update queries to get the schema fixed.<br/><br/>Version to update from: ' . $select->show() . '&nbsp;<input type="submit" name="updatedb" value="Update" /></p>';
$db_working = false;
}
else {
@ -189,15 +176,10 @@ if ($db_working) {
// more database tests
if ($db_working) {
// Using transactions to workaround SQLite bug (#7064)
if ($DB->db_provider == 'sqlite') {
$DB->startTransaction();
}
// write test
$insert_id = md5(uniqid());
$db_write = $DB->query("INSERT INTO " . $DB->quote_identifier($RCI->config['db_prefix'] . 'session')
. " (`sess_id`, `changed`, `ip`, `vars`) VALUES (?, ".$DB->now().", '127.0.0.1', 'foo')", $insert_id);
. " (`sess_id`, `created`, `ip`, `vars`) VALUES (?, ".$DB->now().", '127.0.0.1', 'foo')", $insert_id);
if ($db_write) {
$RCI->pass('DB Write');
@ -209,11 +191,6 @@ if ($db_working) {
}
echo '<br />';
// Transaction end
if ($DB->db_provider == 'sqlite') {
$DB->rollbackTransaction();
}
// check timezone settings
$tz_db = 'SELECT ' . $DB->unixtimestamp($DB->now()) . ' AS tz_db';
$tz_db = $DB->query($tz_db);
@ -263,74 +240,48 @@ else {
echo "<br/>";
}
$smtp_hosts = $RCI->get_hostlist('smtp_server');
if (!empty($smtp_hosts)) {
$smtp_host_field = new html_select(array('name' => '_smtp_host', 'id' => 'smtp_server'));
$smtp_host_field->add($smtp_hosts);
}
else {
$smtp_host_field = new html_inputfield(array('name' => '_smtp_host', 'id' => 'smtp_server'));
}
?>
<h3>Test SMTP config</h3>
<p>
Server: <?php echo rcube_parse_host($RCI->getprop('smtp_server', 'PHP mail()')); ?><br />
Port: <?php echo $RCI->getprop('smtp_port'); ?><br />
$user = $RCI->getprop('smtp_user', '(none)');
$pass = $RCI->getprop('smtp_pass', '(none)');
<?php
if ($user == '%u') {
$user_field = new html_inputfield(array('name' => '_smtp_user', 'id' => 'smtp_user'));
if ($RCI->getprop('smtp_server')) {
$user = $RCI->getprop('smtp_user', '(none)');
$pass = $RCI->getprop('smtp_pass', '(none)');
if ($user == '%u') {
$user_field = new html_inputfield(array('name' => '_smtp_user'));
$user = $user_field->show($_POST['_smtp_user']);
}
else {
$user = html::quote($user);
}
if ($pass == '%p') {
$pass_field = new html_passwordfield(array('name' => '_smtp_pass', 'id' => 'smtp_pass'));
}
if ($pass == '%p') {
$pass_field = new html_passwordfield(array('name' => '_smtp_pass'));
$pass = $pass_field->show();
}
else {
$pass = html::quote($pass);
}
echo "User: $user<br />";
echo "Password: $pass<br />";
}
?>
<h3>Test SMTP config</h3>
$from_field = new html_inputfield(array('name' => '_from', 'id' => 'sendmailfrom'));
$to_field = new html_inputfield(array('name' => '_to', 'id' => 'sendmailto'));
<p>
<table>
<tbody>
<tr>
<td><label for="smtp_server">Server</label></td>
<td><?php echo $smtp_host_field->show($_POST['_smtp_host']); ?></td>
</tr>
<tr>
<td><label for="smtp_port">Port</label></td>
<td><?php echo rcube::Q($RCI->getprop('smtp_port')); ?></td>
</tr>
<tr>
<td><label for="smtp_user">Username</label></td>
<td><?php echo $user; ?></td>
</tr>
<tr>
<td><label for="smtp_pass">Password</label></td>
<td><?php echo $pass; ?></td>
</tr>
</tbody>
</table>
?>
</p>
<?php
$from_field = new html_inputfield(array('name' => '_from', 'id' => 'sendmailfrom'));
$to_field = new html_inputfield(array('name' => '_to', 'id' => 'sendmailto'));
if (isset($_POST['sendmail'])) {
echo '<p>Trying to send email...<br />';
$smtp_host = trim($_POST['_smtp_host']);
$smtp_port = $RCI->getprop('smtp_port');
$from = rcube_utils::idn_to_ascii(trim($_POST['_from']));
$to = rcube_utils::idn_to_ascii(trim($_POST['_to']));
$from = idn_to_ascii(trim($_POST['_from']));
$to = idn_to_ascii(trim($_POST['_to']));
if (preg_match('/^' . $RCI->email_pattern . '$/i', $from) &&
preg_match('/^' . $RCI->email_pattern . '$/i', $to)
@ -342,26 +293,42 @@ if (isset($_POST['sendmail'])) {
);
$body = 'This is a test to confirm that Roundcube can send email.';
$smtp_response = array();
// send mail using configured SMTP server
$CONFIG = $RCI->config;
if ($RCI->getprop('smtp_server')) {
$CONFIG = $RCI->config;
if (!empty($_POST['_smtp_user'])) {
$CONFIG['smtp_user'] = $_POST['_smtp_user'];
}
if (!empty($_POST['_smtp_pass'])) {
$CONFIG['smtp_pass'] = $_POST['_smtp_pass'];
}
if (!empty($_POST['_smtp_user'])) {
$CONFIG['smtp_user'] = $_POST['_smtp_user'];
}
if (!empty($_POST['_smtp_pass'])) {
$CONFIG['smtp_pass'] = $_POST['_smtp_pass'];
}
$mail_object = new Mail_mime();
$send_headers = $mail_object->headers($headers);
$mail_object = new Mail_mime();
$send_headers = $mail_object->headers($headers);
$head = $mail_object->txtHeaders($send_headers);
$SMTP = new rcube_smtp();
$SMTP->connect(rcube_parse_host($RCI->getprop('smtp_server')),
$RCI->getprop('smtp_port'), $CONFIG['smtp_user'], $CONFIG['smtp_pass']);
$SMTP = new rcube_smtp();
$SMTP->connect($smtp_host, $smtp_port, $CONFIG['smtp_user'], $CONFIG['smtp_pass']);
$status = $SMTP->send_mail($headers['From'], $headers['To'],
($foo = $mail_object->txtHeaders($send_headers)), $body);
$status = $SMTP->send_mail($headers['From'], $headers['To'], $head, $body);
$smtp_response = $SMTP->get_response();
$smtp_response = $SMTP->get_response();
}
else { // use mail()
$header_str = 'From: ' . $headers['From'];
if (ini_get('safe_mode'))
$status = mail($headers['To'], $headers['Subject'], $body, $header_str);
else
$status = mail($headers['To'], $headers['Subject'], $body, $header_str, '-f'.$headers['From']);
if (!$status)
$smtp_response[] = 'Mail delivery with mail() failed. Check your error logs for details';
}
if ($status) {
$RCI->pass('SMTP send');
@ -373,7 +340,7 @@ if (isset($_POST['sendmail'])) {
else {
$RCI->fail('SMTP send', 'Invalid sender or recipient');
}
echo '</p>';
}
@ -438,7 +405,7 @@ $pass_field = new html_passwordfield(array('name' => '_pass', 'id' => 'imappass'
if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user'])) {
echo '<p>Connecting to ' . rcube::Q($_POST['_host']) . '...<br />';
echo '<p>Connecting to ' . Q($_POST['_host']) . '...<br />';
$imap_host = trim($_POST['_host']);
$imap_port = $RCI->getprop('default_port');
@ -453,8 +420,8 @@ if (isset($_POST['imaptest']) && !empty($_POST['_host']) && !empty($_POST['_user
$imap_port = 993;
}
$imap_host = rcube_utils::idn_to_ascii($imap_host);
$imap_user = rcube_utils::idn_to_ascii($_POST['_user']);
$imap_host = idn_to_ascii($imap_host);
$imap_user = idn_to_ascii($_POST['_user']);
$imap = new rcube_imap(null);
$imap->set_options(array(

@ -1,115 +0,0 @@
{
"dependencies": [
{
"lib": "jquery",
"name": "jQuery",
"version": "3.4.1",
"url": "https://code.jquery.com/jquery-$v.min.js",
"dest": "program/js/jquery.min.js",
"sha1": "88523924351bac0b5d560fe0c5781e2556e7693d",
"license": "MIT",
"copyright": "Copyright JS Foundation and other contributors",
"source": "https://github.com/jquery/jquery/tree/$v"
},
{
"lib": "jstz",
"name": "jsTimezoneDetect",
"version": "1.0.6",
"url": "https://bitbucket.org/pellepim/jstimezonedetect/raw/6c427658686c664da52c6a87cd62ec910baab276/dist/jstz.min.js",
"dest": "program/js/jstz.min.js",
"sha1": "4291cd3b259d2060460c2a6ab99f428d3c0c9537",
"license": "MIT",
"copyright": "Copyright (c) Jon Nylander",
"source": "https://bitbucket.org/pellepim/jstimezonedetect/raw/6c427658686c664da52c6a87cd62ec910baab276/dist/jstz.js"
},
{
"lib": "publickey",
"name": "PublicKey.js",
"version": "0e011cb1",
"url": "https://raw.githubusercontent.com/diafygi/publickeyjs/$v/publickey.js",
"api_url": "https://api.github.com/repos/diafygi/publickeyjs/contents/publickey.js?ref=$v",
"dest": "program/js/publickey.js",
"sha1": "d0920e190754e024c4be76ad5bbc7e76b2e37a4d",
"license": "GPLv3",
"copyright": "Copyright (c) 2015 Daniel Roesler",
"source": "https://github.com/diafygi/publickeyjs/blob/master/publickey.js"
},
{
"lib": "tinymce",
"version": "4.8.2",
"url": "https://download.tiny.cloud/tinymce/community/tinymce_$v.zip",
"dest": "program/js",
"sha1": "d7fced05acdeeb78299585ea9909b0de2b3d759d",
"license": "LGPL",
"copyright": "Copyright (c) 1999-2015 Ephox Corp. All rights reserved",
"rm": "program/js/tinymce",
"map": {
"js/tinymce": "tinymce"
},
"omit": [
"tinymce/license.txt",
"tinymce/jquery.tinymce.min.js"
],
"addlicense": [
"tinymce/tinymce.min.js"
]
},
{
"lib": "tinymce-langs",
"version": "4.8.2",
"url": "https://www.tiny.cloud/docs-4x/language/tinymce4x_languages.zip",
"dest": "program/js/tinymce"
},
{
"lib": "openpgp",
"name": "OpenPGP.js",
"version": "4.4.6",
"url": "https://raw.githubusercontent.com/openpgpjs/openpgpjs/v$v/dist/openpgp.min.js",
"api_url": "https://api.github.com/repos/openpgpjs/openpgpjs/contents/dist/openpgp.min.js?ref=v$v",
"dest": "plugins/enigma/openpgp.min.js",
"sha1": "e142168db8e666a40fcb4c48ef89c9d774134f8b",
"license": "LGPL",
"copyright": "Copyright (c) OpenPGP Development Team",
"source": "https://github.com/openpgpjs/openpgpjs/blob/v$v/dist/openpgp.js"
},
{
"lib": "codemirror",
"version": "5.46.0",
"url": "https://codemirror.net/codemirror-$v.zip",
"dest": "plugins/managesieve/codemirror",
"sha1": "c11fcb9b63cee2b276e3b9f24a8ad6d7c374c624",
"license": "MIT",
"map": {
"lib": "lib",
"addon/selection": "addon/selection",
"mode/sieve": "mode/sieve"
}
},
{
"lib": "bootstrap",
"name": "Bootstrap",
"version": "4.3.1",
"url": "https://github.com/twbs/bootstrap/releases/download/v$v/bootstrap-$v-dist.zip",
"dest": "skins/elastic/deps",
"sha1": "ee9e9d6bbbb6181dc519778af2b38804a6aa62a4",
"license": "MIT",
"flat": true,
"sourcemap": false,
"map": {
"bootstrap.bundle.min.js": "bootstrap.bundle.min.js",
"bootstrap.min.css": "bootstrap.min.css"
}
},
{
"lib": "less",
"name": "LessJS",
"version": "2.7.3",
"url": "https://raw.githubusercontent.com/less/less.js/v$v/dist/less.min.js",
"api_url": "https://api.github.com/repos/less/less.js/contents/dist/less.min.js?ref=v$v",
"dest": "skins/elastic/deps/less.min.js",
"sha1": "45ea4f9fed6c0568ec11faba048c3e3cb7612e9e",
"license": "Apache-2.0",
"source": "https://raw.githubusercontent.com/less/less.js/v$v/dist/less.js"
}
]
}

@ -1,18 +1,8 @@
/**
* ACL plugin script
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (c) 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.
* @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*/
if (window.rcmail) {
@ -43,7 +33,7 @@ if (window.rcmail) {
rcmail.enable_command('acl-delete', 'acl-edit', false);
if (rcmail.env.acl_advanced)
$('#acl-switch').addClass('selected').find('input').prop('checked', true);
$('#acl-switch').addClass('selected');
});
}
@ -67,14 +57,13 @@ rcube_webmail.prototype.acl_delete = function()
{
var users = this.acl_get_usernames();
if (users && users.length) {
this.confirm_dialog(this.get_label('acl.deleteconfirm'), 'delete', function(e, ref) {
ref.http_post('settings/plugin.acl', {
if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) {
this.http_post('settings/plugin.acl', {
_act: 'delete',
_user: users.join(','),
_mbox: rcmail.env.mailbox
}, ref.set_busy(true, 'acl.deleting'));
});
_mbox: this.env.mailbox
},
this.set_busy(true, 'acl.deleting'));
}
}
@ -94,11 +83,11 @@ rcube_webmail.prototype.acl_save = function()
}
if (!user) {
this.alert_dialog(this.get_label('acl.nouser'));
alert(this.get_label('acl.nouser'));
return;
}
if (!rights) {
this.alert_dialog(this.get_label('acl.norights'));
alert(this.get_label('acl.norights'));
return;
}
@ -171,8 +160,8 @@ rcube_webmail.prototype.acl_list_init = function()
// ACL table row selection handler
rcube_webmail.prototype.acl_list_select = function(list)
{
rcmail.enable_command('acl-delete', list.get_selection().length > 0);
rcmail.enable_command('acl-edit', list.get_selection().length == 1);
rcmail.enable_command('acl-delete', list.selection.length > 0);
rcmail.enable_command('acl-edit', list.selection.length == 1);
list.focus();
}
@ -202,7 +191,7 @@ rcube_webmail.prototype.acl_list_update = function(html)
// Returns names of users in selected rows
rcube_webmail.prototype.acl_get_usernames = function()
{
var users = [], n, len, id, row,
var users = [], n, len, cell, row,
list = this.acl_list,
selection = list.get_selection();
@ -210,8 +199,10 @@ rcube_webmail.prototype.acl_get_usernames = function()
if (this.env.acl_specials.length && $.inArray(selection[n], this.env.acl_specials) >= 0) {
users.push(selection[n]);
}
else if ((row = list.rows[selection[n]]) && (id = $(row.obj).data('userid'))) {
users.push(id);
else if (row = list.rows[selection[n]]) {
cell = $('td.user', row.obj);
if (cell.length == 1)
users.push(cell.text());
}
}
@ -230,8 +221,8 @@ rcube_webmail.prototype.acl_remove_row = function(id)
$('#rcmrow'+id).remove();
this.env.acl[id] = null;
this.enable_command('acl-delete', list.get_selection().length > 0);
this.enable_command('acl-edit', list.get_selection().length == 1);
this.enable_command('acl-delete', list.selection.length > 0);
this.enable_command('acl-edit', list.selection.length == 1);
}
// Adds ACL table row
@ -255,14 +246,15 @@ rcube_webmail.prototype.acl_add_row = function(o, sel)
cl = items[cl];
if (cl == 'user')
td.addClass(cl).attr('title', o.title).append($('<a>').text(o.display));
td.addClass(cl).append($('<a>').text(o.username));
else
td.addClass(this.className + ' ' + rcmail.acl_class(o.acl, cl)).html('<span/>');
td.addClass(this.className + ' ' + rcmail.acl_class(o.acl, cl)).text('');
$(this).replaceWith(td);
});
row = row.attr({id: 'rcmrow' + id, 'data-userid': o.username}).get(0);
row.attr('id', 'rcmrow'+id);
row = row.get(0);
this.env.acl[id] = o.acl;
@ -336,7 +328,7 @@ rcube_webmail.prototype.acl_init_form = function(id)
});
if (!this.env.acl_specials.length || $.inArray(id, this.env.acl_specials) < 0)
val = $(row).data('userid');
val = $('td.user', row).text();
else
type = id;
}
@ -352,16 +344,19 @@ rcube_webmail.prototype.acl_init_form = function(id)
var buttons = {}, me = this, body = document.body;
buttons[this.get_label('save')] = function(e) { me.command('acl-save'); };
buttons[this.get_label('cancel')] = function(e) { me.command('acl-cancel'); };
buttons[this.gettext('save')] = function(e) { me.command('acl-save'); };
buttons[this.gettext('cancel')] = function(e) { me.command('acl-cancel'); };
var popup_wrapper = $('<div style="width:480px; min-height:280px"></div>');
this.acl_form.appendTo(popup_wrapper).show();
// display it as popup
this.acl_popup = this.show_popup_dialog(
this.acl_form.show(),
id ? this.get_label('acl.editperms') : this.get_label('acl.newuser'),
popup_wrapper,
id ? this.gettext('acl.editperms') : this.gettext('acl.newuser'),
buttons,
{
button_classes: ['mainaction submit', 'cancel'],
button_classes: ['mainaction'],
modal: true,
closeOnEscape: true,
close: function(e, ui) {
@ -379,7 +374,7 @@ rcube_webmail.prototype.acl_init_form = function(id)
$('input:checked', type_list).focus();
}
// Returns class name according to ACL comparison result
// Returns class name according to ACL comparision result
rcube_webmail.prototype.acl_class = function(acl1, acl2)
{
var i, len, found = 0;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save