Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F224965
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
154 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/CHANGELOG b/CHANGELOG
index 90b5eb6e0..711cf8da5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,495 +1,496 @@
CHANGELOG RoundCube Webmail
===========================
+- Fix autocomplete spinning wheel does not disappear (#1485804)
- Added log_date_format option (#1485709)
- Fix text wrapping in HTML editor after switching from plain text to HTML (#1485521)
- Fix auto-complete function hangs with plus sign (#1485815)
- Fix AJAX requests errors handler (#1485000)
- Speed up message list displaying on IE
- Fix read/write database recognition (#1485811)
- Fix quicksearchbox look in Chrome and Konqueror (#1484841)
- Fix UTF-8 byte-order mark removing (#1485514)
- Fix folders subscribtions on Konqueror (#1484841)
- Fix debug console on Konqueror and Safari
- Fix messagelist focus issue when modifying status of selected messages (#1485807)
- Support STARTTLS in IMAP connection (#1485284)
- Fix DEL key problem in search boxes (#1485528)
- Support several e-mail addresses per user from virtuser_file (#1485678)
- Fix drag&drop with scrolling on IE (#1485786)
- Fix adding signature separator in html mode (#1485350)
- Fix opening attachment marks message as read (#1485803)
- Fix 'temp_dir' does not support relative path under Windows (#1484529)
- Fix "Initialize Database" button missing from installer (#1485802)
- Fix compose window doesn't fit 1024x768 window (#1485396)
- Fix service not available error when pressing back from compose dialog (#1485552)
- Fix using mail() on Windows (#1485779)
- Fix word wrapping in message-part's <PRE>s for printing (#1485787)
- Fix incorrect word wrapping in outgoing plaintext multibyte messages (#1485714)
- Fix double footer in HTML message with embedded images
- Fix TNEF implementation bug (#1485773)
- Fix incorrect row id parsing for LDAP contacts list (#1485784)
- Fix 'mode' parameter in sqlite DSN (#1485772)
RELEASE 0.2.1
------------------
- Use US-ASCII as failover when Unicode searching fails (#1485762)
- Fix errors handling in IMAP command continuations (#1485762)
- Fix FETCH result parsing for servers returning flags at the end of result (#1485763)
- Fix datetime columns defaults in mysql's DDL (#1485641)
- Fix attaching more than nine inline images (#1485759)
- Support 'UNICODE-1-1-UTF-7' alias for UTF-7 encoding (#1485758)
- Fix mime-type detection using a hard-coded map (#1485311)
- Don't return empty string if charset conversion failed (#1485757)
- Disable concurrent autocomplete query results display (#1485743)
- Fix new lines stripped from message footer (#1485751)
- Fix IE problem with mouse click autocomplete (#1485739)
- Fix html body washing on reply/forward + fix attachments handling (#1485676)
- Fix multiple recipients input parsing (#1485733)
- Fix replying to message with html attachment (#1485676)
- Use default_charset for messages without specified charset (#1485661, #1484961)
- Support non-standard "GMT-XXXX" literal in date header (#1485729)
- Added TNEF support to decode MS Outlook attachments (winmail.dat)
- Fix "value continuation" MIME headers by adding required semicolon (#1485727)
- Fix pressing select all/unread multiple times (#1485723)
- Fix selecting all unread does not honor new messages (#1485724)
- Fix some base64 encoded attachments handling (#1485725)
- Support NGINX as IMAP backend: better BAD response handling (#1485720)
- Performance fix: don't fetch attachment parts headers twice to parse filename
- Fix checking for recent messages on various IMAP servers (#1485702)
- Performance fix: Don't fetch quota and recent messages in "message view" mode
- Fix displaying of alternative-inside-alternative messages (#1485713)
- Fix MDNSent flag checking, use arbitrary keywords (asterisk) flag (#1485706)
- Fix creation of folders with '&' sign in name
- Fix parsing of email addresses without angle brackets (#1485693)
- Save spellcheck corrections when switching from plain to html editor (and spellchecking is on)
- Fix large search results on server without SORT capability (#1485668)
- Get rid of preg_replace() with eval modifier and create_function usage (#1485686)
- Bring back <base> and <link> tags in HTML messages
- Fix XSS vulnerability through background attributes as reported by Julien Cayssol
- Fix problems with backslash as IMAP hierarchy delimiter (#1484467)
- Secure vcard export by getting rid of preg's 'e' modifier use (#1485689)
- Fix authentication when submitting form with existing session (#1485679)
- Allow absolute URLs to images in HTML messages/sigs (#1485666)
- Fix message body which contains both inline attachments and emotions
- Fix SQL query execution errors handling in rcube_mdb2 class (#1485509)
- Fix address names with '@' sign handling (#1485654)
- Improve messages display performance
- Fix messages searching with 'to:' modifier
RELEASE 0.2-STABLE
------------------
- Fix mark popup in IE 7 (#1485369)
- Fix line-break issue when copy & paste in Firefox (#1485425)
- Fix autocomplete "unknown server error" (#1485637)
- Fix STARTTLS before AUTH in SMTP connection (#1484883)
- Support multiple quota values in QUOTAROOT resonse (#1485626)
- Only abbreviate file name for IE < 7 browsers (#1485063)
- Performance: allow setting imap rootdir and delimiter before connect (#1485172)
- Fix sorting of folders with more than 2 levels (#1485569)
- Fix search results page jumps in LDAP addressbook (#1485253)
- Fix empty line before the signature in IE (#1485351)
- Fix horizontal scrollbar in preview pane on IE (#1484633)
- Add Robots meta tag in login page and installer (#1484846)
- Added 'show_images' option, removed 'addrbook_show_images' (#1485597)
- Option to check for new mails in all folders (#1484374)
- Don't set client busy when checking for new messages (#1485276)
- Allow UTF-8 folder names in config (#1485579)
- Add junk_mbox option configuration in installer (#1485579)
- Do serverside addressbook queries for autocompletion (#1485531)
- Allow setting attachment col position in 'list_cols' option
- Allow override 'list_cols' via skin (#1485577)
- Fix 'cache' table cleanup on session destroy (#1485516)
- Increase speed of session destroy and garbage clean up
- Fix session timeout when DB server got clock skew (#1485490)
- Fix handling of some malformed messages (#1484438)
- Speed up raw message body handling
- Better HTML entities conversion in html2text (#1485519)
- Fix big memory consumption and speed up searching on servers without SORT capability
- Fix setting locale to tr_TR, ku and az_AZ (#1485470)
- Use SORT for searching on servers with SORT capability
- Added message status filter
- Fix empty file sending (#1485389)
- Improved searching with many criterias (calling one SEARCH command)
- Fix HTML editor initialization on IE (#1485304)
- Add warning when switching editor mode from html to plain (#1485488)
- Make identities list scrollable (#1485538)
- Fix problem with numeric folder names (#1485527)
- Added BYE response simple support to prevent from endless loops in imap.inc (#1483956)
- Fix unread message unintentionally marked as read if read_when_deleted=true (#1485409)
- Remove port number from SERVER_NAME in smtp_helo_host (#1485518)
- Don't send disposition notification receipts for messages marked as 'read' (#1485523)
- Added 'keep_alive' and 'min_keep_alive' options (#1485360)
- Added option 'identities_level', removed 'multiple_identities'
- Allow deleting identities when multiple_identities=false (#1485435)
- Added option focus_on_new_message (#1485374)
- Fix html2text class autoloading on Windows (#1485505)
- Fix html signature formatting when identity save error occured (#1485426)
- Add feedback and set busy when moving folder (#1485497)
- Fix 'Empty' link visibility for some languages e.g. Slovak (#1485489)
- Fix messages count bar overlapping (#1485270)
- Fix adding signature in drafts compose mode (#1485484)
- Fix iil_C_Sort() to support very long and/or divided responses (#1485283)
- Fix matching case sensitivity when setting identity on reply (#1485480)
- Prefer default identity on reply
- Fix imap searching on ISMail server (#1485466)
- Add css class for flagged messages (#1485464)
- Write username instead of id in sendmail log (#1485477)
- Fix htmlspecialchars() use for PHP version < 5.2.3 (#1485475)
- Fix js keywords escaping in json_serialize() for IE/Opera (#1485472)
- Added bin/killcache.php script (#1485434)
- Add support for SJIS, GB2312, BIG5 in rc_detect_encoding()
- Fix vCard file encoding detection for non-UTF-8 strings (#1485410)
- Add 'skip_deleted' option in User Preferences (#1485445)
- Minimize "inline" javascript scripts use (#1485433)
- Fix css class setting for folders with names matching defined classes names (#1485355)
- Fix race conditions when changing mailbox
- Fix spellchecking when switching to html editor (#1485362)
- Fix compose window width/height (#1485396)
- Allow calling msgimport.sh/msgexport.sh from any directory (#1485431)
- Localized filesize units (#1485340)
- Better handling of "no identity" and "no email in identity" situations (#1485117)
- Added 'mime_param_folding' option with possibility to choose long/non-ascii attachment names encoding eg. to be readable in MS Outlook/OE (#1485320)
- Added "advanced options" feature in User Preferences
- Fix unread counter when displaying cached massage in preview panel (#1485290)
- Fix htmleditor spellchecking on MS Windows (#1485397)
- Fix problem with non-ascii attachment names in Mail_mime (#1485267, #1485096)
- Fix language autodetection (#1485401)
- Fix button label in folders management (#1485405)
- Fix collapsed folder not indicating unread msgs count of all subfolders (#1485403)
- Fix handling of apostrophes in filenames decoded according to rfc2231
RELEASE 0.2-BETA
----------------
- Made config files location configurable (#1485215)
- Reduced memory footprint when forwarding attachments (#1485345)
- Allow and use spellcheck attribute for input/textarea fields (#1485060)
- Added icons for forwarded/forwarded+replied messages (#1485257)
- Added Reply-To to forwarded emails (#1485315)
- Display progress message for folders create/delete/rename (#1485357)
- Smart Tags and NOBR tag support in html messages (#1485363, #1485327)
- Redesign of the identities settings (#1484042)
- Add config option to disable creation/deletion of identities (#1484498)
- Added 'sendmail_delay' option to restrict messages sending interval (#1484491)
- Added vertical splitter for folders list resizing
- Added possibility to view all headers in message view
- Fixed splitter drag/resize on Opera (#1485170)
- Fixed quota img height/width setting from template (#1484857)
- Refactor drag & drop functionality. Don't rely on browser events anymore (#1484453)
- Insert "virtual" folders in subscription list (#1484779)
- Added link to open message in new window
- Enable export of address book contacts as vCard
- Add feature to import contacts from vcard files (#1326103)
- Respect Content-Location headers in multipart/related messages according to RFC2110 (#1484946)
- Allowed max. attachment size now indicated in compose screen (#1485030)
- Also capture backspace key in list mode (#1484566)
- Allow application/pgp parts to be displayed (#1484753)
- Correctly handle options in mailto-links (#1485228)
- Immediately save sort_col/sort_order in user prefs (#1485265)
- Truncate very long (above 50 characters) attachment filenames when displaying
- Allow to auto-detect client language if none set (#1484434)
- Auto-detect the client timezone (user configurable)
- Add RFC2231 header value continuations support for attachment filenames + hack for servers that not support that feature
- Fix Reply-To header displaying (#1485314)
- Mark form buttons that provide the most obvious operation (mainaction)
- Added option 'quota_zero_as_unlimited' (#1484604)
- Added PRE handling in html2text class (#1484740)
- Added folder hierarchy collapsing
- Added options to use syslog instead of log file (#1484850)
- Added Logging & Debugging section in Installer
- Fix In-Reply-To and References headers when composing saved draft message (#1485288)
- Fix html message charset conversion for charsets with underline (#1485287)
- Fix buttons status after contacts deletion (#1485233)
- Fix escaping of To: and From: fields when building message body for reply or forward in the HTML editor (#1484904)
- Use current mailbox name in template (#1485256)
- Better fix for skipping untagged responses (#1485261)
- Added pspell support patch by Kris Steinhoff (#1483960)
- Enable spellchecker for HTML editor (#1485114)
- Respect spellcheck_uri in tinyMCE spellchecker (#1484196)
- Case insensitive contacts searching using PostgreSQL (#1485259)
- Make default imap folders configurable for each user (#1485075)
- Save outgoing mail to selectable folder (#1324581)
- Fix hiding of mark menu when clicking th button again (#1484944)
- Use long date format in print mode (#1485191)
- Updated TinyMCE to version 3.1.0.1
- Re-enable autocomplete attribute for login form (#1485211)
- Check PERMANENTFLAGS before saving $MDNSent flag (#1484963, #1485163)
- Added flag column on messages list (#1484623)
- Patched Mail/MimePart.php (http://pear.php.net/bugs/bug.php?id=14232)
- Allow trash/junk subfolders to be purged (#1485085)
- Store compose parameters in session and redirect to a unique URL
- Fixed CRAM-MD5 authentication (#1484819)
- Fixed forwarding messages with one HTML attachment (#1484442)
- Fixed encoding of message/rfc822 attachments and image/pjpeg handling (#1484914)
- Added option to select skin in user preferences
- Added option to configure displaying of attached images below the message body
- Added option to display images in messages from known senders (#1484601)
- User preferences grouped in more fieldsets
- Fix corrupted MIME headers of messages in Sent folder (#1485111)
- Fixed bug in MDB2 package: http://pear.php.net/bugs/bug.php?id=14124
- Use keypress instead of keydown to select list's row (#1484816)
- Don't call expunge and don't remove message row after message move if flag_for_deletion is set to true (#1485002)
RELEASE 0.2-ALPHA
-----------------
- Added option to disable autocompletion from selected LDAP address books (#1484922)
- TLS support in LDAP connections: 'use_tls' property (#1485104)
- Fixed removing messages from search set after deleting them (#1485106)
- imap.inc: Fixed iil_C_FetchStructureString() to handle many
literal strings in response (#1484969)
- Support for subfolders in default/protected folders (#1484665)
- Disallowed delimiter in folder name (#1484803)
- Support " and \ in folder names
- Escape \ in login (#1484614)
- Better HTML sanitization with the DOM-based washtml script (#1484701)
- Fixed sorting of folders with non-ascii characters
- Fixed Mysql DDL for default identities creation (#1485070)
- In Preferences added possibility to configure 'read_when_deleted',
'mdn_requests', 'flag_for_deletion' options
- Made IMAP auth type configurable (#1483825)
- Fixed empty values with FROM_UNIXTIME() in rcube_mdb2 (#1485055)
- Fixed attachment list on IE 6/7 (#1484807)
- Fixed JavaScript in compose.html that shows cc/bcc fields if populated
- Make password input fields of type password in installer (#1484886)
- Don't attempt to delete cache entries if enable_caching is FALSE (#1485051)
- Optimized messages sorting on servers without sort capability (#1485049)
- Corrected message headers decoding when charset isn't specified and improved
support for native languages (#1485050, #1485048)
- Expanded LDAP configuration options to support LDAP server writes.
- Installer: encode special characters in DB username/password (#1485042)
- Fixed management of folders with national characters in names (#1485036, #1485001)
- Fixed identities saving when using MDB2 pgsql driver (#1485032)
- Fixed BCC header reset (#1484997)
- Improved messages list performance - patch from Justin Heesemann
- Append skin_path to images location only when it starts with '/' sign (#1484859)
- Fix IMAP response in message body when message has no body (#1484964)
- Fixed non-RFC dates formatting (#1484901)
- Fixed typo in set_charset() (#1484991)
- Decode entities when inserting HTML signature to plain text message (#1484990)
- HTML editing is now working with PHP5 updates and TinyMCE v3.0.6
- Fixed signature loading on Windows (#1484545)
- Added language support to HTML editing (#1484862)
- Fixed remove signature when replying (#1333167)
- Fixed problem with line with a space at the end (#1484916)
- Fixed <!DOCTYPE> tag filtering (#1484391)
- Fixed <?xml> tag filtering (#1484403)
- Added sections (fieldset+label) in Settings interface
- Mark as read in one action with message preview (#1484972)
- Deleted redundant quota reads (#1484972)
- Added options for empty trash and expunge inbox on logout (#1483863)
- Removed lines wrapping when displaying message
- Fixed month localization
- Changed codebase to PHP5 with autoloader
RELEASE 0.1.1
-------------
- Clear selection when selecting single item (#1484942)
- Remove hard-coded image size in skin templates (#1484893)
- Database schema improvements (dropped unnecessary indexes)
- Fixed creating a new folder with a comma in its name (#1484681)
- Fixed sorting of messages when default mailbox is empty (#1484317)
- Improve message previewpane - less loading (#1484316)
- Fixed login form autoompletion (#1484839)
- Fixed virtuser_query option for mdb2 backend (#1484874)
- Fixed attachment resoting from Drafts when message body was empty (#1484506)
- Fixed usage of ob_gzhandler (#1484851)
- Fixed message part window in IE6 (#1484610)
- Fixed decoding of mime-encoded strings (#1484191)
- Fixed some iconv/mb_string problems (#1484598)
- Correctly quote mailbox name when using in URL (#1484313)
- Fixed "headers already sent" errors (#1484860)
RELEASE 0.1-STABLE
------------------
- Added interactive installer script
- Fix folder adding/renaming inspired by #1484800
- Localize folder name in page title (#1484785)
- Fix code using wrong variable name (#1484018)
- Allow to send mail with BCC recipients only
- condense TinyMCE toolbar down to one line, removing table buttons (#1484747)
- Add function to mark the selected messages as read/unread (#1457360)
- Also do charset decoding as suggested in RFC 2231 (fix #1484321)
- Show message count in folder list and hint when creating a subfolder
- Distinguish ssl and tls for imap connections (#1484667)
- Added some charset aliases to fix typical mis-labelling (#1484565)
- Remember decision to display images for a certain message during session (#1484754)
- Truncate attachment filenames to 55 characters due to an IE bug (#1484757)
- Make sending of read receipts configurable
- Respect config when localize folder names (#1484707)
- Also respect receipt and priority settings when re-opening a draft message
- Remember search results (closes #1483883), patch by the_glu
- Add Received header on outgoing mail
- Upgrade to TinyMCE 2.1.3
- Allow inserting image attachments into HTML messages while composing (#1484557)
- Implement Message-Disposition-Notification (Receipts)
- Fix overriding of session vars when register_globals is on (#1484670)
- Fix bug with case-sensitive folder names (#1484245)
- Don't create default folders by default
- Fixed some potential security risks (audited by Andris)
- Only show new messages if they match the current search (#1484176)
- Switch to/from when searcing in Sent folder (#1484555)
- Correctly read the References header (#1484646)
- Unset old cookie before sending a new value (#1484639)
- Correctly decode attachments when downloading them (#1484645 and #1484642)
- Suppress IE errors when clearing attachments form (#1484356)
- Log error when login fails due to auto_create_user turned off
- Filter linked/imported CSS files (closes #1484056)
- Improve message compose screen (closes #1484383)
- Select next row after removing one from list (#1484387)
RELEASE 0.1-RC2
---------------
- Enable drag-&-dropping of folders to a new parent and allow to create subfolders (#1457344)
- Suppress IE errors when clearing attachments form (#1484356)
- Set preferences field in user table to NULL (#1484386)
- Log error when login fails due to auto_create_user turned off
- Filter linked/imported CSS files (closes #1484056)
- Improve message compose screen (closes #1484383)
- Select next row after removing one from list (#1484387)
- Make smtp HELO/EHLO hostname configurable (#1484067)
- IPv6 Compatability (#1484322), Patch #1484373
- Unlock interface when message sending fails (#1484570)
- Eval PHP code in template includes (if configured)
- Show message when folder is empty. Mo more static text in table (#1484395)
- Only display unread count in page title when new messages arrived
- Fixed wrong delete button tooltip (#1483965)
- Fixed charset encoding bug (#1484429)
- Applied patch for LDAP version (#1484552)
- Improved XHTML validation
- Fix message list selection (#1484550)
- Better fix lowercased usernames (#1484473)
- Update pngbehavior Script as suggested in #1484490
- Fixed moving/deleting messages when more than 1 is selected
- Applied patch for LDAP contacts listing by Glen Ogilvie
- Applied patch for more address fields in LDAP contacts (#1484402)
- Add alternative for getallheaders() (fix #1484508)
- Identify mailboxes case-sensitive
- Sort mailbox list case-insensitive (closes #1484338)
- Fix display of multipart messages from Apple Mail (closes #1484027)
- Protect AJAX request from being fetched by a foreign site (XSS)
- Make autocomplete for loginform configurable by the skin template
- Fix compose function from address book (closes #1484426)
- Added //IGNORE to iconv call (patch #1484420, closes #1484023)
- Check if mbstring supports charset (#1484290 and #1484292)
- Prefer iconv over mbstring (as suggested in #1484292)
- Check filesize of template includes (#1484409)
- Fixed bug with buttons not dimming/enabling properly after switching folders
- Fixed compose window becoming unresponsive after saving a draft (#1484487)
- Re-enabled "Back" button in compose window now that bug #1484487 is fixed
- Fixed unresponsive interface issue when downloading attachments (#1484496)
- Lowered status message time from 5 to 3 seconds to improve responsiveness
- Raised .htaccess upload_max_filesize from 2M to 5M to differ from default php.ini
- Increased "mailboxcontrols" mail.css width from 160 to 170px to fix non-english languages (#1484499)
- Fix status message bug #1484464 with regard to #1484353
- Fix address adding bug reported by David Koblas
- Applied socket error patch by Thomas Mangin
- Pass-by-reference workarround for PHP5 in sendmail.inc
- Fixed buggy imap_root settings (closes #1484379)
- Prevent default events on subject links (#1484399)
- Use HTTP-POST requests for actions that change state
RELEASE 0.1-RC1
---------------
- Use global filters and bind username/ for Ldap searches (#1484159)
- Hide quota display if imap server does not support it
- Hide address groups if no LDAP servers configured
- Add link to message subjects (closes #1484257)
- Better SQL query for contact listing/search (closes #1484369)
- Fixed marking as read in preview pane (closes #1484364)
- CSS hack to display attachments correctly in IE6
- Wrap message body text (closes #1484148)
- LDAP access is back in address book (closes #1484087)
- Added search function for contacts
- New Template parsing and output encoding
- Fixed bugs #1484119 and #1483978
- Fixed message moving procedure (closes #1484308)
- Fixed display of multiple attachments (closes #1466563)
- Fixed check for new messages (closes #1484310)
- List attachments without filename
- New session authentication: Change sessid cookie when login, authentication with sessauth cookie is now configurable.
Should close bugs #1483951 and #1484299
- Correctly translate mailbox names (closes #1484276)
- Quote e-mail address links (closes #1484300)
- Updated PEAR::Mail_mime package
- Accept single quotes for HTML attributes when modifying message body (thanks Jason)
- Sanitize input for new users/identities (thanks Colin Alston)
- Don't download HTML message parts
- Convert HTML parts to plaintext if 'prefer_html' is off
- Correctly parse message/rfc822 parts (closes #1484045)
- Also use user_id for unique key in messages table (closes #1484074)
- Hide contacts drop down on blur (closes #1484203)
- Make entries in contacts drop down clickable
- Turn off browser autocompletion on login page
- Quote <? in text/html message parts
- Hide border around radio buttons
- Applied patch for attachment download by crichardson (closes #1484198)
- Fixed bug in Postgres DB handling (closes #1484068)
- Fixed bug of invalid calls to fetchRow() in rcube_db.inc (closes #1484280)
- Fixed array_merge bug (closes #1484281)
- Fixed flag for deletion in list view (closes #1484264)
- Finally support semicolons as recipient separator (closes ##1484251)
- Fixed message headers (subject) encoding
- check if safe mode is on or not (closes #1484269)
- Show "no subject" in message list if subject is missing (closes #1484243)
- Solved page caching of message preview (closes #1484153)
- Only use gzip compression if configured (closes #1484236)
- Fixed priority selector issue (#1484150)
- Fixed some CSS issues in default skin (closes #1484210 and #1484161)
- Prevent from double quoting of numeric HTML character references (closes #1484253)
- Fixed display of HTML message attachments (closes #1484178)
- Applied patch for preview caching (closes #1484186)
- Added error handling for attachment uploads
- Use multibyte safe string functions where necessary (closes #1483988)
- Applied security patch to validate the submitted host value (by Kees Cook)
- Applied security patch to validate input values when deleting contacts (by Kees Cook)
- Applied security patch that sanitizes emoticon paths when attaching them (by Kees Cook)
- Applied a patch to more aggressively sanitize a HTML message
- Visualize blocked images in HTML messages
- Fixed wrong message listing when showing search results (closes #1484131)
- Show remote images when opening HTML message part as attachment
- Improve memory usage when sending mail (closes #1484098)
- Mark messages as read once the preview is loaded (closes #1484132)
- Include smtp final response in log (closes #1484081)
- Corrected date string in sent message header (closes #1484125)
- Correclty choose "To" column in sent and draft mailboxes (closes #1483943)
- Changed srong tooltips for message browse buttons (closes #1483930)
- Fixed signature delimeter character to be standard (Bug #1484035)
- Fixed XSS vulnerability (Bug #1484109)
- Remove newlines from mail headers (Bug #1484031)
- Selection issues when moving/deleting (Bug #1484044)
- Applied patch of Clement Moulin for imap host auto-selection
- ISO-encode IMAP password for plaintext login (Bugs #1483977 & #1483886)
- Fixed folder name encoding in subscription list (Bug #1484113)
- Fixed JS errors in identity list (Bug #1484120)
- Translate foldernames in folder form (closes #1484113)
- Added first and last buttons to message list, address book
and message detail
- Pressing Shift-Del bypasses Trash folder
- Enable purge command for Junk folder
- Fetch all aliases if virtuser_query is used instead
- Re-enabled multi select of contacts (Bug #1484017)
- Enable contact editing right after creation (Bug #1459641)
- Correct UTF-7 to UTF-8 conversion if mbstring is not available
- Fixed IMAP fetch of message body (Bug #1484019)
- Fixed safe_mode problems (Bug #1418381)
- Fixed wrong header encoding (Bug #1483976)
- Made automatic draft saving configurable
- Fixed JS bug when renaming folders (Bug #1483989)
- Added quota display as image (by Brett Patterson)
- Corrected creation of a message-id
- New indentation for quoted message text
- Improved HTML validity
- Fixed URL character set (Ticket #1445501)
- Fixed saving of contact into MySQL from LDAP query results (Ticket #1483820)
- Fixed folder renaming: unsubscribe before rename (Bug #1483920)
- Finalized new message parsing (+ chaching)
- Fixed wrong usage of mbstring (Bug #1462439)
- Set default spelling language (Ticket #1483938)
- Added support for Nox Spell Server
- Re-built message parsing (Bug #1327068)
Now based on the message structure delivered by the IMAP server.
- Fixed some XSS and SQL injection issues
- Fixed charset problems with folder renaming
diff --git a/program/js/app.js b/program/js/app.js
index eed88618d..f0317837d 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -1,4043 +1,4043 @@
/*
+-----------------------------------------------------------------------+
| RoundCube Webmail Client Script |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2009, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
| Authors: Thomas Bruederli <roundcube@gmail.com> |
| Charles McNulty <charles@charlesmcnulty.com> |
+-----------------------------------------------------------------------+
| Requires: jquery.js, common.js, list.js |
+-----------------------------------------------------------------------+
$Id$
*/
function rcube_webmail()
{
this.env = new Object();
this.labels = new Object();
this.buttons = new Object();
this.gui_objects = new Object();
this.gui_containers = new Object();
this.commands = new Object();
this.command_handlers = new Object();
this.onloads = new Array();
// create protected reference to myself
this.ref = 'rcmail';
var ref = this;
// webmail client settings
this.dblclick_time = 500;
this.message_time = 3000;
this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
// mimetypes supported by the browser (default settings)
this.mimetypes = new Array('text/plain', 'text/html', 'text/xml',
'image/jpeg', 'image/gif', 'image/png',
'application/x-javascript', 'application/pdf',
'application/x-shockwave-flash');
// default environment vars
this.env.keep_alive = 60; // seconds
this.env.request_timeout = 180; // seconds
this.env.draft_autosave = 0; // seconds
this.env.comm_path = './';
this.env.bin_path = './bin/';
this.env.blankpage = 'program/blank.gif';
// set jQuery ajax options
jQuery.ajaxSetup({ cache:false,
error:function(request, status, err){ ref.http_error(request, status, err); },
beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Referer', bw.get_cookie('roundcube_sessid')); }
});
// set environment variable(s)
this.set_env = function(p, value)
{
if (p != null && typeof(p) == 'object' && !value)
for (var n in p)
this.env[n] = p[n];
else
this.env[p] = value;
};
// add a localized label to the client environment
this.add_label = function(key, value)
{
this.labels[key] = value;
};
// add a button to the button list
this.register_button = function(command, id, type, act, sel, over)
{
if (!this.buttons[command])
this.buttons[command] = new Array();
var button_prop = {id:id, type:type};
if (act) button_prop.act = act;
if (sel) button_prop.sel = sel;
if (over) button_prop.over = over;
this.buttons[command][this.buttons[command].length] = button_prop;
};
// register a specific gui object
this.gui_object = function(name, id)
{
this.gui_objects[name] = id;
};
// register a container object
this.gui_container = function(name, id)
{
this.gui_containers[name] = id;
};
// add a GUI element (html node) to a specified container
this.add_element = function(elm, container)
{
if (this.gui_containers[container] && this.gui_containers[container].jquery)
this.gui_containers[container].append(elm);
};
// register an external handler for a certain command
this.register_command = function(command, callback, enable)
{
this.command_handlers[command] = callback;
if (enable)
this.enable_command(command, true);
};
// execute the given script on load
this.add_onload = function(f)
{
this.onloads[this.onloads.length] = f;
};
// initialize webmail client
this.init = function()
{
var p = this;
this.task = this.env.task;
// check browser
if (!bw.dom || !bw.xmlhttp_test())
{
this.goto_url('error', '_code=0x199');
return;
}
// find all registered gui containers
for (var n in this.gui_containers)
this.gui_containers[n] = $('#'+this.gui_containers[n]);
// find all registered gui objects
for (var n in this.gui_objects)
this.gui_objects[n] = rcube_find_object(this.gui_objects[n]);
// tell parent window that this frame is loaded
if (this.env.framed && parent.rcmail && parent.rcmail.set_busy)
parent.rcmail.set_busy(false);
// enable general commands
this.enable_command('logout', 'mail', 'addressbook', 'settings', true);
if (this.env.permaurl)
this.enable_command('permaurl', true);
switch (this.task)
{
case 'mail':
if (this.gui_objects.messagelist)
{
this.message_list = new rcube_list_widget(this.gui_objects.messagelist, {multiselect:true, draggable:true, keyboard:true, dblclick_time:this.dblclick_time});
this.message_list.row_init = function(o){ p.init_message_row(o); };
this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); });
this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); });
this.message_list.addEventListener('select', function(o){ p.msglist_select(o); });
this.message_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
this.message_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
this.message_list.addEventListener('dragend', function(o){ p.drag_active = false; });
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
this.message_list.init();
this.enable_command('toggle_status', 'toggle_flag', true);
if (this.gui_objects.mailcontframe)
this.gui_objects.mailcontframe.onmousedown = function(e){ return p.click_on_list(e); };
else
this.message_list.focus();
}
if (this.env.coltypes)
this.set_message_coltypes(this.env.coltypes);
// enable mail commands
this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true);
if (this.env.search_text != null && document.getElementById('quicksearchbox') != null)
document.getElementById('quicksearchbox').value = this.env.search_text;
if (this.env.action=='show' || this.env.action=='preview')
{
this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource', 'print', 'load-attachment', 'load-headers', true);
if (this.env.next_uid)
{
this.enable_command('nextmessage', true);
this.enable_command('lastmessage', true);
}
if (this.env.prev_uid)
{
this.enable_command('previousmessage', true);
this.enable_command('firstmessage', true);
}
}
if (this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox)
this.set_alttext('delete', 'movemessagetotrash');
// make preview/message frame visible
if (this.env.action == 'preview' && this.env.framed && parent.rcmail)
{
this.enable_command('compose', 'add-contact', false);
parent.rcmail.show_contentframe(true);
}
if ((this.env.action=='show' || this.env.action=='preview') && this.env.blockedobjects)
{
if (this.gui_objects.remoteobjectsmsg)
this.gui_objects.remoteobjectsmsg.style.display = 'block';
this.enable_command('load-images', 'always-load', true);
}
if (this.env.action=='compose')
{
this.enable_command('add-attachment', 'send-attachment', 'remove-attachment', 'send', true);
if (this.env.spellcheck)
{
this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); };
this.set_spellcheck_state('ready');
if ($("input[name='_is_html']").val() == '1')
this.display_spellcheck_controls(false);
}
if (this.env.drafts_mailbox)
this.enable_command('savedraft', true);
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
}
if (this.env.messagecount)
this.enable_command('select-all', 'select-none', 'expunge', true);
if (this.purge_mailbox_test())
this.enable_command('purge', true);
this.set_page_buttons();
// init message compose form
if (this.env.action=='compose')
this.init_messageform();
// show printing dialog
if (this.env.action=='print')
window.print();
// get unread count for each mailbox
if (this.gui_objects.mailboxlist)
{
this.env.unread_counts = {};
this.gui_objects.folderlist = this.gui_objects.mailboxlist;
this.http_request('getunread', '');
}
// ask user to send MDN
if (this.env.mdn_request && this.env.uid)
{
var mdnurl = '_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox);
if (confirm(this.get_label('mdnrequest')))
this.http_post('sendmdn', mdnurl);
else
this.http_post('mark', mdnurl+'&_flag=mdnsent');
}
break;
case 'addressbook':
if (this.gui_objects.contactslist)
{
this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:true, keyboard:true});
this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); });
this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); });
this.contact_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
this.contact_list.addEventListener('dragmove', function(o, e){ p.drag_move(e); });
this.contact_list.addEventListener('dragend', function(o){ p.drag_active = false; });
this.contact_list.init();
if (this.env.cid)
this.contact_list.highlight_row(this.env.cid);
if (this.gui_objects.contactslist.parentNode)
{
this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
}
else
this.contact_list.focus();
this.gui_objects.folderlist = this.gui_objects.contactslist;
}
this.set_page_buttons();
if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly)
this.enable_command('add', true);
if (this.env.cid)
this.enable_command('show', 'edit', true);
if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
this.enable_command('save', true);
else
this.enable_command('search', 'reset-search', 'moveto', 'import', true);
if (this.contact_list && this.contact_list.rowcount > 0)
this.enable_command('export', true);
this.enable_command('list', true);
break;
case 'settings':
this.enable_command('preferences', 'identities', 'save', 'folders', true);
if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity') {
this.enable_command('add', this.env.identities_level < 2);
this.enable_command('delete', 'edit', true);
}
if (this.env.action=='edit-identity' || this.env.action=='add-identity')
this.enable_command('save', true);
if (this.env.action=='folders')
this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true);
if (this.gui_objects.identitieslist)
{
this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false});
this.identity_list.addEventListener('select', function(o){ p.identity_select(o); });
this.identity_list.init();
this.identity_list.focus();
if (this.env.iid)
this.identity_list.highlight_row(this.env.iid);
}
if (this.gui_objects.subscriptionlist)
this.init_subscription_list();
break;
case 'login':
var input_user = $('#rcmloginuser');
input_user.bind('keyup', function(e){ return rcmail.login_user_keyup(e); });
if (input_user.val() == '')
input_user.focus();
else
$('#rcmloginpwd').focus();
// detect client timezone
$('#rcmlogintz').val(new Date().getTimezoneOffset() / -60);
this.enable_command('login', true);
break;
default:
break;
}
// enable basic commands
this.enable_command('logout', true);
// flag object as complete
this.loaded = true;
// show message
if (this.pending_message)
this.display_message(this.pending_message[0], this.pending_message[1]);
// map implicit containers
if (this.gui_objects.folderlist)
this.gui_containers.foldertray = $(this.gui_objects.folderlist);
// trigger init event hook
this.triggerEvent('init', { task:this.task, action:this.env.action });
// execute all foreign onload scripts
// @deprecated
for (var i=0; i<this.onloads.length; i++)
{
if (typeof(this.onloads[i]) == 'string')
eval(this.onloads[i]);
else if (typeof(this.onloads[i]) == 'function')
this.onloads[i]();
}
// start keep-alive interval
this.start_keepalive();
};
// start interval for keep-alive/recent_check signal
this.start_keepalive = function()
{
if (this.env.keep_alive && !this.env.framed && this.task=='mail' && this.gui_objects.mailboxlist)
this._int = setInterval(function(){ ref.check_for_recent(false); }, this.env.keep_alive * 1000);
else if (this.env.keep_alive && !this.env.framed && this.task!='login')
this._int = setInterval(function(){ ref.send_keep_alive(); }, this.env.keep_alive * 1000);
}
this.init_message_row = function(row)
{
var uid = row.uid;
if (uid && this.env.messages[uid])
{
row.deleted = this.env.messages[uid].deleted ? true : false;
row.unread = this.env.messages[uid].unread ? true : false;
row.replied = this.env.messages[uid].replied ? true : false;
row.flagged = this.env.messages[uid].flagged ? true : false;
row.forwarded = this.env.messages[uid].forwarded ? true : false;
}
// set eventhandler to message icon
if (row.icon = row.obj.getElementsByTagName('TD')[0].getElementsByTagName('IMG')[0])
{
var p = this;
row.icon.id = 'msgicn_'+row.uid;
row.icon._row = row.obj;
row.icon.onmousedown = function(e) { p.command('toggle_status', this); };
}
// global variable 'flagged_col' may be not defined yet
if (!this.env.flagged_col && this.env.coltypes)
{
var found;
if((found = find_in_array('flag', this.env.coltypes)) >= 0)
this.set_env('flagged_col', found+1);
}
// set eventhandler to flag icon, if icon found
if (this.env.flagged_col && (row.flagged_icon = row.obj.getElementsByTagName('TD')[this.env.flagged_col].getElementsByTagName('IMG')[0]))
{
var p = this;
row.flagged_icon.id = 'flaggedicn_'+row.uid;
row.flagged_icon._row = row.obj;
row.flagged_icon.onmousedown = function(e) { p.command('toggle_flag', this); };
}
};
// init message compose form: set focus and eventhandlers
this.init_messageform = function()
{
if (!this.gui_objects.messageform)
return false;
//this.messageform = this.gui_objects.messageform;
var input_from = $("[name='_from']");
var input_to = $("[name='_to']");
var input_subject = $("input[name='_subject']");
var input_message = $("[name='_message']").get(0);
// init live search events
this.init_address_input_events(input_to);
this.init_address_input_events($("[name='_cc']"));
this.init_address_input_events($("[name='_bcc']"));
// add signature according to selected identity
if (input_from.attr('type') == 'select-one' && $("input[name='_draft_saveid']").val() == ''
&& $("input[name='_is_html']").val() != '1') { // if we have HTML editor, signature is added in callback
this.change_identity(input_from[0]);
}
if (input_to.val() == '')
input_to.focus();
else if (input_subject.val() == '')
input_subject.focus();
else if (input_message)
this.set_caret2start(input_message);
// get summary of all field values
this.compose_field_hash(true);
// start the auto-save timer
this.auto_save_start();
};
this.init_address_input_events = function(obj)
{
var handler = function(e){ return ref.ksearch_keypress(e,this); };
obj.bind((bw.safari ? 'keydown' : 'keypress'), handler);
obj.attr('autocomplete', 'off');
};
/*********************************************************/
/********* client command interface *********/
/*********************************************************/
// execute a specific command on the web client
this.command = function(command, props, obj)
{
if (obj && obj.blur)
obj.blur();
if (this.busy)
return false;
// command not supported or allowed
if (!this.commands[command])
{
// pass command to parent window
if (this.env.framed && parent.rcmail && parent.rcmail.command)
parent.rcmail.command(command, props);
return false;
}
// check input before leaving compose step
if (this.task=='mail' && this.env.action=='compose' && (command=='list' || command=='mail' || command=='addressbook' || command=='settings'))
{
if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
return false;
}
// process external commands
if (typeof this.command_handlers[command] == 'function')
{
var ret = this.command_handlers[command](props, obj);
return ret !== null ? ret : (obj ? false : true);
}
else if (typeof this.command_handlers[command] == 'string')
{
var ret = window[this.command_handlers[command]](props, obj);
return ret !== null ? ret : (obj ? false : true);
}
// trigger plugin hook
var event_ret = this.triggerEvent('before'+command, props);
if (typeof event_ret != 'undefined') {
// abort if one the handlers returned false
if (event_ret === false)
return false;
else
props = event_ret;
}
// process internal command
switch (command)
{
case 'login':
if (this.gui_objects.loginform)
this.gui_objects.loginform.submit();
break;
case 'logout':
this.goto_url('logout', '', true);
break;
// commands to switch task
case 'mail':
case 'addressbook':
case 'settings':
this.switch_task(command);
break;
case 'permaurl':
if (obj && obj.href && obj.target)
return true;
else if (this.env.permaurl)
parent.location.href = this.env.permaurl;
break;
// misc list commands
case 'list':
if (this.task=='mail')
{
if (this.env.search_request<0 || (props != '' && (this.env.search_request && props != this.env.mailbox)))
this.reset_qsearch();
this.list_mailbox(props);
if (this.env.trash_mailbox)
this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage');
}
else if (this.task=='addressbook')
{
if (this.env.search_request<0 || (this.env.search_request && props != this.env.source))
this.reset_qsearch();
this.list_contacts(props);
this.enable_command('add', (this.env.address_sources && !this.env.address_sources[props].readonly));
}
break;
case 'load-headers':
this.load_headers(obj);
break;
case 'sort':
// get the type of sorting
var a_sort = props.split('_');
var sort_col = a_sort[0];
var sort_order = a_sort[1] ? a_sort[1].toUpperCase() : null;
// no sort order specified: toggle
if (sort_order==null)
{
if (this.env.sort_col==sort_col)
sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC';
else
sort_order = this.env.sort_order;
}
if (this.env.sort_col==sort_col && this.env.sort_order==sort_order)
break;
// set table header class
$('#rcm'+this.env.sort_col).removeClass('sorted'+(this.env.sort_order.toUpperCase()));
$('#rcm'+sort_col).addClass('sorted'+sort_order);
// save new sort properties
this.env.sort_col = sort_col;
this.env.sort_order = sort_order;
// reload message list
this.list_mailbox('', '', sort_col+'_'+sort_order);
break;
case 'nextpage':
this.list_page('next');
break;
case 'lastpage':
this.list_page('last');
break;
case 'previouspage':
this.list_page('prev');
break;
case 'firstpage':
this.list_page('first');
break;
case 'expunge':
if (this.env.messagecount)
this.expunge_mailbox(this.env.mailbox);
break;
case 'purge':
case 'empty-mailbox':
if (this.env.messagecount)
this.purge_mailbox(this.env.mailbox);
break;
// common commands used in multiple tasks
case 'show':
if (this.task=='mail')
{
var uid = this.get_single_uid();
if (uid && (!this.env.uid || uid != this.env.uid))
{
if (this.env.mailbox == this.env.drafts_mailbox)
this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
else
this.show_message(uid);
}
}
else if (this.task=='addressbook')
{
var cid = props ? props : this.get_single_cid();
if (cid && !(this.env.action=='show' && cid==this.env.cid))
this.load_contact(cid, 'show');
}
break;
case 'add':
if (this.task=='addressbook')
this.load_contact(0, 'add');
else if (this.task=='settings')
{
this.identity_list.clear_selection();
this.load_identity(0, 'add-identity');
}
break;
case 'edit':
var cid;
if (this.task=='addressbook' && (cid = this.get_single_cid()))
this.load_contact(cid, 'edit');
else if (this.task=='settings' && props)
this.load_identity(props, 'edit-identity');
break;
case 'save-identity':
case 'save':
if (this.gui_objects.editform)
{
var input_pagesize = $("input[name='_pagesize']");
var input_name = $("input[name='_name']");
var input_email = $("input[name='_email']");
// user prefs
if (input_pagesize.length && isNaN(parseInt(input_pagesize.val())))
{
alert(this.get_label('nopagesizewarning'));
input_pagesize.focus();
break;
}
// contacts/identities
else
{
if (input_name.length && input_name.val() == '')
{
alert(this.get_label('nonamewarning'));
input_name.focus();
break;
}
else if (input_email.length && !rcube_check_email(input_email.val()))
{
alert(this.get_label('noemailwarning'));
input_email.focus();
break;
}
}
this.gui_objects.editform.submit();
}
break;
case 'delete':
// mail task
if (this.task=='mail')
this.delete_messages();
// addressbook task
else if (this.task=='addressbook')
this.delete_contacts();
// user settings task
else if (this.task=='settings')
this.delete_identity();
break;
// mail task commands
case 'move':
case 'moveto':
if (this.task == 'mail')
this.move_messages(props);
else if (this.task == 'addressbook' && this.drag_active)
this.copy_contact(null, props);
break;
case 'mark':
if (props)
this.mark_message(props);
break;
case 'toggle_status':
if (props && !props._row)
break;
var uid;
var flag = 'read';
if (props._row.uid)
{
uid = props._row.uid;
// toggle read/unread
if (this.message_list.rows[uid].deleted) {
flag = 'undelete';
} else if (!this.message_list.rows[uid].unread)
flag = 'unread';
}
this.mark_message(flag, uid);
break;
case 'toggle_flag':
if (props && !props._row)
break;
var uid;
var flag = 'flagged';
if (props._row.uid)
{
uid = props._row.uid;
// toggle flagged/unflagged
if (this.message_list.rows[uid].flagged)
flag = 'unflagged';
}
this.mark_message(flag, uid);
break;
case 'always-load':
if (this.env.uid && this.env.sender) {
this.add_contact(urlencode(this.env.sender));
window.setTimeout(function(){ ref.command('load-images'); }, 300);
break;
}
case 'load-images':
if (this.env.uid)
this.show_message(this.env.uid, true, this.env.action=='preview');
break;
case 'load-attachment':
var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part;
// open attachment in frame if it's of a supported mimetype
if (this.env.uid && props.mimetype && find_in_array(props.mimetype, this.mimetypes)>=0)
{
if (props.mimetype == 'text/html')
qstring += '&_safe=1';
this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment');
if (this.attachment_win)
{
window.setTimeout(function(){ ref.attachment_win.focus(); }, 10);
break;
}
}
this.goto_url('get', qstring+'&_download=1', false);
break;
case 'select-all':
this.message_list.select_all(props);
break;
case 'select-none':
this.message_list.clear_selection();
break;
case 'nextmessage':
if (this.env.next_uid)
this.show_message(this.env.next_uid, false, this.env.action=='preview');
break;
case 'lastmessage':
if (this.env.last_uid)
this.show_message(this.env.last_uid);
break;
case 'previousmessage':
if (this.env.prev_uid)
this.show_message(this.env.prev_uid, false, this.env.action=='preview');
break;
case 'firstmessage':
if (this.env.first_uid)
this.show_message(this.env.first_uid);
break;
case 'checkmail':
this.check_for_recent(true);
break;
case 'compose':
var url = this.env.comm_path+'&_action=compose';
if (this.task=='mail')
{
url += '&_mbox='+urlencode(this.env.mailbox);
if (this.env.mailbox==this.env.drafts_mailbox)
{
var uid;
if (uid = this.get_single_uid())
url += '&_draft_uid='+uid;
}
else if (props)
url += '&_to='+urlencode(props);
}
// modify url if we're in addressbook
else if (this.task=='addressbook')
{
// switch to mail compose step directly
if (props && props.indexOf('@') > 0)
{
url = this.get_task_url('mail', url);
this.redirect(url + '&_to='+urlencode(props));
break;
}
// use contact_id passed as command parameter
var a_cids = new Array();
if (props)
a_cids[a_cids.length] = props;
// get selected contacts
else if (this.contact_list)
{
var selection = this.contact_list.get_selection();
for (var n=0; n<selection.length; n++)
a_cids[a_cids.length] = selection[n];
}
if (a_cids.length)
this.http_request('mailto', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source), true);
break;
}
// don't know if this is necessary...
url = url.replace(/&_framed=1/, "");
this.redirect(url);
break;
case 'spellcheck':
if (window.tinyMCE && tinyMCE.get('compose-body')) {
tinyMCE.execCommand('mceSpellCheck', true);
}
else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) {
this.env.spellcheck.spellCheck(this.env.spellcheck.check_link);
this.set_spellcheck_state('checking');
}
break;
case 'savedraft':
// Reset the auto-save timer
self.clearTimeout(this.save_timer);
if (!this.gui_objects.messageform)
break;
// if saving Drafts is disabled in main.inc.php
// or if compose form did not change
if (!this.env.drafts_mailbox || this.cmp_hash == this.compose_field_hash())
break;
this.set_busy(true, 'savingmessage');
var form = this.gui_objects.messageform;
form.target = "savetarget";
form._draft.value = '1';
form.submit();
break;
case 'send':
if (!this.gui_objects.messageform)
break;
if (!this.check_compose_input())
break;
// Reset the auto-save timer
self.clearTimeout(this.save_timer);
// all checks passed, send message
this.set_busy(true, 'sendingmessage');
var form = this.gui_objects.messageform;
form.target = "savetarget";
form._draft.value = '';
form.submit();
// clear timeout (sending could take longer)
clearTimeout(this.request_timer);
break;
case 'add-attachment':
this.show_attachment_form(true);
case 'send-attachment':
// Reset the auto-save timer
self.clearTimeout(this.save_timer);
this.upload_file(props)
break;
case 'remove-attachment':
this.remove_attachment(props);
break;
case 'reply-all':
case 'reply':
var uid;
if (uid = this.get_single_uid())
this.goto_url('compose', '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : ''), true);
break;
case 'forward':
var uid;
if (uid = this.get_single_uid())
this.goto_url('compose', '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
break;
case 'print':
var uid;
if (uid = this.get_single_uid())
{
ref.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
if (this.printwin)
{
window.setTimeout(function(){ ref.printwin.focus(); }, 20);
if (this.env.action != 'show')
this.mark_message('read', uid);
}
}
break;
case 'viewsource':
var uid;
if (uid = this.get_single_uid())
{
ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox));
if (this.sourcewin)
window.setTimeout(function(){ ref.sourcewin.focus(); }, 20);
}
break;
case 'add-contact':
this.add_contact(props);
break;
// quicksearch
case 'search':
if (!props && this.gui_objects.qsearchbox)
props = this.gui_objects.qsearchbox.value;
if (props)
{
this.qsearch(props);
break;
}
// reset quicksearch
case 'reset-search':
var s = this.env.search_request;
this.reset_qsearch();
if (s && this.env.mailbox)
this.list_mailbox(this.env.mailbox);
else if (s && this.task == 'addressbook')
this.list_contacts(this.env.source);
break;
case 'import':
if (this.env.action == 'import' && this.gui_objects.importform) {
var file = document.getElementById('rcmimportfile');
if (file && !file.value) {
alert(this.get_label('selectimportfile'));
break;
}
this.gui_objects.importform.submit();
this.set_busy(true, 'importwait');
this.lock_form(this.gui_objects.importform, true);
}
else
this.goto_url('import');
break;
case 'export':
if (this.contact_list.rowcount > 0) {
var add_url = (this.env.source ? '_source='+urlencode(this.env.source)+'&' : '');
if (this.env.search_request)
add_url += '_search='+this.env.search_request;
this.goto_url('export', add_url);
}
break;
// collapse/expand folder
case 'collapse-folder':
if (props)
this.collapse_folder(props);
break;
// user settings commands
case 'preferences':
this.goto_url('');
break;
case 'identities':
this.goto_url('identities');
break;
case 'delete-identity':
this.delete_identity();
case 'folders':
this.goto_url('folders');
break;
case 'subscribe':
this.subscribe_folder(props);
break;
case 'unsubscribe':
this.unsubscribe_folder(props);
break;
case 'create-folder':
this.create_folder(props);
break;
case 'rename-folder':
this.rename_folder(props);
break;
case 'delete-folder':
this.delete_folder(props);
break;
}
this.triggerEvent('after'+command, props);
return obj ? false : true;
};
// set command enabled or disabled
this.enable_command = function()
{
var args = arguments;
if(!args.length) return -1;
var command;
var enable = args[args.length-1];
for(var n=0; n<args.length-1; n++)
{
command = args[n];
this.commands[command] = enable;
this.set_button(command, (enable ? 'act' : 'pas'));
}
return true;
};
// lock/unlock interface
this.set_busy = function(a, message)
{
if (a && message)
{
var msg = this.get_label(message);
if (msg==message)
msg = 'Loading...';
this.display_message(msg, 'loading', true);
}
else if (!a)
this.hide_message();
this.busy = a;
//document.body.style.cursor = a ? 'wait' : 'default';
if (this.gui_objects.editform)
this.lock_form(this.gui_objects.editform, a);
// clear pending timer
if (this.request_timer)
clearTimeout(this.request_timer);
// set timer for requests
if (a && this.env.request_timeout)
this.request_timer = window.setTimeout(function(){ ref.request_timed_out(); }, this.env.request_timeout * 1000);
};
// return a localized string
this.get_label = function(name, domain)
{
if (domain && this.labels[domain+'.'+name])
return this.labels[domain+'.'+name];
else if (this.labels[name])
return this.labels[name];
else
return name;
};
// alias for convenience reasons
this.gettext = this.get_label;
// switch to another application task
this.switch_task = function(task)
{
if (this.task===task && task!='mail')
return;
var url = this.get_task_url(task);
if (task=='mail')
url += '&_mbox=INBOX';
this.redirect(url);
};
this.get_task_url = function(task, url)
{
if (!url)
url = this.env.comm_path;
return url.replace(/_task=[a-z]+/, '_task='+task);
};
// called when a request timed out
this.request_timed_out = function()
{
this.set_busy(false);
this.display_message('Request timed out!', 'error');
};
/*********************************************************/
/********* event handling methods *********/
/*********************************************************/
this.doc_mouse_up = function(e)
{
var model, list, li;
if (this.message_list) {
if (!rcube_mouse_is_over(e, this.message_list.list))
this.message_list.blur();
list = this.message_list;
model = this.env.mailboxes;
}
else if (this.contact_list) {
if (!rcube_mouse_is_over(e, this.contact_list.list))
this.contact_list.blur();
list = this.contact_list;
model = this.env.address_sources;
}
else if (this.ksearch_value) {
this.ksearch_blur();
}
// handle mouse release when dragging
if (this.drag_active && model && this.env.last_folder_target) {
$(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget');
this.command('moveto', model[this.env.last_folder_target].id);
this.env.last_folder_target = null;
list.draglayer.hide();
}
};
this.drag_start = function(list)
{
var model = this.task == 'mail' ? this.env.mailboxes : this.env.address_sources;
this.drag_active = true;
if (this.preview_timer)
clearTimeout(this.preview_timer);
// save folderlist and folders location/sizes for droptarget calculation in drag_move()
if (this.gui_objects.folderlist && model)
{
this.initialBodyScrollTop = bw.ie ? 0 : window.pageYOffset;
this.initialListScrollTop = this.gui_objects.folderlist.parentNode.scrollTop;
var li, pos, list, height;
list = $(this.gui_objects.folderlist);
pos = list.offset();
this.env.folderlist_coords = { x1:pos.left, y1:pos.top, x2:pos.left + list.width(), y2:pos.top + list.height() };
this.env.folder_coords = new Array();
for (var k in model) {
if (li = this.get_folder_li(k)) {
pos = $(li.firstChild).offset();
// only visible folders
if (height = li.firstChild.offsetHeight)
this.env.folder_coords[k] = { x1:pos.left, y1:pos.top, x2:pos.left + li.firstChild.offsetWidth, y2:pos.top + height };
}
}
}
};
this.drag_move = function(e)
{
if (this.gui_objects.folderlist && this.env.folder_coords) {
// offsets to compensate for scrolling while dragging a message
var boffset = bw.ie ? -document.documentElement.scrollTop : this.initialBodyScrollTop;
var moffset = this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop;
var toffset = -moffset-boffset;
var li, pos, mouse;
mouse = rcube_event.get_mouse_pos(e);
pos = this.env.folderlist_coords;
mouse.y += toffset;
// if mouse pointer is outside of folderlist
if (mouse.x < pos.x1 || mouse.x >= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) {
if (this.env.last_folder_target) {
$(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget');
this.env.last_folder_target = null;
}
return;
}
// over the folders
for (var k in this.env.folder_coords) {
pos = this.env.folder_coords[k];
if (this.check_droptarget(k) && ((mouse.x >= pos.x1) && (mouse.x < pos.x2)
&& (mouse.y >= pos.y1) && (mouse.y < pos.y2))) {
$(this.get_folder_li(k)).addClass('droptarget');
this.env.last_folder_target = k;
}
else {
$(this.get_folder_li(k)).removeClass('droptarget');
if (k == this.env.last_folder_target)
this.env.last_folder_target = null;
}
}
}
};
this.collapse_folder = function(id)
{
var div;
if ((li = this.get_folder_li(id)) &&
(div = $(li.getElementsByTagName("div")[0])) &&
(div.hasClass('collapsed') || div.hasClass('expanded')))
{
var ul = $(li.getElementsByTagName("ul")[0]);
if (div.hasClass('collapsed'))
{
ul.show();
div.removeClass('collapsed').addClass('expanded');
var reg = new RegExp('&'+urlencode(id)+'&');
this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, ''));
}
else
{
ul.hide();
div.removeClass('expanded').addClass('collapsed');
this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+urlencode(id)+'&');
// select parent folder if one of its childs is currently selected
if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0)
this.command('list', id);
}
// Work around a bug in IE6 and IE7, see #1485309
if ((bw.ie6 || bw.ie7) &&
li.nextSibling &&
(li.nextSibling.getElementsByTagName("ul").length>0) &&
li.nextSibling.getElementsByTagName("ul")[0].style &&
(li.nextSibling.getElementsByTagName("ul")[0].style.display!='none'))
{
li.nextSibling.getElementsByTagName("ul")[0].style.display = 'none';
li.nextSibling.getElementsByTagName("ul")[0].style.display = '';
}
this.http_post('save-pref', '_name=collapsed_folders&_value='+urlencode(this.env.collapsed_folders));
this.set_unread_count_display(id, false);
}
}
this.click_on_list = function(e)
{
if (this.gui_objects.qsearchbox)
this.gui_objects.qsearchbox.blur();
if (this.message_list)
this.message_list.focus();
else if (this.contact_list)
this.contact_list.focus();
return rcube_event.get_button(e) == 2 ? true : rcube_event.cancel(e);
};
this.msglist_select = function(list)
{
if (this.preview_timer)
clearTimeout(this.preview_timer);
var selected = list.selection.length==1;
// Hide certain command buttons when Drafts folder is selected
if (this.env.mailbox == this.env.drafts_mailbox)
{
this.enable_command('reply', 'reply-all', 'forward', false);
this.enable_command('show', 'print', selected);
this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
}
else
{
this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false));
}
// start timer for message preview (wait for double click)
if (selected && this.env.contentframe && !list.multi_selecting)
this.preview_timer = window.setTimeout(function(){ ref.msglist_get_preview(); }, 200);
else if (this.env.contentframe)
this.show_contentframe(false);
};
this.msglist_dbl_click = function(list)
{
if (this.preview_timer)
clearTimeout(this.preview_timer);
var uid = list.get_single_selection();
if (uid && this.env.mailbox == this.env.drafts_mailbox)
this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
else if (uid)
this.show_message(uid, false, false);
};
this.msglist_keypress = function(list)
{
if (list.key_pressed == list.ENTER_KEY)
this.command('show');
else if (list.key_pressed == list.DELETE_KEY)
this.command('delete');
else if (list.key_pressed == list.BACKSPACE_KEY)
this.command('delete');
else
list.shiftkey = false;
};
this.msglist_get_preview = function()
{
var uid = this.get_single_uid();
if (uid && this.env.contentframe && !this.drag_active)
this.show_message(uid, false, true);
else if (this.env.contentframe)
this.show_contentframe(false);
};
this.check_droptarget = function(id)
{
if (this.task == 'mail')
return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual);
else if (this.task == 'addressbook')
return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly);
else if (this.task == 'settings')
return (id != this.env.folder);
};
/*********************************************************/
/********* (message) list functionality *********/
/*********************************************************/
// when user doble-clicks on a row
this.show_message = function(id, safe, preview)
{
if (!id) return;
var add_url = '';
var action = preview ? 'preview': 'show';
var target = window;
if (preview && this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url = '&_framed=1';
}
if (safe)
add_url = '&_safe=1';
// also send search request to get the right messages
if (this.env.search_request)
add_url += '&_search='+this.env.search_request;
var url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url;
if (action == 'preview' && String(target.location.href).indexOf(url) >= 0)
this.show_contentframe(true);
else
{
this.set_busy(true, 'loading');
target.location.href = this.env.comm_path+url;
// mark as read and change mbox unread counter
if (action == 'preview' && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread)
{
this.set_message(id, 'unread', false);
if (this.env.unread_counts[this.env.mailbox])
{
this.env.unread_counts[this.env.mailbox] -= 1;
this.set_unread_count(this.env.mailbox, this.env.unread_counts[this.env.mailbox], this.env.mailbox == 'INBOX');
}
}
}
};
this.show_contentframe = function(show)
{
var frm;
if (this.env.contentframe && (frm = $('#'+this.env.contentframe)) && frm.length)
{
if (!show && window.frames[this.env.contentframe])
{
if (window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0)
window.frames[this.env.contentframe].location.href = this.env.blankpage;
}
else if (!bw.safari && !bw.konq)
frm[show ? 'show' : 'hide']();
}
if (!show && this.busy)
this.set_busy(false);
};
// list a specific page
this.list_page = function(page)
{
if (page=='next')
page = this.env.current_page+1;
if (page=='last')
page = this.env.pagecount;
if (page=='prev' && this.env.current_page>1)
page = this.env.current_page-1;
if (page=='first' && this.env.current_page>1)
page = 1;
if (page > 0 && page <= this.env.pagecount)
{
this.env.current_page = page;
if (this.task=='mail')
this.list_mailbox(this.env.mailbox, page);
else if (this.task=='addressbook')
this.list_contacts(this.env.source, page);
}
};
// list messages of a specific mailbox using filter
this.filter_mailbox = function(filter)
{
var search;
if (this.gui_objects.qsearchbox)
search = this.gui_objects.qsearchbox.value;
this.message_list.clear();
// reset vars
this.env.current_page = 1;
this.set_busy(true, 'searching');
this.http_request('search', '_filter='+filter
+ (search ? '&_q='+urlencode(search) : '')
+ (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), true);
}
// list messages of a specific mailbox
this.list_mailbox = function(mbox, page, sort)
{
this.last_selected = 0;
var add_url = '';
var target = window;
if (!mbox)
mbox = this.env.mailbox;
// add sort to url if set
if (sort)
add_url += '&_sort=' + sort;
// also send search request to get the right messages
if (this.env.search_request)
add_url += '&_search='+this.env.search_request;
// set page=1 if changeing to another mailbox
if (!page && mbox != this.env.mailbox)
{
page = 1;
this.env.current_page = page;
if (this.message_list)
this.message_list.clear_selection();
this.show_contentframe(false);
}
if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort))
add_url += '&_refresh=1';
this.select_folder(mbox, this.env.mailbox);
this.env.mailbox = mbox;
// load message list remotely
if (this.gui_objects.messagelist)
{
this.list_mailbox_remote(mbox, page, add_url);
return;
}
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url += '&_framed=1';
}
// load message list to target frame/window
if (mbox)
{
this.set_busy(true, 'loading');
target.location.href = this.env.comm_path+'&_mbox='+urlencode(mbox)+(page ? '&_page='+page : '')+add_url;
}
};
// send remote request to load message list
this.list_mailbox_remote = function(mbox, page, add_url)
{
// clear message list first
this.message_list.clear();
// send request to server
var url = '_mbox='+urlencode(mbox)+(page ? '&_page='+page : '');
this.set_busy(true, 'loading');
this.http_request('list', url+add_url, true);
};
this.expunge_mailbox = function(mbox)
{
var lock = false;
var add_url = '';
// lock interface if it's the active mailbox
if (mbox == this.env.mailbox)
{
lock = true;
this.set_busy(true, 'loading');
add_url = '&_reload=1';
}
// send request to server
var url = '_mbox='+urlencode(mbox);
this.http_post('expunge', url+add_url, lock);
};
this.purge_mailbox = function(mbox)
{
var lock = false;
var add_url = '';
if (!confirm(this.get_label('purgefolderconfirm')))
return false;
// lock interface if it's the active mailbox
if (mbox == this.env.mailbox)
{
lock = true;
this.set_busy(true, 'loading');
add_url = '&_reload=1';
}
// send request to server
var url = '_mbox='+urlencode(mbox);
this.http_post('purge', url+add_url, lock);
return true;
};
// test if purge command is allowed
this.purge_mailbox_test = function()
{
return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox
|| this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter))
|| this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter))));
};
// set message icon
this.set_message_icon = function(uid)
{
var icn_src;
var rows = this.message_list.rows;
if (!rows[uid])
return false;
if (rows[uid].deleted && this.env.deletedicon)
icn_src = this.env.deletedicon;
else if (rows[uid].replied && this.env.repliedicon)
{
if (rows[uid].forwarded && this.env.forwardedrepliedicon)
icn_src = this.env.forwardedrepliedicon;
else
icn_src = this.env.repliedicon;
}
else if (rows[uid].forwarded && this.env.forwardedicon)
icn_src = this.env.forwardedicon;
else if (rows[uid].unread && this.env.unreadicon)
icn_src = this.env.unreadicon;
else if (this.env.messageicon)
icn_src = this.env.messageicon;
if (icn_src && rows[uid].icon)
rows[uid].icon.src = icn_src;
icn_src = '';
if (rows[uid].flagged && this.env.flaggedicon)
icn_src = this.env.flaggedicon;
else if (!rows[uid].flagged && this.env.unflaggedicon)
icn_src = this.env.unflaggedicon;
if (rows[uid].flagged_icon && icn_src)
rows[uid].flagged_icon.src = icn_src;
}
// set message status
this.set_message_status = function(uid, flag, status)
{
var rows = this.message_list.rows;
if (!rows[uid]) return false;
if (flag == 'unread')
rows[uid].unread = status;
else if(flag == 'deleted')
rows[uid].deleted = status;
else if (flag == 'replied')
rows[uid].replied = status;
else if (flag == 'forwarded')
rows[uid].forwarded = status;
else if (flag == 'flagged')
rows[uid].flagged = status;
this.env.messages[uid] = rows[uid];
}
// set message row status, class and icon
this.set_message = function(uid, flag, status)
{
var rows = this.message_list.rows;
if (!rows[uid]) return false;
if (flag)
this.set_message_status(uid, flag, status);
var rowobj = $(rows[uid].obj);
if (rows[uid].unread && rows[uid].classname.indexOf('unread')<0)
{
rows[uid].classname += ' unread';
rowobj.addClass('unread');
}
else if (!rows[uid].unread && rows[uid].classname.indexOf('unread')>=0)
{
rows[uid].classname = rows[uid].classname.replace(/\s*unread/, '');
rowobj.removeClass('unread');
}
if (rows[uid].deleted && rows[uid].classname.indexOf('deleted')<0)
{
rows[uid].classname += ' deleted';
rowobj.addClass('deleted');
}
else if (!rows[uid].deleted && rows[uid].classname.indexOf('deleted')>=0)
{
rows[uid].classname = rows[uid].classname.replace(/\s*deleted/, '');
rowobj.removeClass('deleted');
}
if (rows[uid].flagged && rows[uid].classname.indexOf('flagged')<0)
{
rows[uid].classname += ' flagged';
rowobj.addClass('flagged');
}
else if (!rows[uid].flagged && rows[uid].classname.indexOf('flagged')>=0)
{
rows[uid].classname = rows[uid].classname.replace(/\s*flagged/, '');
rowobj.removeClass('flagged');
}
this.set_message_icon(uid);
}
// move selected messages to the specified mailbox
this.move_messages = function(mbox)
{
// exit if current or no mailbox specified or if selection is empty
if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length)))
return;
var lock = false;
var add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : '');
// show wait message
if (this.env.action=='show')
{
lock = true;
this.set_busy(true, 'movingmessage');
}
else if (!this.env.flag_for_deletion)
this.show_contentframe(false);
// Hide message command buttons until a message is selected
this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', false);
this._with_selected_messages('moveto', lock, add_url, (this.env.flag_for_deletion ? false : true));
};
// delete selected messages from the current mailbox
this.delete_messages = function()
{
var selection = this.message_list ? this.message_list.get_selection() : new Array();
// exit if no mailbox specified or if selection is empty
if (!this.env.uid && !selection.length)
return;
// if there is a trash mailbox defined and we're not currently in it:
if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() != String(this.env.trash_mailbox).toLowerCase())
{
// if shift was pressed delete it immediately
if (this.message_list && this.message_list.shiftkey)
{
if (confirm(this.get_label('deletemessagesconfirm')))
this.permanently_remove_messages();
}
else
this.move_messages(this.env.trash_mailbox);
}
// if there is a trash mailbox defined but we *are* in it:
else if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() == String(this.env.trash_mailbox).toLowerCase())
this.permanently_remove_messages();
// if there isn't a defined trash mailbox and the config is set to flag for deletion
else if (!this.env.trash_mailbox && this.env.flag_for_deletion)
{
this.mark_message('delete');
if(this.env.action=="show")
this.command('nextmessage','',this);
else if (selection.length == 1)
this.message_list.select_next();
}
// if there isn't a defined trash mailbox and the config is set NOT to flag for deletion
else if (!this.env.trash_mailbox)
this.permanently_remove_messages();
};
// delete the selected messages permanently
this.permanently_remove_messages = function()
{
// exit if no mailbox specified or if selection is empty
if (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))
return;
this.show_contentframe(false);
this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : ''), true);
};
// Send a specifc request with UIDs of all selected messages
// @private
this._with_selected_messages = function(action, lock, add_url, remove)
{
var a_uids = new Array();
if (this.env.uid)
a_uids[0] = this.env.uid;
else
{
var selection = this.message_list.get_selection();
var rows = this.message_list.rows;
var id;
for (var n=0; n<selection.length; n++)
{
id = selection[n];
a_uids[a_uids.length] = id;
if (remove)
this.message_list.remove_row(id, (n == selection.length-1));
else
{
this.set_message_status(id, 'deleted', true);
if (this.env.read_when_deleted)
this.set_message_status(id, 'unread', false);
this.set_message(id);
}
}
}
// also send search request to get the right messages
if (this.env.search_request)
add_url += '&_search='+this.env.search_request;
// send request to server
this.http_post(action, '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+add_url, lock);
};
// set a specific flag to one or more messages
this.mark_message = function(flag, uid)
{
var a_uids = new Array();
var r_uids = new Array();
var selection = this.message_list ? this.message_list.get_selection() : new Array();
if (uid)
a_uids[0] = uid;
else if (this.env.uid)
a_uids[0] = this.env.uid;
else if (this.message_list)
{
for (var n=0; n<selection.length; n++)
{
a_uids[a_uids.length] = selection[n];
}
}
if (!this.message_list)
r_uids = a_uids;
else
for (var id, n=0; n<a_uids.length; n++)
{
id = a_uids[n];
if ((flag=='read' && this.message_list.rows[id].unread)
|| (flag=='unread' && !this.message_list.rows[id].unread)
|| (flag=='delete' && !this.message_list.rows[id].deleted)
|| (flag=='undelete' && this.message_list.rows[id].deleted)
|| (flag=='flagged' && !this.message_list.rows[id].flagged)
|| (flag=='unflagged' && this.message_list.rows[id].flagged))
{
r_uids[r_uids.length] = id;
}
}
// nothing to do
if (!r_uids.length)
return;
switch (flag)
{
case 'read':
case 'unread':
this.toggle_read_status(flag, r_uids);
break;
case 'delete':
case 'undelete':
this.toggle_delete_status(r_uids);
break;
case 'flagged':
case 'unflagged':
this.toggle_flagged_status(flag, a_uids);
break;
}
};
// set class to read/unread
this.toggle_read_status = function(flag, a_uids)
{
// mark all message rows as read/unread
for (var i=0; i<a_uids.length; i++)
this.set_message(a_uids[i], 'unread', (flag=='unread' ? true : false));
this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
};
// set image to flagged or unflagged
this.toggle_flagged_status = function(flag, a_uids)
{
// mark all message rows as flagged/unflagged
for (var i=0; i<a_uids.length; i++)
this.set_message(a_uids[i], 'flagged', (flag=='flagged' ? true : false));
this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
};
// mark all message rows as deleted/undeleted
this.toggle_delete_status = function(a_uids)
{
var rows = this.message_list ? this.message_list.rows : new Array();
if (a_uids.length==1)
{
if (!rows.length || (rows[a_uids[0]] && !rows[a_uids[0]].deleted))
this.flag_as_deleted(a_uids);
else
this.flag_as_undeleted(a_uids);
return true;
}
var all_deleted = true;
for (var i=0; i<a_uids.length; i++)
{
uid = a_uids[i];
if (rows[uid]) {
if (!rows[uid].deleted)
{
all_deleted = false;
break;
}
}
}
if (all_deleted)
this.flag_as_undeleted(a_uids);
else
this.flag_as_deleted(a_uids);
return true;
};
this.flag_as_undeleted = function(a_uids)
{
for (var i=0; i<a_uids.length; i++)
this.set_message(a_uids[i], 'deleted', false);
this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=undelete');
return true;
};
this.flag_as_deleted = function(a_uids)
{
var add_url = '';
var r_uids = new Array();
var rows = this.message_list ? this.message_list.rows : new Array();
for (var i=0; i<a_uids.length; i++)
{
uid = a_uids[i];
if (rows[uid])
{
this.set_message(uid, 'deleted', true);
if (rows[uid].unread)
r_uids[r_uids.length] = uid;
}
}
if (r_uids.length)
add_url = '&_ruid='+r_uids.join(',');
this.http_post('mark', '_uid='+a_uids.join(',')+'&_flag=delete'+add_url);
return true;
};
// flag as read without mark request (called from backend)
// argument should be a coma-separated list of uids
this.flag_deleted_as_read = function(uids)
{
var icn_src;
var rows = this.message_list ? this.message_list.rows : new Array();
var str = String(uids);
var a_uids = new Array();
a_uids = str.split(',');
for (var uid, i=0; i<a_uids.length; i++)
{
uid = a_uids[i];
if (rows[uid])
this.set_message(uid, 'unread', false);
}
};
/*********************************************************/
/********* login form methods *********/
/*********************************************************/
// handler for keyboard events on the _user field
this.login_user_keyup = function(e)
{
var key = rcube_event.get_keycode(e);
var passwd = $('#rcmloginpwd');
// enter
if (key == 13 && passwd.length && !passwd.val()) {
passwd.focus();
return rcube_event.cancel(e);
}
return true;
};
/*********************************************************/
/********* message compose methods *********/
/*********************************************************/
// checks the input fields before sending a message
this.check_compose_input = function()
{
// check input fields
var input_to = $("[name='_to']");
var input_cc = $("[name='_cc']");
var input_bcc = $("[name='_bcc']");
var input_from = $("[name='_from']");
var input_subject = $("[name='_subject']");
var input_message = $("[name='_message']");
// check sender (if have no identities)
if (input_from.attr('type') == 'text' && !rcube_check_email(input_from.val(), true))
{
alert(this.get_label('nosenderwarning'));
input_from.focus();
return false;
}
// check for empty recipient
var recipients = input_to.val() ? input_to.val() : (input_cc.val() ? input_cc.val() : input_bcc.val());
if (!rcube_check_email(recipients.replace(/^\s+/, '').replace(/[\s,;]+$/, ''), true))
{
alert(this.get_label('norecipientwarning'));
input_to.focus();
return false;
}
// display localized warning for missing subject
if (input_subject.val() == '')
{
var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject'));
// user hit cancel, so don't send
if (!subject && subject !== '')
{
input_subject.focus();
return false;
}
else
{
input_subject.val((subject ? subject : this.get_label('nosubject')));
}
}
// check for empty body
if ((!window.tinyMCE || !tinyMCE.get('compose-body')) && input_message.val() == '' && !confirm(this.get_label('nobodywarning')))
{
input_message.focus();
return false;
}
else if (window.tinyMCE && tinyMCE.get('compose-body') && !tinyMCE.get('compose-body').getContent() && !confirm(this.get_label('nobodywarning')))
{
tinyMCE.get('compose-body').focus();
return false;
}
// Apply spellcheck changes if spell checker is active
this.stop_spellchecking();
return true;
};
this.stop_spellchecking = function()
{
if (this.env.spellcheck && !this.spellcheck_ready) {
exec_event(this.env.spellcheck.check_link, 'click');
this.set_spellcheck_state('ready');
}
};
this.display_spellcheck_controls = function(vis)
{
if (this.env.spellcheck) {
// stop spellchecking process
if (!vis)
this.stop_spellchecking();
this.env.spellcheck.check_link.style.visibility = vis ? 'visible' : 'hidden';
this.env.spellcheck.switch_lan_pic.style.visibility = vis ? 'visible' : 'hidden';
}
};
this.set_spellcheck_state = function(s)
{
this.spellcheck_ready = (s=='check_spelling' || s=='ready');
this.enable_command('spellcheck', this.spellcheck_ready);
};
this.set_draft_id = function(id)
{
$("input[name='_draft_saveid']").val(id);
};
this.auto_save_start = function()
{
if (this.env.draft_autosave)
this.save_timer = self.setTimeout(function(){ ref.command("savedraft"); }, this.env.draft_autosave * 1000);
// Unlock interface now that saving is complete
this.busy = false;
};
this.compose_field_hash = function(save)
{
// check input fields
var value_to = $("[name='_to']").val();
var value_cc = $("[name='_cc']").val();
var value_bcc = $("[name='_bcc']").val();
var value_subject = $("[name='_subject']").val();
var str = '';
if (value_to)
str += value_to+':';
if (value_cc)
str += value_cc+':';
if (value_bcc)
str += value_bcc+':';
if (value_subject)
str += value_subject+':';
var editor = tinyMCE.get('compose-body');
if (editor)
str += editor.getContent();
else
str += $("[name='_message']").val();
if (save)
this.cmp_hash = str;
return str;
};
this.change_identity = function(obj)
{
if (!obj || !obj.options)
return false;
var id = obj.options[obj.selectedIndex].value;
var input_message = $("[name='_message']");
var message = input_message.val();
var is_html = ($("input[name='_is_html']").val() == '1');
var sig, p;
if (!this.env.identity)
this.env.identity = id
if (!is_html)
{
// remove the 'old' signature
if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
{
if (this.env.signatures[this.env.identity]['is_html'])
sig = this.env.signatures[this.env.identity]['plain_text'];
else
sig = this.env.signatures[this.env.identity]['text'];
if (sig.indexOf('-- ')!=0)
sig = '-- \n'+sig;
p = message.lastIndexOf(sig);
if (p>=0)
message = message.substring(0, p-1) + message.substring(p+sig.length, message.length);
}
message = message.replace(/[\r\n]+$/, '');
// add the new signature string
if (this.env.signatures && this.env.signatures[id])
{
sig = this.env.signatures[id]['text'];
if (this.env.signatures[id]['is_html'])
{
sig = this.env.signatures[id]['plain_text'];
}
if (sig.indexOf('-- ')!=0)
sig = '-- \n'+sig;
message += '\n\n'+sig;
}
}
else
{
var editor = tinyMCE.get('compose-body');
if (this.env.signatures)
{
// Append the signature as a div within the body
var sigElem = editor.dom.get('_rc_sig');
var newsig = '';
var htmlsig = true;
if (!sigElem)
{
// add empty line before signature on IE
if (bw.ie)
editor.getBody().appendChild(editor.getDoc().createElement('br'));
sigElem = editor.getDoc().createElement('div');
sigElem.setAttribute('id', '_rc_sig');
editor.getBody().appendChild(sigElem);
}
if (this.env.signatures[id])
{
newsig = this.env.signatures[id]['text'];
htmlsig = this.env.signatures[id]['is_html'];
if (newsig) {
if (htmlsig && this.env.signatures[id]['plain_text'].indexOf('-- ')!=0)
newsig = '<p>-- </p>' + newsig;
else if (!htmlsig && newsig.indexOf('-- ')!=0)
newsig = '-- \n' + newsig;
}
}
if (htmlsig)
sigElem.innerHTML = newsig;
else
sigElem.innerHTML = '<pre>' + newsig + '</pre>';
}
}
input_message.val(message);
this.env.identity = id;
return true;
};
this.show_attachment_form = function(a)
{
if (!this.gui_objects.uploadbox)
return false;
var elm, list;
if (elm = this.gui_objects.uploadbox)
{
if (a && (list = this.gui_objects.attachmentlist))
{
var pos = $(list).offset();
elm.style.top = (pos.top + list.offsetHeight + 10) + 'px';
elm.style.left = pos.left + 'px';
}
elm.style.visibility = a ? 'visible' : 'hidden';
}
// clear upload form
try {
if (!a && this.gui_objects.attachmentform != this.gui_objects.messageform)
this.gui_objects.attachmentform.reset();
}
catch(e){} // ignore errors
return true;
};
// upload attachment file
this.upload_file = function(form)
{
if (!form)
return false;
// get file input fields
var send = false;
for (var n=0; n<form.elements.length; n++)
if (form.elements[n].type=='file' && form.elements[n].value)
{
send = true;
break;
}
// create hidden iframe and post upload form
if (send)
{
var ts = new Date().getTime();
var frame_name = 'rcmupload'+ts;
// have to do it this way for IE
// otherwise the form will be posted to a new window
if(document.all)
{
var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
document.body.insertAdjacentHTML('BeforeEnd',html);
}
else // for standards-compilant browsers
{
var frame = document.createElement('IFRAME');
frame.name = frame_name;
frame.style.border = 'none';
frame.style.width = 0;
frame.style.height = 0;
frame.style.visibility = 'hidden';
document.body.appendChild(frame);
}
form.target = frame_name;
form.action = this.env.comm_path+'&_action=upload';
form.setAttribute('enctype', 'multipart/form-data');
form.submit();
}
// set reference to the form object
this.gui_objects.attachmentform = form;
return true;
};
// add file name to attachment list
// called from upload page
this.add2attachment_list = function(name, content)
{
if (!this.gui_objects.attachmentlist)
return false;
$('<li>').attr('id', name).html(content).appendTo(this.gui_objects.attachmentlist);
return true;
};
this.remove_from_attachment_list = function(name)
{
if (!this.gui_objects.attachmentlist)
return false;
var list = this.gui_objects.attachmentlist.getElementsByTagName("li");
for (i=0;i<list.length;i++)
if (list[i].id == name)
this.gui_objects.attachmentlist.removeChild(list[i]);
};
this.remove_attachment = function(name)
{
if (name)
this.http_post('remove-attachment', '_file='+urlencode(name));
return true;
};
// send remote request to add a new contact
this.add_contact = function(value)
{
if (value)
this.http_post('addcontact', '_address='+value);
return true;
};
// send remote request to search mail or contacts
this.qsearch = function(value, addurl)
{
if (value != '')
{
if (this.message_list)
this.message_list.clear();
else if (this.contact_list) {
this.contact_list.clear(true);
this.show_contentframe(false);
}
if (this.gui_objects.search_filter)
addurl = '&_filter=' + this.gui_objects.search_filter.value;
// reset vars
this.env.current_page = 1;
this.set_busy(true, 'searching');
this.http_request('search', '_q='+urlencode(value)
+ (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : '')
+ (this.env.source ? '&_source='+urlencode(this.env.source) : '')
+ (addurl ? addurl : ''), true);
}
return true;
};
// reset quick-search form
this.reset_qsearch = function()
{
if (this.gui_objects.qsearchbox)
this.gui_objects.qsearchbox.value = '';
this.env.search_request = null;
return true;
};
this.sent_successfully = function(type, msg)
{
this.list_mailbox();
this.display_message(msg, type, true);
}
/*********************************************************/
/********* keyboard live-search methods *********/
/*********************************************************/
// handler for keyboard events on address-fields
this.ksearch_keypress = function(e, obj)
{
if (this.ksearch_timer)
clearTimeout(this.ksearch_timer);
var highlight;
var key = rcube_event.get_keycode(e);
var mod = rcube_event.get_modifier(e);
switch (key)
{
case 38: // key up
case 40: // key down
if (!this.ksearch_pane)
break;
var dir = key==38 ? 1 : 0;
highlight = document.getElementById('rcmksearchSelected');
if (!highlight)
highlight = this.ksearch_pane.__ul.firstChild;
if (highlight)
this.ksearch_select(dir ? highlight.previousSibling : highlight.nextSibling);
return rcube_event.cancel(e);
case 9: // tab
if(mod == SHIFT_KEY)
break;
case 13: // enter
if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value)
break;
// insert selected address and hide ksearch pane
this.insert_recipient(this.ksearch_selected);
this.ksearch_hide();
return rcube_event.cancel(e);
case 27: // escape
this.ksearch_hide();
break;
case 37: // left
case 39: // right
if (mod != SHIFT_KEY)
return;
}
// start timer
this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(); }, 200);
this.ksearch_input = obj;
return true;
};
this.ksearch_select = function(node)
{
var current = $('#rcmksearchSelected');
if (current[0] && node) {
current.removeAttr('id').removeClass('selected');
}
if (node) {
$(node).attr('id', 'rcmksearchSelected').addClass('selected');
this.ksearch_selected = node._rcm_id;
}
};
this.insert_recipient = function(id)
{
if (!this.env.contacts[id] || !this.ksearch_input)
return;
// get cursor pos
var inp_value = this.ksearch_input.value.toLowerCase();
var cpos = this.get_caret_pos(this.ksearch_input);
var p = inp_value.lastIndexOf(this.ksearch_value, cpos);
// replace search string with full address
var pre = this.ksearch_input.value.substring(0, p);
var end = this.ksearch_input.value.substring(p+this.ksearch_value.length, this.ksearch_input.value.length);
var insert = this.env.contacts[id]+', ';
this.ksearch_input.value = pre + insert + end;
// set caret to insert pos
cpos = p+insert.length;
if (this.ksearch_input.setSelectionRange)
this.ksearch_input.setSelectionRange(cpos, cpos);
};
// address search processor
this.ksearch_get_results = function()
{
var inp_value = this.ksearch_input ? this.ksearch_input.value : null;
if (inp_value === null)
return;
if (this.ksearch_pane && this.ksearch_pane.is(":visible"))
this.ksearch_pane.hide();
// get string from current cursor pos to last comma
var cpos = this.get_caret_pos(this.ksearch_input);
var p = inp_value.lastIndexOf(',', cpos-1);
var q = inp_value.substring(p+1, cpos);
// trim query string
q = q.replace(/(^\s+|\s+$)/g, '').toLowerCase();
// Don't (re-)search if string is empty or if the last results are still active
if (!q.length || q == this.ksearch_value)
return;
this.ksearch_value = q;
this.display_message(this.get_label('searching'), 'loading', true);
this.http_post('autocomplete', '_search='+urlencode(q));
};
this.ksearch_query_results = function(results, search)
{
// ignore this outdated search response
- if (search != this.ksearch_value)
+ if (this.ksearch_value && search != this.ksearch_value)
return;
this.hide_message();
this.env.contacts = results ? results : [];
this.ksearch_display_results(this.env.contacts);
};
this.ksearch_display_results = function (a_results)
{
// display search results
if (a_results.length && this.ksearch_input) {
var p, ul, li;
// create results pane if not present
if (!this.ksearch_pane) {
ul = $('<ul>');
this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body);
this.ksearch_pane.__ul = ul[0];
}
// remove all search results
ul = this.ksearch_pane.__ul;
ul.innerHTML = '';
// add each result line to list
for (i=0; i<a_results.length; i++) {
li = document.createElement('LI');
li.innerHTML = a_results[i].replace(new RegExp('('+this.ksearch_value+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>');
li.onmouseover = function(){ ref.ksearch_select(this); };
li.onmouseup = function(){ ref.ksearch_click(this) };
li._rcm_id = i;
ul.appendChild(li);
}
// select the first
$(ul.firstChild).attr('id', 'rcmksearchSelected').addClass('selected');
this.ksearch_selected = 0;
// move the results pane right under the input box and make it visible
var pos = $(this.ksearch_input).offset();
this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px' }).show();
}
// hide results pane
else
this.ksearch_hide();
};
this.ksearch_click = function(node)
{
if (this.ksearch_input)
this.ksearch_input.focus();
this.insert_recipient(node._rcm_id);
this.ksearch_hide();
};
this.ksearch_blur = function()
{
if (this.ksearch_timer)
clearTimeout(this.ksearch_timer);
this.ksearch_value = '';
this.ksearch_input = null;
this.ksearch_hide();
};
this.ksearch_hide = function()
{
this.ksearch_selected = null;
if (this.ksearch_pane)
this.ksearch_pane.hide();
};
/*********************************************************/
/********* address book methods *********/
/*********************************************************/
this.contactlist_keypress = function(list)
{
if (list.key_pressed == list.DELETE_KEY)
this.command('delete');
};
this.contactlist_select = function(list)
{
if (this.preview_timer)
clearTimeout(this.preview_timer);
var id, frame, ref = this;
if (id = list.get_single_selection())
this.preview_timer = window.setTimeout(function(){ ref.load_contact(id, 'show'); }, 200);
else if (this.env.contentframe)
this.show_contentframe(false);
this.enable_command('compose', list.selection.length > 0);
this.enable_command('edit', (id && this.env.address_sources && !this.env.address_sources[this.env.source].readonly) ? true : false);
this.enable_command('delete', list.selection.length && this.env.address_sources && !this.env.address_sources[this.env.source].readonly);
return false;
};
this.list_contacts = function(src, page)
{
var add_url = '';
var target = window;
if (!src)
src = this.env.source;
if (page && this.current_page==page && src == this.env.source)
return false;
if (src != this.env.source)
{
page = 1;
this.env.current_page = page;
this.reset_qsearch();
}
this.select_folder(src, this.env.source);
this.env.source = src;
// load contacts remotely
if (this.gui_objects.contactslist)
{
this.list_contacts_remote(src, page);
return;
}
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
target = window.frames[this.env.contentframe];
add_url = '&_framed=1';
}
// also send search request to get the correct listing
if (this.env.search_request)
add_url += '&_search='+this.env.search_request;
this.set_busy(true, 'loading');
target.location.href = this.env.comm_path+(src ? '&_source='+urlencode(src) : '')+(page ? '&_page='+page : '')+add_url;
};
// send remote request to load contacts list
this.list_contacts_remote = function(src, page)
{
// clear message list first
this.contact_list.clear(true);
this.show_contentframe(false);
this.enable_command('delete', 'compose', false);
// send request to server
var url = (src ? '_source='+urlencode(src) : '') + (page ? (src?'&':'') + '_page='+page : '');
this.env.source = src;
// also send search request to get the right messages
if (this.env.search_request)
url += '&_search='+this.env.search_request;
this.set_busy(true, 'loading');
this.http_request('list', url, true);
};
// load contact record
this.load_contact = function(cid, action, framed)
{
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
add_url = '&_framed=1';
target = window.frames[this.env.contentframe];
this.show_contentframe(true);
}
else if (framed)
return false;
if (action && (cid || action=='add') && !this.drag_active)
{
this.set_busy(true);
target.location.href = this.env.comm_path+'&_action='+action+'&_source='+urlencode(this.env.source)+'&_cid='+urlencode(cid) + add_url;
}
return true;
};
// copy a contact to the specified target (group or directory)
this.copy_contact = function(cid, to)
{
if (!cid)
cid = this.contact_list.get_selection().join(',');
if (to != this.env.source && cid && this.env.address_sources[to] && !this.env.address_sources[to].readonly)
this.http_post('copy', '_cid='+urlencode(cid)+'&_source='+urlencode(this.env.source)+'&_to='+urlencode(to));
};
this.delete_contacts = function()
{
// exit if no mailbox specified or if selection is empty
var selection = this.contact_list.get_selection();
if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
return;
var a_cids = new Array();
var qs = '';
if (this.env.cid)
a_cids[a_cids.length] = this.env.cid;
else
{
var id;
for (var n=0; n<selection.length; n++)
{
id = selection[n];
a_cids[a_cids.length] = id;
this.contact_list.remove_row(id, (n == selection.length-1));
}
// hide content frame if we delete the currently displayed contact
if (selection.length == 1)
this.show_contentframe(false);
}
// also send search request to get the right records from the next page
if (this.env.search_request)
qs += '&_search='+this.env.search_request;
// send request to server
this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs);
return true;
};
// update a contact record in the list
this.update_contact_row = function(cid, cols_arr)
{
var row;
if (this.contact_list.rows[cid] && (row = this.contact_list.rows[cid].obj)) {
for (var c=0; c<cols_arr.length; c++)
if (row.cells[c])
$(row.cells[c]).html(cols_arr[c]);
return true;
}
return false;
};
/*********************************************************/
/********* user settings methods *********/
/*********************************************************/
this.init_subscription_list = function()
{
var p = this;
this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, {multiselect:false, draggable:true, keyboard:false, toggleselect:true});
this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); });
this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; });
this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); });
this.subscription_list.row_init = function (row)
{
var anchors = row.obj.getElementsByTagName('A');
if (anchors[0])
anchors[0].onclick = function() { p.rename_folder(row.id); return false; };
if (anchors[1])
anchors[1].onclick = function() { p.delete_folder(row.id); return false; };
row.obj.onmouseover = function() { p.focus_subscription(row.id); };
row.obj.onmouseout = function() { p.unfocus_subscription(row.id); };
}
this.subscription_list.init();
}
this.identity_select = function(list)
{
var id;
if (id = list.get_single_selection())
this.load_identity(id, 'edit-identity');
};
// load contact record
this.load_identity = function(id, action)
{
if (action=='edit-identity' && (!id || id==this.env.iid))
return false;
var add_url = '';
var target = window;
if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
{
add_url = '&_framed=1';
target = window.frames[this.env.contentframe];
document.getElementById(this.env.contentframe).style.visibility = 'inherit';
}
if (action && (id || action=='add-identity'))
{
this.set_busy(true);
target.location.href = this.env.comm_path+'&_action='+action+'&_iid='+id+add_url;
}
return true;
};
this.delete_identity = function(id)
{
// exit if no mailbox specified or if selection is empty
var selection = this.identity_list.get_selection();
if (!(selection.length || this.env.iid))
return;
if (!id)
id = this.env.iid ? this.env.iid : selection[0];
// if (this.env.framed && id)
this.goto_url('delete-identity', '_iid='+id, true);
return true;
};
this.focus_subscription = function(id)
{
var row, folder;
var reg = RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
if (this.drag_active && this.env.folder && (row = document.getElementById(id)))
if (this.env.subscriptionrows[id] &&
(folder = this.env.subscriptionrows[id][0]))
{
if (this.check_droptarget(folder) &&
!this.env.subscriptionrows[this.get_folder_row_id(this.env.folder)][2] &&
(folder != this.env.folder.replace(reg, '')) &&
(!folder.match(new RegExp('^'+RegExp.escape(this.env.folder+this.env.delimiter)))))
{
this.set_env('dstfolder', folder);
$(row).addClass('droptarget');
}
}
else if (this.env.folder.match(new RegExp(RegExp.escape(this.env.delimiter))))
{
this.set_env('dstfolder', this.env.delimiter);
$(this.subscription_list.frame).addClass('droptarget');
}
}
this.unfocus_subscription = function(id)
{
var row = $('#'+id);
this.set_env('dstfolder', null);
if (this.env.subscriptionrows[id] && row[0])
row.removeClass('droptarget');
else
$(this.subscription_list.frame).removeClass('droptarget');
}
this.subscription_select = function(list)
{
var id, folder;
if ((id = list.get_single_selection()) &&
this.env.subscriptionrows['rcmrow'+id] &&
(folder = this.env.subscriptionrows['rcmrow'+id][0]))
this.set_env('folder', folder);
else
this.set_env('folder', null);
if (this.gui_objects.createfolderhint)
$(this.gui_objects.createfolderhint).html(this.env.folder ? this.get_label('addsubfolderhint') : '');
};
this.subscription_move_folder = function(list)
{
var reg = RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
if (this.env.folder && this.env.dstfolder && (this.env.dstfolder != this.env.folder) &&
(this.env.dstfolder != this.env.folder.replace(reg, '')))
{
var reg = new RegExp('[^'+RegExp.escape(this.env.delimiter)+']*['+RegExp.escape(this.env.delimiter)+']', 'g');
var basename = this.env.folder.replace(reg, '');
var newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename;
this.set_busy(true, 'foldermoving');
this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.folder)+'&_folder_newname='+urlencode(newname), true);
}
this.drag_active = false;
this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder));
};
// tell server to create and subscribe a new mailbox
this.create_folder = function(name)
{
if (this.edit_folder)
this.reset_folder_rename();
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
{
name = form.elements['_folder_name'].value;
if (name.indexOf(this.env.delimiter)>=0)
{
alert(this.get_label('forbiddencharacter')+' ('+this.env.delimiter+')');
return false;
}
if (this.env.folder && name != '')
name = this.env.folder+this.env.delimiter+name;
this.set_busy(true, 'foldercreating');
this.http_post('create-folder', '_name='+urlencode(name), true);
}
else if (form.elements['_folder_name'])
form.elements['_folder_name'].focus();
};
// start renaming the mailbox name.
// this will replace the name string with an input field
this.rename_folder = function(id)
{
var temp, row, form;
// reset current renaming
if (temp = this.edit_folder)
{
this.reset_folder_rename();
if (temp == id)
return;
}
if (id && this.env.subscriptionrows[id] && (row = document.getElementById(id)))
{
var reg = new RegExp('.*['+RegExp.escape(this.env.delimiter)+']');
this.name_input = document.createElement('INPUT');
this.name_input.value = this.env.subscriptionrows[id][0].replace(reg, '');
reg = new RegExp('['+RegExp.escape(this.env.delimiter)+']?[^'+RegExp.escape(this.env.delimiter)+']+$');
this.name_input.__parent = this.env.subscriptionrows[id][0].replace(reg, '');
this.name_input.onkeypress = function(e){ rcmail.name_input_keypress(e); };
row.cells[0].replaceChild(this.name_input, row.cells[0].firstChild);
this.edit_folder = id;
this.name_input.select();
if (form = this.gui_objects.editform)
form.onsubmit = function(){ return false; };
}
};
// remove the input field and write the current mailbox name to the table cell
this.reset_folder_rename = function()
{
var cell = this.name_input ? this.name_input.parentNode : null;
if (cell && this.edit_folder && this.env.subscriptionrows[this.edit_folder])
$(cell).html(this.env.subscriptionrows[this.edit_folder][1]);
this.edit_folder = null;
};
// handler for keyboard events on the input field
this.name_input_keypress = function(e)
{
var key = rcube_event.get_keycode(e);
// enter
if (key==13)
{
var newname = this.name_input ? this.name_input.value : null;
if (this.edit_folder && newname)
{
if (newname.indexOf(this.env.delimiter)>=0)
{
alert(this.get_label('forbiddencharacter')+' ('+this.env.delimiter+')');
return false;
}
if (this.name_input.__parent)
newname = this.name_input.__parent + this.env.delimiter + newname;
this.set_busy(true, 'folderrenaming');
this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname), true);
}
}
// escape
else if (key==27)
this.reset_folder_rename();
};
// delete a specific mailbox with all its messages
this.delete_folder = function(id)
{
var folder = this.env.subscriptionrows[id][0];
if (this.edit_folder)
this.reset_folder_rename();
if (folder && confirm(this.get_label('deletefolderconfirm')))
{
this.set_busy(true, 'folderdeleting');
this.http_post('delete-folder', '_mboxes='+urlencode(folder), true);
this.set_env('folder', null);
$(this.gui_objects.createfolderhint).html('');
}
};
// add a new folder to the subscription list by cloning a folder row
this.add_folder_row = function(name, display_name, replace, before)
{
if (!this.gui_objects.subscriptionlist)
return false;
// find not protected folder
for (var refid in this.env.subscriptionrows)
if (this.env.subscriptionrows[refid]!=null && !this.env.subscriptionrows[refid][2])
break;
var refrow, form;
var tbody = this.gui_objects.subscriptionlist.tBodies[0];
var id = 'rcmrow'+(tbody.childNodes.length+1);
var selection = this.subscription_list.get_single_selection();
if (replace && replace.id)
{
id = replace.id;
refid = replace.id;
}
if (!id || !(refrow = document.getElementById(refid)))
{
// Refresh page if we don't have a table row to clone
this.goto_url('folders');
}
else
{
// clone a table row if there are existing rows
var row = this.clone_table_row(refrow);
row.id = id;
if (before && (before = this.get_folder_row_id(before)))
tbody.insertBefore(row, document.getElementById(before));
else
tbody.appendChild(row);
if (replace)
tbody.removeChild(replace);
}
// add to folder/row-ID map
this.env.subscriptionrows[row.id] = [name, display_name, 0];
// set folder name
row.cells[0].innerHTML = display_name;
// set messages count to zero
if (!replace)
row.cells[1].innerHTML = '*';
if (!replace && row.cells[2] && row.cells[2].firstChild.tagName=='INPUT')
{
row.cells[2].firstChild.value = name;
row.cells[2].firstChild.checked = true;
}
// add new folder to rename-folder list and clear input field
if (!replace && (form = this.gui_objects.editform))
{
if (form.elements['_folder_oldname'])
form.elements['_folder_oldname'].options[form.elements['_folder_oldname'].options.length] = new Option(name,name);
if (form.elements['_folder_name'])
form.elements['_folder_name'].value = '';
}
this.init_subscription_list();
if (selection && document.getElementById('rcmrow'+selection))
this.subscription_list.select_row(selection);
if (document.getElementById(id).scrollIntoView)
document.getElementById(id).scrollIntoView();
};
// replace an existing table row with a new folder line
this.replace_folder_row = function(oldfolder, newfolder, display_name, before)
{
var id = this.get_folder_row_id(oldfolder);
var row = document.getElementById(id);
// replace an existing table row (if found)
this.add_folder_row(newfolder, display_name, row, before);
// rename folder in rename-folder dropdown
var form, elm;
if ((form = this.gui_objects.editform) && (elm = form.elements['_folder_oldname']))
{
for (var i=0;i<elm.options.length;i++)
{
if (elm.options[i].value == oldfolder)
{
elm.options[i].text = display_name;
elm.options[i].value = newfolder;
break;
}
}
form.elements['_folder_newname'].value = '';
}
};
// remove the table row of a specific mailbox from the table
// (the row will not be removed, just hidden)
this.remove_folder_row = function(folder)
{
var row;
var id = this.get_folder_row_id(folder);
if (id && (row = document.getElementById(id)))
row.style.display = 'none';
// remove folder from rename-folder list
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_oldname'])
{
for (var i=0;i<form.elements['_folder_oldname'].options.length;i++)
{
if (form.elements['_folder_oldname'].options[i].value == folder)
{
form.elements['_folder_oldname'].options[i] = null;
break;
}
}
}
if (form && form.elements['_folder_newname'])
form.elements['_folder_newname'].value = '';
};
this.subscribe_folder = function(folder)
{
if (folder)
this.http_post('subscribe', '_mbox='+urlencode(folder));
};
this.unsubscribe_folder = function(folder)
{
if (folder)
this.http_post('unsubscribe', '_mbox='+urlencode(folder));
};
// helper method to find a specific mailbox row ID
this.get_folder_row_id = function(folder)
{
for (var id in this.env.subscriptionrows)
if (this.env.subscriptionrows[id] && this.env.subscriptionrows[id][0] == folder)
break;
return id;
};
// duplicate a specific table row
this.clone_table_row = function(row)
{
var cell, td;
var new_row = document.createElement('TR');
for(var n=0; n<row.cells.length; n++)
{
cell = row.cells[n];
td = document.createElement('TD');
if (cell.className)
td.className = cell.className;
if (cell.align)
td.setAttribute('align', cell.align);
td.innerHTML = cell.innerHTML;
new_row.appendChild(td);
}
return new_row;
};
/*********************************************************/
/********* GUI functionality *********/
/*********************************************************/
// eable/disable buttons for page shifting
this.set_page_buttons = function()
{
this.enable_command('nextpage', (this.env.pagecount > this.env.current_page));
this.enable_command('lastpage', (this.env.pagecount > this.env.current_page));
this.enable_command('previouspage', (this.env.current_page > 1));
this.enable_command('firstpage', (this.env.current_page > 1));
}
// set button to a specific state
this.set_button = function(command, state)
{
var a_buttons = this.buttons[command];
var button, obj;
if(!a_buttons || !a_buttons.length)
return false;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
obj = document.getElementById(button.id);
// get default/passive setting of the button
if (obj && button.type=='image' && !button.status) {
button.pas = obj._original_src ? obj._original_src : obj.src;
// respect PNG fix on IE browsers
if (obj.runtimeStyle && obj.runtimeStyle.filter && obj.runtimeStyle.filter.match(/src=['"]([^'"]+)['"]/))
button.pas = RegExp.$1;
}
else if (obj && !button.status)
button.pas = String(obj.className);
// set image according to button state
if (obj && button.type=='image' && button[state])
{
button.status = state;
obj.src = button[state];
}
// set class name according to button state
else if (obj && typeof(button[state])!='undefined')
{
button.status = state;
obj.className = button[state];
}
// disable/enable input buttons
if (obj && button.type=='input')
{
button.status = state;
obj.disabled = !state;
}
}
};
// display a specific alttext
this.set_alttext = function(command, label)
{
if (!this.buttons[command] || !this.buttons[command].length)
return;
var button, obj, link;
for (var n=0; n<this.buttons[command].length; n++)
{
button = this.buttons[command][n];
obj = document.getElementById(button.id);
if (button.type=='image' && obj)
{
obj.setAttribute('alt', this.get_label(label));
if ((link = obj.parentNode) && link.tagName == 'A')
link.setAttribute('title', this.get_label(label));
}
else if (obj)
obj.setAttribute('title', this.get_label(label));
}
};
// mouse over button
this.button_over = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return false;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.over)
img.src = button.over;
}
}
};
// mouse down on button
this.button_sel = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.sel)
img.src = button.sel;
}
}
};
// mouse out of button
this.button_out = function(command, id)
{
var a_buttons = this.buttons[command];
var button, img;
if(!a_buttons || !a_buttons.length)
return;
for(var n=0; n<a_buttons.length; n++)
{
button = a_buttons[n];
if(button.id==id && button.status=='act')
{
img = document.getElementById(button.id);
if (img && button.act)
img.src = button.act;
}
}
};
// write to the document/window title
this.set_pagetitle = function(title)
{
if (title && document.title)
document.title = title;
}
// display a system message
this.display_message = function(msg, type, hold)
{
if (!this.loaded) // save message in order to display after page loaded
{
this.pending_message = new Array(msg, type);
return true;
}
// pass command to parent window
if (this.env.framed && parent.rcmail)
return parent.rcmail.display_message(msg, type, hold);
if (!this.gui_objects.message)
return false;
if (this.message_timer)
clearTimeout(this.message_timer);
var cont = msg;
if (type)
cont = '<div class="'+type+'">'+cont+'</div>';
var obj = $(this.gui_objects.message).html(cont).show();
if (type!='loading')
obj.bind('mousedown', function(){ ref.hide_message(); return true; });
if (!hold)
this.message_timer = window.setTimeout(function(){ ref.hide_message(true); }, this.message_time);
};
// make a message row disapear
this.hide_message = function(fade)
{
if (this.gui_objects.message)
$(this.gui_objects.message).unbind()[(fade?'fadeOut':'hide')]();
};
// mark a mailbox as selected and set environment variable
this.select_folder = function(name, old)
{
if (this.gui_objects.folderlist)
{
var current_li, target_li;
if ((current_li = this.get_folder_li(old))) {
$(current_li).removeClass('selected').removeClass('unfocused');
}
if ((target_li = this.get_folder_li(name))) {
$(target_li).removeClass('unfocused').addClass('selected');
}
}
};
// helper method to find a folder list item
this.get_folder_li = function(name)
{
if (this.gui_objects.folderlist)
{
name = String(name).replace(this.identifier_expr, '');
return document.getElementById('rcmli'+name);
}
return null;
};
// for reordering column array, Konqueror workaround
this.set_message_coltypes = function(coltypes)
{
this.coltypes = coltypes;
// set correct list titles
var cell, col;
var thead = this.gui_objects.messagelist ? this.gui_objects.messagelist.tHead : null;
for (var n=0; thead && n<this.coltypes.length; n++)
{
col = this.coltypes[n];
if ((cell = thead.rows[0].cells[n+1]) && (col=='from' || col=='to'))
{
// if we have links for sorting, it's a bit more complicated...
if (cell.firstChild && cell.firstChild.tagName=='A')
{
cell.firstChild.innerHTML = this.get_label(this.coltypes[n]);
cell.firstChild.onclick = function(){ return rcmail.command('sort', this.__col, this); };
cell.firstChild.__col = col;
}
else
cell.innerHTML = this.get_label(this.coltypes[n]);
cell.id = 'rcm'+col;
}
else if (col == 'subject' && this.message_list)
this.message_list.subject_col = n+1;
}
};
// create a table row in the message list
this.add_message_row = function(uid, cols, flags, attachment, attop)
{
if (!this.gui_objects.messagelist || !this.message_list)
return false;
if (this.message_list.background)
var tbody = this.message_list.background;
else
var tbody = this.gui_objects.messagelist.tBodies[0];
var rowcount = tbody.rows.length;
var even = rowcount%2;
this.env.messages[uid] = {
deleted: flags.deleted?1:0,
replied: flags.replied?1:0,
unread: flags.unread?1:0,
forwarded: flags.forwarded?1:0,
flagged:flags.flagged?1:0
};
var css_class = 'message'
+ (even ? ' even' : ' odd')
+ (flags.unread ? ' unread' : '')
+ (flags.deleted ? ' deleted' : '')
+ (flags.flagged ? ' flagged' : '')
+ (this.message_list.in_selection(uid) ? ' selected' : '');
// for performance use DOM instead of jQuery here
var row = document.createElement('TR');
row.id = 'rcmrow'+uid;
row.className = css_class;
var icon = this.env.messageicon;
if (flags.deleted && this.env.deletedicon)
icon = this.env.deletedicon;
else if (flags.replied && this.env.repliedicon)
{
if (flags.forwarded && this.env.forwardedrepliedicon)
icon = this.env.forwardedrepliedicon;
else
icon = this.env.repliedicon;
}
else if (flags.forwarded && this.env.forwardedicon)
icon = this.env.forwardedicon;
else if(flags.unread && this.env.unreadicon)
icon = this.env.unreadicon;
// add icon col
var col = document.createElement('TD');
col.className = 'icon';
col.innerHTML = icon ? '<img src="'+icon+'" alt="" />' : '';
row.appendChild(col);
// add each submitted col
for (var n = 0; n < this.coltypes.length; n++) {
var c = this.coltypes[n];
col = document.createElement('TD');
col.className = String(c).toLowerCase();
if (c=='flag') {
if (flags.flagged && this.env.flaggedicon)
col.innerHTML = '<img src="'+this.env.flaggedicon+'" alt="" />';
else if(!flags.flagged && this.env.unflaggedicon)
col.innerHTML = '<img src="'+this.env.unflaggedicon+'" alt="" />';
}
else if (c=='attachment')
col.innerHTML = (attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" />' : ' ');
else
col.innerHTML = cols[c];
row.appendChild(col);
}
this.message_list.insert_row(row, attop);
// remove 'old' row
if (attop && this.env.pagesize && this.message_list.rowcount > this.env.pagesize) {
var uid = this.message_list.get_last_row();
this.message_list.remove_row(uid);
this.message_list.clear_selection(uid);
}
};
// messages list handling in background (for performance)
this.offline_message_list = function(flag)
{
if (this.message_list)
this.message_list.set_background_mode(flag);
};
// replace content of row count display
this.set_rowcount = function(text)
{
$(this.gui_objects.countdisplay).html(text);
// update page navigation buttons
this.set_page_buttons();
};
// replace content of mailboxname display
this.set_mailboxname = function(content)
{
if (this.gui_objects.mailboxname && content)
this.gui_objects.mailboxname.innerHTML = content;
};
// replace content of quota display
this.set_quota = function(content)
{
if (content && this.gui_objects.quotadisplay)
$(this.gui_objects.quotadisplay).html(content);
};
// update the mailboxlist
this.set_unread_count = function(mbox, count, set_title)
{
if (!this.gui_objects.mailboxlist)
return false;
this.env.unread_counts[mbox] = count;
this.set_unread_count_display(mbox, set_title);
}
// update the mailbox count display
this.set_unread_count_display = function(mbox, set_title)
{
var reg, text_obj, item, mycount, childcount, div;
if (item = this.get_folder_li(mbox))
{
mycount = this.env.unread_counts[mbox] ? this.env.unread_counts[mbox] : 0;
text_obj = item.getElementsByTagName('a')[0];
reg = /\s+\([0-9]+\)$/i;
childcount = 0;
if ((div = item.getElementsByTagName('div')[0]) &&
div.className.match(/collapsed/))
{
// add children's counters
for (var k in this.env.unread_counts)
if (k.indexOf(mbox + this.env.delimiter) == 0)
childcount += this.env.unread_counts[k];
}
if (mycount && text_obj.innerHTML.match(reg))
text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+mycount+')');
else if (mycount)
text_obj.innerHTML += ' ('+mycount+')';
else
text_obj.innerHTML = text_obj.innerHTML.replace(reg, '');
// set parent's display
reg = new RegExp(RegExp.escape(this.env.delimiter) + '[^' + RegExp.escape(this.env.delimiter) + ']+$');
if (mbox.match(reg))
this.set_unread_count_display(mbox.replace(reg, ''), false);
// set the right classes
if ((mycount+childcount)>0)
$(item).addClass('unread');
else
$(item).removeClass('unread');
}
// set unread count to window title
reg = /^\([0-9]+\)\s+/i;
if (set_title && document.title)
{
var doc_title = String(document.title);
var new_title = "";
if (mycount && doc_title.match(reg))
new_title = doc_title.replace(reg, '('+mycount+') ');
else if (mycount)
new_title = '('+mycount+') '+doc_title;
else
new_title = doc_title.replace(reg, '');
this.set_pagetitle(new_title);
}
};
// notifies that a new message(s) has hit the mailbox
this.new_message_focus = function()
{
// focus main window
if (this.env.framed && window.parent)
window.parent.focus();
else
window.focus();
}
// add row to contacts list
this.add_contact_row = function(cid, cols, select)
{
if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
return false;
var tbody = this.gui_objects.contactslist.tBodies[0];
var rowcount = tbody.rows.length;
var even = rowcount%2;
var row = document.createElement('TR');
row.id = 'rcmrow'+cid;
row.className = 'contact '+(even ? 'even' : 'odd');
if (this.contact_list.in_selection(cid))
row.className += ' selected';
// add each submitted col
for (var c in cols) {
col = document.createElement('TD');
col.className = String(c).toLowerCase();
col.innerHTML = cols[c];
row.appendChild(col);
}
this.contact_list.insert_row(row);
this.enable_command('export', (this.contact_list.rowcount > 0));
};
this.toggle_prefer_html = function(checkbox)
{
var addrbook_show_images;
if (addrbook_show_images = document.getElementById('rcmfd_addrbook_show_images'))
addrbook_show_images.disabled = !checkbox.checked;
}
// display fetched raw headers
this.set_headers = function(content)
{
if (this.gui_objects.all_headers_row && this.gui_objects.all_headers_box && content) {
$(this.gui_objects.all_headers_box).html(content).show();
if (this.env.framed && parent.rcmail)
parent.rcmail.set_busy(false);
else
this.set_busy(false);
}
};
// display all-headers row and fetch raw message headers
this.load_headers = function(elem)
{
if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box || !this.env.uid)
return;
$(elem).removeClass('show-headers').addClass('hide-headers');
$(this.gui_objects.all_headers_row).show();
elem.onclick = function() { rcmail.hide_headers(elem); }
// fetch headers only once
if (!this.gui_objects.all_headers_box.innerHTML)
{
this.display_message(this.get_label('loading'), 'loading', true);
this.http_post('headers', '_uid='+this.env.uid);
}
}
// hide all-headers row
this.hide_headers = function(elem)
{
if (!this.gui_objects.all_headers_row || !this.gui_objects.all_headers_box)
return;
$(elem).removeClass('hide-headers').addClass('show-headers');
$(this.gui_objects.all_headers_row).hide();
elem.onclick = function() { rcmail.load_headers(elem); }
}
/********************************************************/
/********* html to text conversion functions *********/
/********************************************************/
this.html2plain = function(htmlText, id)
{
var url = this.env.bin_path+'html2text.php';
var rcmail = this;
this.set_busy(true, 'converting');
console.log('HTTP POST: '+url);
$.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream',
error: function(o) { rcmail.http_error(o); },
success: function(data) { rcmail.set_busy(false); $(document.getElementById(id)).val(data); console.log(data); }
});
}
this.plain2html = function(plainText, id)
{
this.set_busy(true, 'converting');
$(document.getElementById(id)).val('<pre>'+plainText+'</pre>');
this.set_busy(false);
}
/********************************************************/
/********* remote request methods *********/
/********************************************************/
this.redirect = function(url, lock)
{
if (lock || lock === null)
this.set_busy(true);
if (this.env.framed && window.parent)
parent.location.href = url;
else
location.href = url;
};
this.goto_url = function(action, query, lock)
{
var querystring = query ? '&'+query : '';
this.redirect(this.env.comm_path+'&_action='+action+querystring, lock);
};
// send a http request to the server
this.http_request = function(action, querystring, lock)
{
querystring += (querystring ? '&' : '') + '_remote=1';
var url = this.env.comm_path + '&_action=' + action + '&' + querystring
// send request
console.log('HTTP POST: ' + url);
jQuery.get(url, { _unlock:(lock?1:0) }, function(data){ ref.http_response(data); }, 'json');
};
// send a http POST request to the server
this.http_post = function(action, postdata, lock)
{
var url = this.env.comm_path+'&_action=' + action;
if (postdata && typeof(postdata) == 'object') {
postdata._remote = 1;
postdata._unlock = (lock ? 1 : 0);
}
else
postdata += (postdata ? '&' : '') + '_remote=1' + (lock ? '&_unlock=1' : '');
// send request
console.log('HTTP POST: ' + url);
jQuery.post(url, postdata, function(data){ ref.http_response(data); }, 'json');
};
// handle HTTP response
this.http_response = function(response)
{
var console_msg = '';
if (response.unlock)
this.set_busy(false);
// set env vars
if (response.env)
this.set_env(response.env);
// we have labels to add
if (typeof response.texts == 'object') {
for (var name in response.texts)
if (typeof response.texts[name] == 'string')
this.add_label(name, response.texts[name]);
}
// if we get javascript code from server -> execute it
if (response.exec) {
console.log(response.exec);
eval(response.exec);
}
// process the response data according to the sent action
switch (response.action) {
case 'delete':
if (this.task == 'addressbook') {
var uid = this.contact_list.get_selection();
this.enable_command('compose', (uid && this.contact_list.rows[uid]));
this.enable_command('delete', 'edit', (uid && this.contact_list.rows[uid] && this.env.address_sources && !this.env.address_sources[this.env.source].readonly));
this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
}
case 'moveto':
if (this.env.action == 'show')
this.command('list');
else if (this.message_list)
this.message_list.init();
break;
case 'purge':
case 'expunge':
if (!this.env.messagecount && this.task == 'mail') {
// clear preview pane content
if (this.env.contentframe)
this.show_contentframe(false);
// disable commands useless when mailbox is empty
this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'mark', 'viewsource',
'print', 'load-attachment', 'purge', 'expunge', 'select-all', 'select-none', 'sort', false);
}
break;
case 'check-recent':
case 'getunread':
case 'list':
if (this.task == 'mail') {
if (this.message_list && response.action == 'list')
this.msglist_select(this.message_list);
this.enable_command('show', 'expunge', 'select-all', 'select-none', 'sort', (this.env.messagecount > 0));
this.enable_command('purge', this.purge_mailbox_test());
}
else if (this.task == 'addressbook')
this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
break;
}
};
// handle HTTP request errors
this.http_error = function(request, status, err)
{
var errmsg = request.statusText;
this.set_busy(false);
request.abort();
this.display_message('Unknown Server Error!' + (errmsg ? ' ('+errmsg+')' : ''), 'error');
};
// use an image to send a keep-alive siganl to the server
this.send_keep_alive = function()
{
var d = new Date();
this.http_request('keep-alive', '_t='+d.getTime());
};
// send periodic request to check for recent messages
this.check_for_recent = function(setbusy)
{
if (this.busy)
return;
if (setbusy)
this.set_busy(true, 'checkingmail');
var addurl = '_t=' + (new Date().getTime());
if (this.gui_objects.messagelist)
addurl += '&_list=1';
if (this.gui_objects.quotadisplay)
addurl += '&_quota=1';
if (this.env.search_request)
addurl += '&_search=' + this.env.search_request;
this.http_request('check-recent', addurl, true);
};
/********************************************************/
/********* helper methods *********/
/********************************************************/
// check if we're in show mode or if we have a unique selection
// and return the message uid
this.get_single_uid = function()
{
return this.env.uid ? this.env.uid : (this.message_list ? this.message_list.get_single_selection() : null);
};
// same as above but for contacts
this.get_single_cid = function()
{
return this.env.cid ? this.env.cid : (this.contact_list ? this.contact_list.get_single_selection() : null);
};
this.get_caret_pos = function(obj)
{
if (typeof(obj.selectionEnd)!='undefined')
return obj.selectionEnd;
else if (document.selection && document.selection.createRange)
{
var range = document.selection.createRange();
if (range.parentElement()!=obj)
return 0;
var gm = range.duplicate();
if (obj.tagName=='TEXTAREA')
gm.moveToElementText(obj);
else
gm.expand('textedit');
gm.setEndPoint('EndToStart', range);
var p = gm.text.length;
return p<=obj.value.length ? p : -1;
}
else
return obj.value.length;
};
this.set_caret2start = function(obj)
{
if (obj.createTextRange)
{
var range = obj.createTextRange();
range.collapse(true);
range.select();
}
else if (obj.setSelectionRange)
obj.setSelectionRange(0,0);
obj.focus();
};
// set all fields of a form disabled
this.lock_form = function(form, lock)
{
if (!form || !form.elements)
return;
var type;
for (var n=0; n<form.elements.length; n++)
{
type = form.elements[n];
if (type=='hidden')
continue;
form.elements[n].disabled = lock;
}
};
} // end object rcube_webmail
// copy event engine prototype
rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener;
rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener;
rcube_webmail.prototype.triggerEvent = rcube_event_engine.prototype.triggerEvent;
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Mar 1, 1:43 PM (2 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
167148
Default Alt Text
(154 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment