summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2005-12-03 16:54:12 +0000
committerthomascube <thomas@roundcube.net>2005-12-03 16:54:12 +0000
commit1cded85790206afe084e1baff371c543711b2b18 (patch)
treeb050fb89707e048df5f30f500faad792962a1e81
parent5bc8cb662fc3bcda9aa641b7a5e88c0b81dd63d6 (diff)
Re-design of caching (new database table added\!); some bugfixes; Postgres support
-rw-r--r--CHANGELOG104
-rw-r--r--INSTALL20
-rw-r--r--SQL/mysql.initial.sql38
-rw-r--r--SQL/mysql.update.sql35
-rwxr-xr-xSQL/postgres.initial.sql286
-rw-r--r--SQL/sqlite.initial.sql54
-rw-r--r--UPGRADING30
-rw-r--r--config/db.inc.php.dist18
-rw-r--r--config/main.inc.php.dist2
-rw-r--r--index.php17
-rw-r--r--program/include/cache.inc5
-rw-r--r--program/include/main.inc312
-rwxr-xr-xprogram/include/rcube_db.inc465
-rw-r--r--program/include/rcube_imap.inc748
-rwxr-xr-xprogram/include/rcube_mdb2.inc16
-rw-r--r--program/include/rcube_shared.inc109
-rw-r--r--program/include/rcube_sqlite.inc71
-rw-r--r--program/include/session.inc16
-rw-r--r--program/js/app.js99
-rw-r--r--program/localization/de/labels.inc4
-rw-r--r--program/localization/de/messages.inc2
-rw-r--r--program/localization/ee/labels.inc182
-rw-r--r--program/localization/ee/messages.inc80
-rw-r--r--program/localization/en/labels.inc4
-rw-r--r--program/localization/en/messages.inc8
-rw-r--r--program/localization/en_GB/labels.inc3
-rw-r--r--program/localization/index.inc1
-rw-r--r--program/steps/addressbook/delete.inc6
-rw-r--r--program/steps/addressbook/edit.inc2
-rw-r--r--program/steps/addressbook/func.inc6
-rw-r--r--program/steps/addressbook/list.inc4
-rw-r--r--program/steps/addressbook/save.inc12
-rw-r--r--program/steps/addressbook/show.inc2
-rw-r--r--program/steps/mail/addcontact.inc8
-rw-r--r--program/steps/mail/compose.inc182
-rw-r--r--program/steps/mail/func.inc121
-rw-r--r--program/steps/mail/sendmail.inc15
-rw-r--r--program/steps/settings/delete_identity.inc2
-rw-r--r--program/steps/settings/edit_identity.inc5
-rw-r--r--program/steps/settings/func.inc4
-rw-r--r--program/steps/settings/manage_folders.inc15
-rw-r--r--program/steps/settings/save_identity.inc12
-rw-r--r--skins/default/images/sort_asc.gifbin0 -> 121 bytes
-rw-r--r--skins/default/images/sort_desc.gifbin0 -> 123 bytes
-rw-r--r--skins/default/mail.css27
-rw-r--r--skins/default/pngbehavior.htc2
-rw-r--r--skins/default/templates/compose.html5
-rw-r--r--skins/default/templates/mail.html4
48 files changed, 2105 insertions, 1058 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ae7631f28..afadced18 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,38 @@
CHANGELOG RoundCube Webmail
---------------------------
+2005/12/03
+----------
+- Added Finnish, Romanian, Polish, Czech, British, Norwegian, Greek, Russian, Estonian and Chinese translation
+- Get IMAP server capabilities in array
+- Check for NAMESPACE capability before sending command
+- Set default user language from config 'locale_string'
+- Added sorting patch for message list
+- Make default sort col/order configurable
+- Fixed XSS in address book and identities
+- Added more XSS protection (Bug #1308236)
+- Added tab indexes for compose form
+- Added 'changed' col to contacts table
+- Support for 160-bit session hashes
+- Added input check for contacts and identities (Patch #1346523)
+- Added messages/warning to compose step (Patch #1323895)
+- Added favicon to the default skin
+- Fixed Bug #1334337 as far as possible
+- Added Reply-To-All functionality (Request #1326395, Patch #1349777)
+- Redesign of client side AJAX code (enable multi threading)
+- Added keep-alive signal every minute
+- Make logs dir configurable
+- Added support for SMTPS
+- Decode attachment file names
+- Make delimiter for message headers configurable
+- Add generic footer to sent messages
+- Choose the rigt identity when replying
+- Remove signature when replying (Request #1333167)
+- Signatures for each identity
+- Select charset when composing message
+- Complete re-design of the caching mechanism
+
+
2005/08/11
----------
- Write list header to client even if list is empty
@@ -14,16 +46,20 @@ CHANGELOG RoundCube Webmail
- Added German translation
-2005/08/20
+2005/10/20
----------
-- Improved cacheing of mailbox messagecount
-- Fixed javascript bug when creating a new message folder
-- Fixed javascript bugs #1260990 and #1260992: folder selection
-- Make Trash folder configurable
-- Auto create folders Inbox, Sent and Trash (if configured)
-- Support for IMAP root folder
-- Added support fot text/enriched messages
-- Make list of special mailboxes configurable
+- Added Swedish, Latvian, Portuguese and Catalan translation
+- Make SMTP auth method configurable
+- Make mailboxlist scrollable (Bug #1326372)
+- Fixed SSL support
+- Improved support for Courier IMAP (root folder and delimiter issues)
+- Moved taskbar from bottom to top
+- Added 'session_lifetime' parameter
+- Fixed wrong unread count when deleting message (Bug #1332434)
+- Srip tags when creating a new folder (Bug #1332084)
+- Translate HTML tags in message headers (Bug #1330134)
+- Correction in German translation (Bug #1329434)
+- Display folder names with special chars correctly (Bug #1330157)
2005/10/07
@@ -44,46 +80,14 @@ CHANGELOG RoundCube Webmail
- Enable IMAPS by host
-2005/10/20
-----------
-- Added Swedish, Latvian, Portuguese and Catalan translation
-- Make SMTP auth method configurable
-- Make mailboxlist scrollable (Bug #1326372)
-- Fixed SSL support
-- Improved support for Courier IMAP (root folder and delimiter issues)
-- Moved taskbar from bottom to top
-- Added 'session_lifetime' parameter
-- Fixed wrong unread count when deleting message (Bug #1332434)
-- Srip tags when creating a new folder (Bug #1332084)
-- Translate HTML tags in message headers (Bug #1330134)
-- Correction in German translation (Bug #1329434)
-- Display folder names with special chars correctly (Bug #1330157)
-
-
-2005/11/18
+2005/08/20
----------
-- Added Finnish, Romanian, Polish, Czech, British, Norwegian, Greek, Russian and Chinese translation
-- Get IMAP server capabilities in array
-- Check for NAMESPACE capability before sending command
-- Set default user language from config 'locale_string'
-- Added sorting patch for message list
-- Make default sort col/order configurable
-- Fixed XSS in address book and identities
-- Added more XSS protection (Bug #1308236)
-- Added tab indexes for compose form
-- Added 'changed' col to contacts table
-- Support for 160-bit session hashes
-- Added input check for contacts and identities (Patch #1346523)
-- Added messages/warning to compose step (Patch #1323895)
-- Added favicon to the default skin
-- Fixed Bug #1334337 as far as possible
-- Added Reply-To-All functionality (Request #1326395, Patch #1349777)
-- Redesign of client side AJAX code (enable multi threading)
-- Added keep-alive signal every minute
-- Make logs dir configurable
-- Added support for SMTPS
-- Decode attachment file names
-- Make delimiter for message headers configurable
-- Add generic footer to sent messages
-
+- Improved cacheing of mailbox messagecount
+- Fixed javascript bug when creating a new message folder
+- Fixed javascript bugs #1260990 and #1260992: folder selection
+- Make Trash folder configurable
+- Auto create folders Inbox, Sent and Trash (if configured)
+- Support for IMAP root folder
+- Added support fot text/enriched messages
+- Make list of special mailboxes configurable
diff --git a/INSTALL b/INSTALL
index cca4fa12a..f343c8228 100644
--- a/INSTALL
+++ b/INSTALL
@@ -31,6 +31,7 @@ roundcube user. Here is an example of that procedure:
> quit
# mysql roundcubemail < SQL/mysql.initial.sql
+
* SQLite
--------
Sqlite requires specifically php5 (sqlite in php4 currently doesn't
@@ -44,6 +45,25 @@ Make sure your configuration points to the sqlite.db file and that the
webserver can write to the file.
+* PostgreSQL
+------------
+To use RoundCube with PostgreSQL support you have to follow the next
+simple steps, which have to be done with the postgres system user (or
+which ever is the database superuser):
+
+$ createuser roundcubemail
+$ createdb -O roundcubemail roundcubemail
+$ psql roundcubemail
+
+roundcubemail =# ALTER USER roundcube WITH PASSWORD 'the_new_password';
+roundcubemail =# \c - roundcubemail
+roundcubemail => \i SQL/postgres.initial.sql
+
+All this has been tested with PostgreSQL 8.0.x and 7.4.x. Older
+versions don't have a -O option for the createdb, so if you are
+using that version you'll have to change ownership of the DB later.
+
+
UPGRADING
=========
If you already have a previous version of RoundCube installed,
diff --git a/SQL/mysql.initial.sql b/SQL/mysql.initial.sql
index 09d9b8017..21444edda 100644
--- a/SQL/mysql.initial.sql
+++ b/SQL/mysql.initial.sql
@@ -11,7 +11,7 @@
CREATE TABLE `cache` (
`cache_id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL default '0',
- `session_id` varchar(32) default NULL,
+ `session_id` varchar(40) default NULL,
`cache_key` varchar(128) NOT NULL default '',
`created` datetime NOT NULL default '0000-00-00 00:00:00',
`data` longtext NOT NULL,
@@ -31,7 +31,7 @@ CREATE TABLE `contacts` (
`contact_id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL default '0',
`changed` datetime NOT NULL default '0000-00-00 00:00:00',
- `del` enum('0','1') NOT NULL default '0',
+ `del` tinyint(1) NOT NULL default '0',
`name` varchar(128) NOT NULL default '',
`email` varchar(128) NOT NULL default '',
`firstname` varchar(128) NOT NULL default '',
@@ -50,8 +50,8 @@ CREATE TABLE `contacts` (
CREATE TABLE `identities` (
`identity_id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL default '0',
- `del` enum('0','1') NOT NULL default '0',
- `default` enum('0','1') NOT NULL default '0',
+ `del` tinyint(1) NOT NULL default '0',
+ `standard` tinyint(1) NOT NULL default '0',
`name` varchar(128) NOT NULL default '',
`organization` varchar(128) NOT NULL default '',
`email` varchar(128) NOT NULL default '',
@@ -94,3 +94,33 @@ CREATE TABLE `users` (
`preferences` text NOT NULL,
PRIMARY KEY (`user_id`)
) TYPE=MyISAM;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `messages`
+--
+
+CREATE TABLE `messages` (
+ `message_id` int(11) unsigned NOT NULL auto_increment,
+ `user_id` int(11) unsigned NOT NULL default '0',
+ `del` tinyint(1) NOT NULL default '0',
+ `cache_key` varchar(128) NOT NULL default '',
+ `idx` int(11) unsigned NOT NULL default '0',
+ `uid` int(11) unsigned NOT NULL default '0',
+ `subject` varchar(255) NOT NULL default '',
+ `from` varchar(255) NOT NULL default '',
+ `to` varchar(255) NOT NULL default '',
+ `cc` varchar(255) NOT NULL default '',
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `size` int(11) unsigned NOT NULL default '0',
+ `headers` text NOT NULL,
+ `body` longtext,
+ PRIMARY KEY (`message_id`),
+ KEY `user_id` (`user_id`),
+ KEY `cache_key` (`cache_key`),
+ KEY `idx` (`idx`),
+ KEY `uid` (`uid`)
+) TYPE=MyISAM;
+
+
diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql
index 0119225ef..778919acf 100644
--- a/SQL/mysql.update.sql
+++ b/SQL/mysql.update.sql
@@ -11,4 +11,39 @@ ALTER TABLE users ADD alias VARCHAR(128) NOT NULL AFTER mail_host;
-- Version 0.1-20051021
ALTER TABLE `session` CHANGE `sess_id` `sess_id` VARCHAR(40) NOT NULL;
+
+ALTER TABLE `contacts` CHANGE `del` `del` TINYINT(1) NOT NULL;
ALTER TABLE `contacts` ADD `changed` DATETIME NOT NULL AFTER `user_id`;
+
+UPDATE `contacts` SET `del`=0 WHERE `del`=1;
+UPDATE `contacts` SET `del`=1 WHERE `del`=2;
+
+ALTER TABLE `identities` CHANGE `default` `standard` TINYINT(1) NOT NULL;
+ALTER TABLE `identities` CHANGE `del` `del` TINYINT(1) NOT NULL;
+
+UPDATE `identities` SET `del`=0 WHERE `del`=1;
+UPDATE `identities` SET `del`=1 WHERE `del`=2;
+UPDATE `identities` SET `standard`=0 WHERE `standard`=1;
+UPDATE `identities` SET `standard`=1 WHERE `standard`=2;
+
+CREATE TABLE `messages` (
+ `message_id` int(11) unsigned NOT NULL auto_increment,
+ `user_id` int(11) unsigned NOT NULL default '0',
+ `del` tinyint(1) NOT NULL default '0',
+ `cache_key` varchar(128) NOT NULL default '',
+ `idx` int(11) unsigned NOT NULL default '0',
+ `uid` int(11) unsigned NOT NULL default '0',
+ `subject` varchar(255) NOT NULL default '',
+ `from` varchar(255) NOT NULL default '',
+ `to` varchar(255) NOT NULL default '',
+ `cc` varchar(255) NOT NULL default '',
+ `date` datetime NOT NULL default '0000-00-00 00:00:00',
+ `size` int(11) unsigned NOT NULL default '0',
+ `headers` text NOT NULL,
+ `body` longtext,
+ PRIMARY KEY (`message_id`),
+ KEY `user_id` (`user_id`),
+ KEY `cache_key` (`cache_key`),
+ KEY `idx` (`idx`),
+ KEY `uid` (`uid`)
+) TYPE=MyISAM;
diff --git a/SQL/postgres.initial.sql b/SQL/postgres.initial.sql
index 29c134d14..4e74a222f 100755
--- a/SQL/postgres.initial.sql
+++ b/SQL/postgres.initial.sql
@@ -1,255 +1,223 @@
--
--- PostgreSQL database dump
---
-
-SET client_encoding = 'UNICODE';
-SET check_function_bodies = false;
-SET search_path = public, pg_catalog;
-
-ALTER TABLE ONLY public.identities DROP CONSTRAINT "$1";
-ALTER TABLE ONLY public.contacts DROP CONSTRAINT "$1";
-ALTER TABLE ONLY public."cache" DROP CONSTRAINT "$2";
-ALTER TABLE ONLY public."cache" DROP CONSTRAINT "$1";
-ALTER TABLE ONLY public.users DROP CONSTRAINT users_pkey;
-ALTER TABLE ONLY public."session" DROP CONSTRAINT session_pkey;
-ALTER TABLE ONLY public.identities DROP CONSTRAINT identities_pkey;
-ALTER TABLE ONLY public.contacts DROP CONSTRAINT contacts_pkey;
-ALTER TABLE ONLY public."cache" DROP CONSTRAINT cache_pkey;
-DROP TABLE public.users;
-DROP TABLE public."session";
-DROP TABLE public.identities;
-DROP TABLE public.contacts;
-DROP TABLE public."cache";
-DROP SEQUENCE public.user_ids;
-DROP SEQUENCE public.identity_ids;
-DROP SEQUENCE public.contact_ids;
-DROP SEQUENCE public.cache_ids;
---
--- TOC entry 4 (OID 15282470)
--- Name: cache_ids; Type: SEQUENCE; Schema: public; Owner: postgres
+-- Table "users"
+-- Name: users; Type: TABLE; Schema: public; Owner: postgres
--
-CREATE SEQUENCE cache_ids
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-
---
--- TOC entry 5 (OID 15282472)
--- Name: contact_ids; Type: SEQUENCE; Schema: public; Owner: postgres
---
+CREATE TABLE users (
+ user_id integer DEFAULT nextval('user_ids'::text) NOT NULL,
+ username character varying(128) DEFAULT ''::character varying NOT NULL,
+ mail_host character varying(128) DEFAULT ''::character varying NOT NULL,
+ alias character varying(128) DEFAULT ''::character varying NOT NULL,
+ created timestamp with time zone DEFAULT now() NOT NULL,
+ last_login timestamp with time zone DEFAULT now() NOT NULL,
+ "language" character varying(5) DEFAULT 'en'::character varying NOT NULL,
+ preferences text DEFAULT ''::text NOT NULL
+);
-CREATE SEQUENCE contact_ids
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
--
--- TOC entry 6 (OID 15282474)
--- Name: identity_ids; Type: SEQUENCE; Schema: public; Owner: postgres
+-- Table "session"
+-- Name: session; Type: TABLE; Schema: public; Owner: postgres
--
-CREATE SEQUENCE identity_ids
- START WITH 1
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
-
-
---
--- TOC entry 7 (OID 15282476)
--- Name: user_ids; Type: SEQUENCE; Schema: public; Owner: postgres
---
+CREATE TABLE "session" (
+ sess_id character varying(40) DEFAULT ''::character varying NOT NULL,
+ created timestamp with time zone DEFAULT now() NOT NULL,
+ changed timestamp with time zone DEFAULT now() NOT NULL,
+ ip character varying(16) NOT NULL,
+ vars text NOT NULL
+);
-CREATE SEQUENCE user_ids
- INCREMENT BY 1
- NO MAXVALUE
- NO MINVALUE
- CACHE 1;
--
--- TOC entry 8 (OID 15282478)
--- Name: cache; Type: TABLE; Schema: public; Owner: postgres
+-- Table "identities"
+-- Name: identities; Type: TABLE; Schema: public; Owner: postgres
--
-CREATE TABLE "cache" (
- cache_id integer DEFAULT nextval('cache_ids'::text) NOT NULL,
+CREATE TABLE identities (
+ identity_id integer DEFAULT nextval('identity_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
- session_id character varying(32),
- cache_key character varying(128) DEFAULT ''::character varying NOT NULL,
- created timestamp with time zone DEFAULT now() NOT NULL,
- data text NOT NULL
+ del integer DEFAULT 0 NOT NULL,
+ standard integer DEFAULT 0 NOT NULL,
+ name character varying(128) NOT NULL,
+ organization character varying(128),
+ email character varying(128) NOT NULL,
+ "reply-to" character varying(128),
+ bcc character varying(128),
+ signature text
);
--
--- TOC entry 10 (OID 15282486)
+-- Table "contacts"
-- Name: contacts; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE contacts (
contact_id integer DEFAULT nextval('contact_ids'::text) NOT NULL,
user_id integer DEFAULT 0 NOT NULL,
- del boolean DEFAULT false NOT NULL,
+ changed timestamp with time zone DEFAULT now() NOT NULL,
+ del integer DEFAULT 0 NOT NULL,
name character varying(128) DEFAULT ''::character varying NOT NULL,
email character varying(128) DEFAULT ''::character varying NOT NULL,
firstname character varying(128) DEFAULT ''::character varying NOT NULL,
surname character varying(128) DEFAULT ''::character varying NOT NULL,
- vcard text NOT NULL
+ vcard text
);
---
--- TOC entry 11 (OID 15282494)
--- Name: identities; Type: TABLE; Schema: public; Owner: postgres
---
-
-CREATE TABLE identities (
- identity_id integer DEFAULT nextval('identity_ids'::text) NOT NULL,
- user_id integer DEFAULT 0 NOT NULL,
- del boolean DEFAULT false NOT NULL,
- "default" boolean DEFAULT false NOT NULL,
- name character varying(128) NOT NULL,
- organization character varying(128),
- email character varying(128) NOT NULL,
- "reply-to" character varying(128),
- bcc character varying(128),
- signature text
-);
-
--
--- TOC entry 12 (OID 15282503)
--- Name: session; Type: TABLE; Schema: public; Owner: postgres
+-- Table "cache"
+-- Name: cache; Type: TABLE; Schema: public; Owner: postgres
--
-CREATE TABLE "session" (
- sess_id character varying(32) DEFAULT ''::character varying NOT NULL,
+CREATE TABLE "cache" (
+ cache_id integer DEFAULT nextval('cache_ids'::text) NOT NULL,
+ user_id integer DEFAULT 0 NOT NULL,
+ session_id character varying(40),
+ cache_key character varying(128) DEFAULT ''::character varying NOT NULL,
created timestamp with time zone DEFAULT now() NOT NULL,
- changed timestamp with time zone DEFAULT now() NOT NULL,
- ip character varying(16) NOT NULL,
- vars text NOT NULL
+ data text NOT NULL
);
+
--
--- TOC entry 13 (OID 15282510)
--- Name: users; Type: TABLE; Schema: public; Owner: postgres
+-- Table "messages"
+-- Name: messages; Type: TABLE; Schema: public; Owner: postgres
--
-CREATE TABLE users (
- user_id integer DEFAULT nextval('user_ids'::text) NOT NULL,
- username character varying(128) DEFAULT ''::character varying NOT NULL,
- mail_host character varying(128) DEFAULT ''::character varying NOT NULL,
- alias character varying(128) DEFAULT ''::character varying NOT NULL,
- created timestamp with time zone DEFAULT now() NOT NULL,
- last_login timestamp with time zone DEFAULT now() NOT NULL,
- "language" character varying(5) DEFAULT 'en'::character varying NOT NULL,
- preferences text DEFAULT ''::text NOT NULL
+CREATE TABLE "messages" (
+ message_id integer DEFAULT nextval('message_ids'::text) NOT NULL,
+ user_id integer DEFAULT 0 NOT NULL,
+ del integer DEFAULT 0 NOT NULL,
+ cache_key character varying(128) DEFAULT ''::character varying NOT NULL,
+ idx integer DEFAULT 0 NOT NULL,
+ uid integer DEFAULT 0 NOT NULL,
+ subject character varying(128) DEFAULT ''::character varying NOT NULL,
+ "from" character varying(128) DEFAULT ''::character varying NOT NULL,
+ "to" character varying(128) DEFAULT ''::character varying NOT NULL,
+ cc character varying(128) DEFAULT ''::character varying NOT NULL,
+ date timestamp with time zone NOT NULL,
+ size integer DEFAULT 0 NOT NULL,
+ headers text NOT NULL,
+ body text
);
+
--
--- TOC entry 14 (OID 15282518)
--- Name: cache_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+-- Add primary keys
--
ALTER TABLE ONLY "cache"
ADD CONSTRAINT cache_pkey PRIMARY KEY (cache_id);
---
--- TOC entry 15 (OID 15282520)
--- Name: contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
---
-
-ALTER TABLE ONLY contacts
+ALTER TABLE ONLY "contacts"
ADD CONSTRAINT contacts_pkey PRIMARY KEY (contact_id);
---
--- TOC entry 16 (OID 15282522)
--- Name: identities_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
---
-
ALTER TABLE ONLY identities
ADD CONSTRAINT identities_pkey PRIMARY KEY (identity_id);
---
--- TOC entry 17 (OID 15282524)
--- Name: session_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
---
-
ALTER TABLE ONLY "session"
ADD CONSTRAINT session_pkey PRIMARY KEY (sess_id);
---
--- TOC entry 18 (OID 15282526)
--- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
---
-
-ALTER TABLE ONLY users
+ALTER TABLE ONLY "users"
ADD CONSTRAINT users_pkey PRIMARY KEY (user_id);
+ALTER TABLE ONLY "messages"
+ ADD CONSTRAINT messages_pkey PRIMARY KEY (message_id);
+
+
--
--- TOC entry 19 (OID 15282528)
--- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+-- Reference keys
--
ALTER TABLE ONLY "cache"
ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
+ALTER TABLE ONLY "cache"
+ ADD CONSTRAINT "$2" FOREIGN KEY (session_id) REFERENCES "session"(sess_id);
+
+
+ALTER TABLE ONLY "contacts"
+ ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
+
+
+ALTER TABLE ONLY "identities"
+ ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
+
+
+ALTER TABLE ONLY "messages"
+ ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
+
--
--- TOC entry 20 (OID 15282532)
--- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+-- Sequence "cache_ids"
+-- Name: cache_ids; Type: SEQUENCE; Schema: public; Owner: postgres
--
-ALTER TABLE ONLY "cache"
- ADD CONSTRAINT "$2" FOREIGN KEY (session_id) REFERENCES "session"(sess_id);
+CREATE SEQUENCE cache_ids
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
--
--- TOC entry 21 (OID 15282536)
--- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+-- Sequence "contact_ids"
+-- Name: contact_ids; Type: SEQUENCE; Schema: public; Owner: postgres
--
-ALTER TABLE ONLY contacts
- ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
+CREATE SEQUENCE contact_ids
+ START WITH 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
--
--- TOC entry 22 (OID 15282540)
--- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+-- Sequence "identity_ids"
+-- Name: identity_ids; Type: SEQUENCE; Schema: public; Owner: postgres
--
-ALTER TABLE ONLY identities
- ADD CONSTRAINT "$1" FOREIGN KEY (user_id) REFERENCES users(user_id);
-
+CREATE SEQUENCE identity_ids
+ START WITH 1
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
-SET SESSION AUTHORIZATION 'postgres';
--
--- TOC entry 3 (OID 15282469)
--- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres
+-- Sequence "user_ids"
+-- Name: user_ids; Type: SEQUENCE; Schema: public; Owner: postgres
--
-COMMENT ON SCHEMA public IS 'Standard public schema';
-
+CREATE SEQUENCE user_ids
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
-SET SESSION AUTHORIZATION 'postgres';
--
--- TOC entry 9 (OID 15282478)
--- Name: TABLE "cache"; Type: COMMENT; Schema: public; Owner: postgres
--- \ No newline at end of file
+-- Sequence "message_ids"
+-- Name: message_ids; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE message_ids
+ INCREMENT BY 1
+ NO MAXVALUE
+ NO MINVALUE
+ CACHE 1;
+
diff --git a/SQL/sqlite.initial.sql b/SQL/sqlite.initial.sql
index 01f51d6a8..19ca6a578 100644
--- a/SQL/sqlite.initial.sql
+++ b/SQL/sqlite.initial.sql
@@ -11,7 +11,7 @@
CREATE TABLE cache (
cache_id integer NOT NULL PRIMARY KEY,
user_id integer NOT NULL default 0,
- session_id varchar(32) default NULL,
+ session_id varchar(40) default NULL,
cache_key varchar(128) NOT NULL default '',
created datetime NOT NULL default '0000-00-00 00:00:00',
data longtext NOT NULL
@@ -21,6 +21,7 @@ CREATE INDEX ix_cache_user_id ON cache(user_id);
CREATE INDEX ix_cache_cache_key ON cache(cache_key);
CREATE INDEX ix_cache_session_id ON cache(session_id);
+
-- --------------------------------------------------------
--
@@ -30,7 +31,8 @@ CREATE INDEX ix_cache_session_id ON cache(session_id);
CREATE TABLE contacts (
contact_id integer NOT NULL PRIMARY KEY,
user_id integer NOT NULL default '0',
- del integer NOT NULL default '0',
+ created datetime NOT NULL default '0000-00-00 00:00:00',
+ del tinyint NOT NULL default '0',
name varchar(128) NOT NULL default '',
email varchar(128) NOT NULL default '',
firstname varchar(128) NOT NULL default '',
@@ -49,10 +51,10 @@ CREATE INDEX ix_contacts_user_id ON contacts(user_id);
CREATE TABLE identities (
identity_id integer NOT NULL PRIMARY KEY,
user_id integer NOT NULL default '0',
- del integer NOT NULL default '0',
- "default" integer NOT NULL default '0',
+ del tinyint NOT NULL default '0',
+ standard tinyint NOT NULL default '0',
name varchar(128) NOT NULL default '',
- organization varchar(128) NOT NULL default '',
+ organization varchar(128) default '',
email varchar(128) NOT NULL default '',
"reply-to" varchar(128) NOT NULL default '',
bcc varchar(128) NOT NULL default '',
@@ -78,3 +80,45 @@ CREATE TABLE users (
language varchar(5) NOT NULL default 'en',
preferences text NOT NULL default ''
);
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table session
+--
+
+CREATE TABLE session (
+ sess_id varchar(40) NOT NULL PRIMARY KEY,
+ created datetime NOT NULL default '0000-00-00 00:00:00',
+ changed datetime NOT NULL default '0000-00-00 00:00:00',
+ ip varchar(15) NOT NULL default '',
+ vars text NOT NULL
+);
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table messages
+--
+
+CREATE TABLE messages (
+ message_id integer NOT NULL PRIMARY KEY,
+ user_id integer NOT NULL default '0',
+ del tinyint NOT NULL default '0',
+ cache_key varchar(128) NOT NULL default '',
+ idx integer NOT NULL default '0',
+ uid integer NOT NULL default '0',
+ subject varchar(255) NOT NULL default '',
+ "from" varchar(255) NOT NULL default '',
+ "to" varchar(255) NOT NULL default '',
+ cc varchar(255) NOT NULL default '',
+ date datetime NOT NULL default '0000-00-00 00:00:00',
+ size integer NOT NULL default '0',
+ headers text NOT NULL,
+ body text
+);
+
+CREATE INDEX ix_messages_user_id ON messages(user_id);
+CREATE INDEX ix_messages_cache_key ON messages(cache_key);
diff --git a/UPGRADING b/UPGRADING
index 57be50bbf..fbfd47b19 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -10,7 +10,7 @@ from versions 0.1-alpha and 0.1-20050811
- replace index.php
- replace all files in folder /program/
- replace all files in folder /skins/default/
-- rund SQL queries in order to update the database
+- run all commands in SQL/*.update.sql or re-initalize database with *.initial.sql
- add these line to /config/main.inc.php
$rcmail_config['trash_mbox'] = 'Trash';
$rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
@@ -22,9 +22,12 @@ from versions 0.1-alpha and 0.1-20050811
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
+ $rcmail_config['temp_dir'] = 'temp/';
- replace database properties (db_type, db_host, db_user, db_pass, $d_name)
in /config/db.inc.php with the following line:
$rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
+- add these lines to /config/db.inc.php
+ $rcmail_config['db_max_length'] = 512000;
from version 0.1-20050820
@@ -32,7 +35,7 @@ from version 0.1-20050820
- replace index.php
- replace all files in folder /program/
- replace all files in folder /skins/default/
-- rund SQL queries in order to update the database
+- run all commands in SQL/*.update.sql or re-initalize database with *.initial.sql
- add these line to /config/main.inc.php
$rcmail_config['prettydate'] = TRUE;
$rcmail_config['smtp_port'] = 25;
@@ -41,9 +44,12 @@ from version 0.1-20050820
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
+ $rcmail_config['temp_dir'] = 'temp/';
- replace database properties (db_type, db_host, db_user, db_pass, $d_name)
in /config/db.inc.php with the following line:
$rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
+- add these lines to /config/db.inc.php
+ $rcmail_config['db_max_length'] = 512000;
from version 0.1-20051007
@@ -51,20 +57,38 @@ from version 0.1-20051007
- replace index.php
- replace all files in folder /program/
- replace all files in folder /skins/default/
+- run all commands in SQL/*.update.sql or re-initalize database with *.initial.sql
- add these lines to /config/main.inc.php
$rcmail_config['smtp_auth_type'] = ''; // if you need to specify an auth method for SMTP
$rcmail_config['session_lifetime'] = 20; // to specify the session lifetime in minutes
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
-
+ $rcmail_config['temp_dir'] = 'temp/';
+- add these lines to /config/db.inc.php
+ $rcmail_config['db_max_length'] = 512000;
+ $rcmail_config['db_sequence_user_ids'] = 'user_ids';
+ $rcmail_config['db_sequence_identity_ids'] = 'identity_ids';
+ $rcmail_config['db_sequence_contact_ids'] = 'contact_ids';
+ $rcmail_config['db_sequence_cache_ids'] = 'cache_ids';
+ $rcmail_config['db_sequence_message_ids'] = 'message_ids';
+
from version 0.1-20051021
----------------------------------------
- replace index.php
- replace all files in folder /program/
- replace all files in folder /skins/default/
+- run all commands in SQL/*.update.sql or re-initalize database with *.initial.sql
- add these lines to /config/main.inc.php
$rcmail_config['message_sort_col'] = 'date';
$rcmail_config['message_sort_order'] = 'DESC';
$rcmail_config['log_dir'] = 'logs/';
+ $rcmail_config['temp_dir'] = 'temp/';
+- add these lines to /config/db.inc.php
+ $rcmail_config['db_max_length'] = 512000;
+ $rcmail_config['db_sequence_user_ids'] = 'user_ids';
+ $rcmail_config['db_sequence_identity_ids'] = 'identity_ids';
+ $rcmail_config['db_sequence_contact_ids'] = 'contact_ids';
+ $rcmail_config['db_sequence_cache_ids'] = 'cache_ids';
+ $rcmail_config['db_sequence_message_ids'] = 'message_ids'; \ No newline at end of file
diff --git a/config/db.inc.php.dist b/config/db.inc.php.dist
index 6db417860..c797168db 100644
--- a/config/db.inc.php.dist
+++ b/config/db.inc.php.dist
@@ -19,6 +19,7 @@ $rcmail_config = array();
// currentyl suported db_providers: mysql, sqlite
$rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail';
+// postgres example: 'pgsql://roundcube:pass@localhost/roundcubemail';
// sqlite example: 'sqlite://./sqlite.db?mode=0646';
// PEAR database DSN for read only operations (if empty write database will be used)
@@ -28,6 +29,9 @@ $rcmail_config['db_dsnr'] = '';
// database backend to use (only db or mdb2 are supported)
$rcmail_config['db_backend'] = 'db';
+// maximum length of a query in bytes
+$rcmail_config['db_max_length'] = 512000; // 500K
+
// you can define specific table names used to store webmail data
$rcmail_config['db_table_users'] = 'users';
@@ -39,6 +43,20 @@ $rcmail_config['db_table_session'] = 'session';
$rcmail_config['db_table_cache'] = 'cache';
+$rcmail_config['db_table_messages'] = 'messages';
+
+
+// you can define specific sequence names used in PostgreSQL
+$rcmail_config['db_sequence_users'] = 'user_ids';
+
+$rcmail_config['db_sequence_identities'] = 'identity_ids';
+
+$rcmail_config['db_sequence_contacts'] = 'contact_ids';
+
+$rcmail_config['db_sequence_cache'] = 'cache_ids';
+
+$rcmail_config['db_sequence_messages'] = 'message_ids';
+
// end db config file
?>
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 6a0ada4c5..ec1614e18 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -88,7 +88,7 @@ $rcmail_config['date_short'] = 'D H:i';
$rcmail_config['date_long'] = 'd.m.Y H:i';
// add this user-agent to message headers when sending
-$rcmail_config['useragent'] = 'RoundCube Webmail/0.1-20051021';
+$rcmail_config['useragent'] = 'RoundCube Webmail/0.1b';
// only list folders within this path
$rcmail_config['imap_root'] = '';
diff --git a/index.php b/index.php
index 16a3540d7..31d4e7574 100644
--- a/index.php
+++ b/index.php
@@ -62,7 +62,7 @@ ini_set('error_reporting', E_ALL&~E_NOTICE);
// increase maximum execution time for php scripts
// (does not work in safe mode)
-@set_time_limit('120');
+@set_time_limit(120);
// include base files
require_once('include/rcube_shared.inc');
@@ -199,6 +199,13 @@ if (!$_SESSION['user_id'])
}
+// handle keep-alive signal
+if ($_action=='keep-alive')
+ {
+ rcube_remote_response('');
+ exit;
+ }
+
// include task specific files
if ($_task=='mail')
@@ -289,14 +296,6 @@ if ($_task=='settings')
}
-// handle keep-alive signal
-if ($_action=='keep-alive')
- {
- rcube_remote_response('');
- exit;
- }
-
-
// only allow these templates to be included
$valid_tasks = array('mail','settings','addressbook');
diff --git a/program/include/cache.inc b/program/include/cache.inc
index 8d088e57b..06e0681ce 100644
--- a/program/include/cache.inc
+++ b/program/include/cache.inc
@@ -43,8 +43,8 @@ function rcube_read_cache($key)
return $data;
}
-
-
+
+
function rcube_write_cache($key, $data, $session_cache=FALSE)
{
global $DB, $CACHE_KEYS, $sess_id;
@@ -91,7 +91,6 @@ function rcube_write_cache($key, $data, $session_cache=FALSE)
}
-
function rcube_clear_cache($key)
{
global $DB;
diff --git a/program/include/main.inc b/program/include/main.inc
index ddb42181a..40ca1d4d7 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -69,7 +69,7 @@ function rcmail_startup($task='mail')
// we can use the database for storing session data
// session queries do not work with MDB2
- if ($CONFIG['db_backend']!='mdb2' && is_object($DB) && $DB->db_provider!='sqlite')
+ if ($CONFIG['db_backend']!='mdb2' && is_object($DB) /* && $DB->db_provider!='sqlite' */)
include_once('include/session.inc');
@@ -143,9 +143,9 @@ function rcmail_auth_hash($sess_id, $ts)
// create IMAP object and connect to server
function rcmail_imap_init($connect=FALSE)
{
- global $CONFIG, $IMAP;
+ global $CONFIG, $DB, $IMAP;
- $IMAP = new rcube_imap();
+ $IMAP = new rcube_imap($DB);
// connect with stored session data
if ($connect)
@@ -227,6 +227,22 @@ function get_table_name($table)
}
+// return correct name for a specific database sequence
+// (used for Postres only)
+function get_sequence_name($sequence)
+ {
+ global $CONFIG;
+
+ // return table name if configured
+ $config_key = 'db_sequence_'.$sequence;
+
+ if (strlen($CONFIG[$config_key]))
+ return $CONFIG[$config_key];
+
+ return $table;
+ }
+
+
// init output object for GUI and add common scripts
function load_gui()
@@ -380,15 +396,15 @@ function rcmail_create_user($user, $host)
$host,
$_SESSION['user_lang']);
- if ($user_id = $DB->insert_id('user_ids'))
+ if ($user_id = $DB->insert_id(get_sequence_name('users')))
{
$user_email = strstr($user, '@') ? $user : sprintf('%s@%s', $user, $host);
$user_name = $user!=$user_email ? $user : '';
// also create a new identity record
$DB->query("INSERT INTO ".get_table_name('identities')."
- (user_id, `default`, name, email)
- VALUES (?, '1', ?, ?)",
+ (user_id, del, standard, name, email)
+ VALUES (?, 0, 1, ?, ?)",
$user_id,
$user_name,
$user_email);
@@ -479,7 +495,6 @@ function decrypt_passwd($cypher)
function rcube_remote_response($js_code)
{
send_nocacheing_headers();
- //header('Content-Type: text/javascript');
header('Content-Type: application/x-javascript');
print '/** remote response ['.date('d/M/Y h:i:s O')."] **/\n";
@@ -530,6 +545,117 @@ function rcube_add_label()
}
+// remove temp files of a session
+function rcmail_clear_session_temp($sess_id)
+ {
+ global $CONFIG;
+
+ $temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '');
+ $cache_dir = $temp_dir.$sess_id;
+
+ if (is_dir($cache_dir))
+ {
+ clear_directory($cache_dir);
+ rmdir($cache_dir);
+ }
+ }
+
+
+
+// replace specials characters to a specific encoding type
+function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
+ {
+ global $OUTPUT_TYPE, $CHARSET;
+ static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table;
+
+ if (!$enctype)
+ $enctype = $GLOBALS['OUTPUT_TYPE'];
+
+ // convert nbsps back to normal spaces if not html
+ if ($enctype!='html')
+ $str = str_replace(chr(160), ' ', $str);
+
+
+ // encode for plaintext
+ if ($enctype=='text')
+ return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
+
+ // encode for HTML output
+ if ($enctype=='html')
+ {
+ if (!$html_encode_arr)
+ {
+ if ($CHARSET=='ISO-8859-1')
+ {
+ $html_encode_arr = get_html_translation_table(HTML_ENTITIES);
+ $html_encode_arr[chr(128)] = '&euro;';
+ }
+ else
+ $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
+
+ unset($html_encode_arr['?']);
+ unset($html_encode_arr['&']);
+ }
+
+ $ltpos = strpos($str, '<');
+ $encode_arr = $html_encode_arr;
+
+ // don't replace quotes and html tags
+ if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
+ {
+ unset($encode_arr['"']);
+ unset($encode_arr['<']);
+ unset($encode_arr['>']);
+ }
+ else if ($mode=='remove')
+ $str = strip_tags($str);
+
+ $out = strtr($str, $encode_arr);
+
+ return $newlines ? nl2br($out) : $out;
+ }
+
+
+ if ($enctype=='url')
+ return rawurlencode($str);
+
+
+ // if the replace tables for RTF, XML and JS are not yet defined
+ if (!$js_rep_table)
+ {
+ $js_rep_table = $rtf_rep_table = $xml_rep_table = array();
+
+ for ($c=160; $c<256; $c++) // can be increased to support more charsets
+ {
+ $hex = dechex($c);
+ $rtf_rep_table[Chr($c)] = "\\'$hex";
+ $xml_rep_table[Chr($c)] = "&#$c;";
+
+ if ($CHARSET=='ISO-8859-1')
+ $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
+ }
+
+ $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34));
+ $xml_rep_table['"'] = '&quot;';
+ }
+
+ // encode for RTF
+ if ($enctype=='xml')
+ return strtr($str, $xml_rep_table);
+
+ // encode for javascript use
+ if ($enctype=='js')
+ return preg_replace(array("/\r\n/", '/"/', "/([^\\\])'/"), array('\n', '\"', "$1\'"), strtr($str, $js_rep_table));
+
+ // encode for RTF
+ if ($enctype=='rtf')
+ return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table));
+
+ // no encoding given -> return original string
+ return $str;
+ }
+
+
// ************** template parsing and gui functions **************
@@ -653,104 +779,53 @@ function rcube_xml_command($command, $str_attrib, $a_attrib=NULL)
case 'object':
$object = strtolower($attrib['name']);
+ $object_handlers = array(
+ // MAIL
+ 'mailboxlist' => 'rcmail_mailbox_list',
+ 'messages' => 'rcmail_message_list',
+ 'messagecountdisplay' => 'rcmail_messagecount_display',
+ 'messageheaders' => 'rcmail_message_headers',
+ 'messagebody' => 'rcmail_message_body',
+ 'messageattachments' => 'rcmail_message_attachments',
+ 'blockedobjects' => 'rcmail_remote_objects_msg',
+ 'messagecontentframe' => 'rcmail_messagecontent_frame',
+ 'messagepartframe' => 'rcmail_message_part_frame',
+ 'messagepartcontrols' => 'rcmail_message_part_controls',
+ 'composeheaders' => 'rcmail_compose_headers',
+ 'composesubject' => 'rcmail_compose_subject',
+ 'composebody' => 'rcmail_compose_body',
+ 'composeattachmentlist' => 'rcmail_compose_attachment_list',
+ 'composeattachmentform' => 'rcmail_compose_attachment_form',
+ 'composeattachment' => 'rcmail_compose_attachment_field',
+ 'priorityselector' => 'rcmail_priority_selector',
+ 'charsetselector' => 'rcmail_charset_selector',
+
+ // ADDRESS BOOK
+ 'addresslist' => 'rcmail_contacts_list',
+ 'addressframe' => 'rcmail_contact_frame',
+ 'recordscountdisplay' => 'rcmail_rowcount_display',
+ 'contactdetails' => 'rcmail_contact_details',
+ 'contacteditform' => 'rcmail_contact_editform',
+
+ // USER SETTINGS
+ 'userprefs' => 'rcmail_user_prefs_form',
+ 'itentitieslist' => 'rcmail_identities_list',
+ 'identityframe' => 'rcmail_identity_frame',
+ 'identityform' => 'rcube_identity_form',
+ 'foldersubscription' => 'rcube_subscription_form',
+ 'createfolder' => 'rcube_create_folder_form',
+ 'composebody' => 'rcmail_compose_body'
+ );
+
if ($object=='loginform')
return rcmail_login_form($attrib);
else if ($object=='message')
return rcmail_message_container($attrib);
-
- // MAIL
- else if ($object=='mailboxlist' && function_exists('rcmail_mailbox_list'))
- return rcmail_mailbox_list($attrib);
-
- else if ($object=='messages' && function_exists('rcmail_message_list'))
- return rcmail_message_list($attrib);
-
- else if ($object=='messagecountdisplay' && function_exists('rcmail_messagecount_display'))
- return rcmail_messagecount_display($attrib);
-
- else if ($object=='messageheaders' && function_exists('rcmail_message_headers'))
- return rcmail_message_headers($attrib);
-
- else if ($object=='messageattachments' && function_exists('rcmail_message_attachments'))
- return rcmail_message_attachments($attrib);
-
- else if ($object=='messagebody' && function_exists('rcmail_message_body'))
- return rcmail_message_body($attrib);
-
- else if ($object=='blockedobjects' && function_exists('rcmail_remote_objects_msg'))
- return rcmail_remote_objects_msg($attrib);
-
- else if ($object=='messagecontentframe' && function_exists('rcmail_messagecontent_frame'))
- return rcmail_messagecontent_frame($attrib);
-
- else if ($object=='messagepartframe' && function_exists('rcmail_message_part_frame'))
- return rcmail_message_part_frame($attrib);
-
- else if ($object=='messagepartcontrols' && function_exists('rcmail_message_part_controls'))
- return rcmail_message_part_controls($attrib);
-
- else if ($object=='composeheaders' && function_exists('rcmail_compose_headers'))
- return rcmail_compose_headers($attrib);
-
- else if ($object=='composesubject' && function_exists('rcmail_compose_subject'))
- return rcmail_compose_subject($attrib);
-
- else if ($object=='composebody' && function_exists('rcmail_compose_body'))
- return rcmail_compose_body($attrib);
-
- else if ($object=='composeattachmentlist' && function_exists('rcmail_compose_attachment_list'))
- return rcmail_compose_attachment_list($attrib);
-
- else if ($object=='composeattachmentform' && function_exists('rcmail_compose_attachment_form'))
- return rcmail_compose_attachment_form($attrib);
-
- else if ($object=='composeattachment' && function_exists('rcmail_compose_attachment_field'))
- return rcmail_compose_attachment_field($attrib);
-
- else if ($object=='priorityselector' && function_exists('rcmail_priority_selector'))
- return rcmail_priority_selector($attrib);
-
- else if ($object=='priorityselector' && function_exists('rcmail_priority_selector'))
- return rcmail_priority_selector($attrib);
-
-
- // ADDRESS BOOK
- else if ($object=='addresslist' && function_exists('rcmail_contacts_list'))
- return rcmail_contacts_list($attrib);
-
- else if ($object=='addressframe' && function_exists('rcmail_contact_frame'))
- return rcmail_contact_frame($attrib);
-
- else if ($object=='recordscountdisplay' && function_exists('rcmail_rowcount_display'))
- return rcmail_rowcount_display($attrib);
-
- else if ($object=='contactdetails' && function_exists('rcmail_contact_details'))
- return rcmail_contact_details($attrib);
-
- else if ($object=='contacteditform' && function_exists('rcmail_contact_editform'))
- return rcmail_contact_editform($attrib);
-
-
- // USER SETTINGS
- else if ($object=='userprefs' && function_exists('rcmail_user_prefs_form'))
- return rcmail_user_prefs_form($attrib);
-
- else if ($object=='itentitieslist' && function_exists('rcmail_identities_list'))
- return rcmail_identities_list($attrib);
-
- else if ($object=='identityframe' && function_exists('rcmail_identity_frame'))
- return rcmail_identity_frame($attrib);
-
- else if ($object=='identityform' && function_exists('rcube_identity_form'))
- return rcube_identity_form($attrib);
-
- else if ($object=='foldersubscription' && function_exists('rcube_subscription_form'))
- return rcube_subscription_form($attrib);
-
- else if ($object=='createfolder' && function_exists('rcube_create_folder_form'))
- return rcube_create_folder_form($attrib);
-
+
+ // execute object handler function
+ else if ($object_handlers[$object] && function_exists($object_handlers[$object]))
+ return call_user_func($object_handlers[$object], $attrib);
else if ($object=='pagetitle')
{
@@ -878,7 +953,7 @@ function rcube_button($attrib)
// generate image tag
if ($attrib['type']=='image')
{
- $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'alt'));
+ $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'align', 'alt'));
$img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
$btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
if ($attrib['label'])
@@ -1161,4 +1236,39 @@ EOF;
}
+
+function rcmail_charset_selector($attrib)
+ {
+ // pass the following attributes to the form class
+ $field_attrib = array('name' => '_charset');
+ foreach ($attrib as $attr => $value)
+ if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
+ $field_attrib[$attr] = $value;
+
+ $charsets = array(
+ 'US-ASCII' => 'ASCII (English)',
+ 'X-EUC-JP' => 'EUC-JP (Japanese)',
+ 'EUC-KR' => 'EUC-KR (Korean)',
+ 'BIG5' => 'BIG5 (Chinese)',
+ 'GB2312' => 'GB2312 (Chinese)',
+ 'ISO-8859-1' => 'ISO-8859-1 (Latin-1)',
+ 'ISO-8859-2' => 'ISO-8895-2 (Central European)',
+ 'ISO-8859-7' => 'ISO-8859-7 (Greek)',
+ 'ISO-8859-9' => 'ISO-8859-9 (Turkish)',
+ 'Windows-1251' => 'Windows-1251 (Cyrillic)',
+ 'Windows-1252' => 'Windows-1252 (Western)',
+ 'Windows-1255' => 'Windows-1255 (Hebrew)',
+ 'Windows-1256' => 'Windows-1256 (Arabic)',
+ 'Windows-1257' => 'Windows-1257 (Baltic)',
+ 'UTF-8' => 'UTF-8'
+ );
+
+ $select = new select($field_attrib);
+ $select->add(array_values($charsets), array_keys($charsets));
+
+ $set = $_POST['_charset'] ? $_POST['_charset'] : $GLOBALS['CHARSET'];
+ return $select->show($set);
+ }
+
+
?> \ No newline at end of file
diff --git a/program/include/rcube_db.inc b/program/include/rcube_db.inc
index f13ab55c0..acb13ce37 100755
--- a/program/include/rcube_db.inc
+++ b/program/include/rcube_db.inc
@@ -23,299 +23,332 @@
require_once('DB.php');
class rcube_db
-{
- var $db_dsnw; // DSN for write operations
- var $db_dsnr; // DSN for read operations
- var $db_connected=false; // Already connected ?
- var $db_mode=''; // Connection mode
- var $db_handle=0; // Connection handle
-
- var $a_query_results = array('dummy');
- var $last_res_id = 0;
-
- // PHP 5 constructor
- function __construct($db_dsnw,$db_dsnr='')
+ {
+ var $db_dsnw; // DSN for write operations
+ var $db_dsnr; // DSN for read operations
+ var $db_connected = false; // Already connected ?
+ var $db_mode = ''; // Connection mode
+ var $db_handle = 0; // Connection handle
+
+ var $a_query_results = array('dummy');
+ var $last_res_id = 0;
+
+
+ // PHP 5 constructor
+ function __construct($db_dsnw,$db_dsnr='')
{
- if ($db_dsnr=='') $db_dsnr=$db_dsnw;
+ if ($db_dsnr=='')
+ $db_dsnr=$db_dsnw;
- $this->db_dsnw = $db_dsnw;
- $this->db_dsnr = $db_dsnr;
+ $this->db_dsnw = $db_dsnw;
+ $this->db_dsnr = $db_dsnr;
- $dsn_array = DB::parseDSN($db_dsnw);
- $this->db_provider = $dsn_array['phptype'];
+ $dsn_array = DB::parseDSN($db_dsnw);
+ $this->db_provider = $dsn_array['phptype'];
}
- // PHP 4 compatibility
- function rcube_db($db_dsnw,$db_dsnr='')
+
+ // PHP 4 compatibility
+ function rcube_db($db_dsnw,$db_dsnr='')
{
- $this->__construct($db_dsnw,$db_dsnr);
+ $this->__construct($db_dsnw,$db_dsnr);
}
- // Connect to specific database
- function dsn_connect($dsn)
+
+ // Connect to specific database
+ function dsn_connect($dsn)
{
- // Use persistent connections if available
- $dbh = DB::connect($dsn, array('persistent' => $true));
+ // Use persistent connections if available
+ $dbh = DB::connect($dsn, array('persistent' => TRUE));
- if (DB::isError($dbh))
- raise_error(array('code' => 500,
+ if (DB::isError($dbh))
+ raise_error(array('code' => 500,
'type' => 'db',
'line' => __LINE__,
'file' => __FILE__,
'message' => $dbh->getMessage()), TRUE, FALSE);
- else if ($this->db_provider=='sqlite')
- {
- $dsn_array = DB::parseDSN($dsn);
- if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials))
- $this->_sqlite_create_database($dbh, $this->sqlite_initials);
- }
+ else if ($this->db_provider=='sqlite')
+ {
+ $dsn_array = DB::parseDSN($dsn);
+ if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials))
+ $this->_sqlite_create_database($dbh, $this->sqlite_initials);
+ }
- return $dbh;
+ return $dbh;
}
- // Connect to appropiate databse
- function db_connect ($mode)
- {
- $this->db_mode = $mode;
- // Already connected
- if ($this->db_connected)
- {
- // no replication, current connection is ok
- if ($this->db_dsnw==$this->db_dsnr) return;
+ // Connect to appropiate databse
+ function db_connect ($mode)
+ {
+ $this->db_mode = $mode;
+
+ // Already connected
+ if ($this->db_connected)
+ {
+ // no replication, current connection is ok
+ if ($this->db_dsnw==$this->db_dsnr)
+ return;
- // connected to master, current connection is ok
- if ($this->db_mode=='w') return;
-
- // Same mode, current connection is ok
- if ($this->db_mode==$mode) return;
- }
+ // connected to master, current connection is ok
+ if ($this->db_mode=='w')
+ return;
+
+ // Same mode, current connection is ok
+ if ($this->db_mode==$mode)
+ return;
+ }
- if ($mode=='r')
- $dsn=$this->db_dsnr;
- else
- $dsn=$this->db_dsnw;
+ if ($mode=='r')
+ $dsn = $this->db_dsnr;
+ else
+ $dsn = $this->db_dsnw;
- $this->db_handle = $this->dsn_connect($dsn);
- $this->db_connected = true;
+ $this->db_handle = $this->dsn_connect($dsn);
+ $this->db_connected = true;
}
- // Query database
-
- function query()
+
+ // Query database
+ function query()
{
- $params = func_get_args();
- $query = array_shift($params);
-
- return $this->_query($query, 0, 0, $params);
+ $params = func_get_args();
+ $query = array_shift($params);
+
+ return $this->_query($query, 0, 0, $params);
}
-
- function limitquery()
+
+
+ // Query with limits
+ function limitquery()
{
- $params = func_get_args();
- $query = array_shift($params);
- $offset = array_shift($params);
- $numrows = array_shift($params);
+ $params = func_get_args();
+ $query = array_shift($params);
+ $offset = array_shift($params);
+ $numrows = array_shift($params);
- return $this->_query($query, $offset, $numrows, $params);
+ return $this->_query($query, $offset, $numrows, $params);
}
-
- function _query($query, $offset, $numrows, $params)
+
+
+ function _query($query, $offset, $numrows, $params)
{
- // Read or write ?
- if (strtolower(trim(substr($query,0,6)))=='select')
- $mode='r';
- else
- $mode='w';
+ // Read or write ?
+ if (strtolower(trim(substr($query,0,6)))=='select')
+ $mode='r';
+ else
+ $mode='w';
- $this->db_connect($mode);
+ $this->db_connect($mode);
- if ($this->db_provider == 'sqlite')
- $query = $this->_sqlite_prepare_query($query);
-
- if ($numrows || $offset)
- {
- $result = $this->db_handle->limitQuery($query,$offset,$numrows,$params);
- }
- else
- $result = $this->db_handle->query($query, $params);
+ if ($this->db_provider == 'sqlite')
+ $this->_sqlite_prepare();
- if (DB::isError($result))
- {
- raise_error(array('code' => 500,
- 'type' => 'db',
- 'line' => __LINE__,
- 'file' => __FILE__,
- 'message' => $result->getMessage().'; QUERY: '.$query), TRUE, FALSE);
- return false;
- }
-
- return $this->_add_result($result, $query);
+ if ($numrows || $offset)
+ $result = $this->db_handle->limitQuery($query,$offset,$numrows,$params);
+ else
+ $result = $this->db_handle->query($query, $params);
+
+ // add result, even if it's an error
+ return $this->_add_result($result);
}
-
- function num_rows($res_id=NULL)
+
+
+ function num_rows($res_id=NULL)
{
- if (!$this->db_handle)
- return FALSE;
+ if (!$this->db_handle)
+ return FALSE;
- $result = $this->_get_result($res_id);
-
- if ($result)
- return $result->numRows();
- else
- return FALSE;
+ if ($result = $this->_get_result($res_id))
+ return $result->numRows();
+ else
+ return FALSE;
}
- function affected_rows($res_id=NULL)
+
+ function affected_rows($res_id=NULL)
{
- if (!$this->db_handle)
- return FALSE;
-
- return $this->db_handle->affectedRows();
+ if (!$this->db_handle)
+ return FALSE;
+
+ return $this->db_handle->affectedRows();
}
- function insert_id($sequence = '')
+
+ function insert_id($sequence = '')
{
- if (!$this->db_handle || $this->db_mode=='r')
- return FALSE;
-
- switch($this->db_provider)
- {
- case 'pgsql':
- // PostgreSQL uses sequences
- $result =& $this->db_handle->getOne("SELECT CURRVAL('$sequence')");
- if (DB::isError($result)) {
- raise_error( array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $result->getMessage()), TRUE, TRUE);
- }
- return $result;
+ if (!$this->db_handle || $this->db_mode=='r')
+ return FALSE;
+
+ switch($this->db_provider)
+ {
+ case 'pgsql':
+ // PostgreSQL uses sequences
+ $result =& $this->db_handle->getOne("SELECT CURRVAL('$sequence')");
+ if (DB::isError($result))
+ raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $result->getMessage()), TRUE, FALSE);
+
+ return $result;
- case 'mysql': // This is unfortuneate
- return mysql_insert_id($this->db_handle->connection);
+ case 'mysql': // This is unfortuneate
+ return mysql_insert_id($this->db_handle->connection);
- case 'mysqli':
- return mysqli_insert_id($this->db_handle->connection);
+ case 'mysqli':
+ return mysqli_insert_id($this->db_handle->connection);
- case 'sqlite':
- return sqlite_last_insert_rowid($this->db_handle->connection);
+ case 'sqlite':
+ return sqlite_last_insert_rowid($this->db_handle->connection);
- default:
- die("portability issue with this database, please have the developer fix");
- }
+ default:
+ die("portability issue with this database, please have the developer fix");
+ }
}
- function fetch_assoc($res_id=NULL)
+ function fetch_assoc($res_id=NULL)
{
- $result = $this->_get_result($res_id);
-
- if (DB::isError($result))
- {
- raise_error( array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_link->getMessage()), TRUE, FALSE);
- return FALSE;
- }
+ $result = $this->_get_result($res_id);
+
+ if (DB::isError($result))
+ {
+ raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $this->db_link->getMessage()), TRUE, FALSE);
+ return FALSE;
+ }
- return $result->fetchRow(DB_FETCHMODE_ASSOC);
+ return $result->fetchRow(DB_FETCHMODE_ASSOC);
}
- function quote($input, $type=null)
+ function quote($input, $type=null)
{
- if (!$this->db_handle)
- $this->db_connect('r');
+ if (!$this->db_handle)
+ $this->db_connect('r');
- return $this->db_handle->quote($input);
+ return $this->db_handle->quote($input);
}
- function quoteIdentifier($str)
+ function quoteIdentifier($str)
{
- if (!$this->db_handle)
- $this->db_connect('r');
+ if (!$this->db_handle)
+ $this->db_connect('r');
- return $this->db_handle->quoteIdentifier($str);
- }
-
- function quote_identifier($str)
- {
- return $this->quoteIdentifier($str);
+ return $this->db_handle->quoteIdentifier($str);
}
-
- function unixtimestamp($field)
- {
- switch($this->db_provider)
- {
- case 'pgsql':
- return "EXTRACT (EPOCH FROM $field)";
- break;
- default:
- return "UNIX_TIMESTAMP($field)";
- }
- }
-
- function _add_result($res, $query)
+
+ function quote_identifier($str)
+ {
+ return $this->quoteIdentifier($str);
+ }
+
+
+ function unixtimestamp($field)
{
- // sql error occured
- if (DB::isError($res))
- {
- raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, 'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $query), 0, 1024)), TRUE, FALSE);
- return FALSE;
- }
- else
- {
- $res_id = sizeof($this->a_query_results);
- $this->a_query_results[$res_id] = $res;
- $this->last_res_id = $res_id;
- return $res_id;
- }
+ switch($this->db_provider)
+ {
+ case 'pgsql':
+ return "EXTRACT (EPOCH FROM $field)";
+ break;
+
+ default:
+ return "UNIX_TIMESTAMP($field)";
+ }
}
- function _get_result($res_id)
+ function fromunixtime($timestamp)
{
- if ($res_id==NULL)
- $res_id = $this->last_res_id;
+ switch($this->db_provider)
+ {
+ case 'mysqli':
+ case 'mysql':
+ case 'sqlite':
+ return "FROM_UNIXTIME($timestamp)";
+
+ default:
+ return date("'Y-m-d H:i:s'", $timestamp);
+ }
+ }
+
+
+ function _add_result($res)
+ {
+ // sql error occured
+ if (DB::isError($res))
+ {
+ raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $res->getMessage() . " Query: " . substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 1024)), TRUE, FALSE);
+ return FALSE;
+ }
+ else
+ {
+ $res_id = sizeof($this->a_query_results);
+ $this->a_query_results[$res_id] = $res;
+ $this->last_res_id = $res_id;
+ return $res_id;
+ }
+ }
+
+
+ function _get_result($res_id)
+ {
+ if ($res_id==NULL)
+ $res_id = $this->last_res_id;
- if ($res_id && isset($this->a_query_results[$res_id]))
- return $this->a_query_results[$res_id];
- else
- return FALSE;
+ if ($res_id && isset($this->a_query_results[$res_id]))
+ return $this->a_query_results[$res_id];
+ else
+ return FALSE;
}
- // create a sqlite database from a file
- function _sqlite_create_database($dbh, $fileName)
+ // create a sqlite database from a file
+ function _sqlite_create_database($dbh, $fileName)
{
- if (empty($fileName) || !is_string($fileName))
- return ;
-
- $data = '';
- if ($fd = fopen($fileName, 'r'))
- {
- $data = fread($fd, filesize($fileName));
- fclose($fd);
- }
-
- if (strlen($data))
- sqlite_exec($dbh->connection, $data);
+ if (empty($fileName) || !is_string($fileName))
+ return ;
+
+ $data = '';
+ if ($fd = fopen($fileName, 'r'))
+ {
+ $data = fread($fd, filesize($fileName));
+ fclose($fd);
+ }
+
+ if (strlen($data))
+ sqlite_exec($dbh->connection, $data);
}
- // transform a query so that it is sqlite2 compliant
- function _sqlite_prepare_query($query)
+ function _sqlite_prepare()
{
- if (!is_string($query))
- return ($query);
-
- $search = array('/NOW\(\)/i', '/`/');
- $replace = array("datetime('now')", '"');
- $query = preg_replace($search, $replace, $query);
+ include_once('include/rcube_sqlite.inc');
- return ($query);
+ // we emulate via callback some missing MySQL function
+ sqlite_create_function($this->db_handle->connection, "from_unixtime", "rcube_sqlite_from_unixtime");
+ sqlite_create_function($this->db_handle->connection, "unix_timestamp", "rcube_sqlite_unix_timestamp");
+ sqlite_create_function($this->db_handle->connection, "now", "rcube_sqlite_now");
+ sqlite_create_function($this->db_handle->connection, "md5", "rcube_sqlite_md5");
}
-
-}
+
+/*
+ // transform a query so that it is sqlite2 compliant
+ function _sqlite_prepare_query($query)
+ {
+ if (!is_string($query))
+ return ($query);
+
+
+ $search = array('/NOW\(\)/i', '/`/');
+ $replace = array("datetime('now')", '"');
+ $query = preg_replace($search, $replace, $query);
+
+ return ($query);
+ }
+*/
+ } // end class rcube_db
?> \ No newline at end of file
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index 2237b38f3..ed7c3edcd 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -28,6 +28,7 @@ require_once('lib/utf7.inc');
class rcube_imap
{
+ var $db;
var $conn;
var $root_ns = '';
var $root_dir = '';
@@ -38,21 +39,23 @@ class rcube_imap
var $caching_enabled = FALSE;
var $default_folders = array('inbox', 'drafts', 'sent', 'junk', 'trash');
var $cache = array();
+ var $cache_keys = array();
var $cache_changes = array();
var $uid_id_map = array();
var $msg_headers = array();
+ var $capabilities = array();
// PHP 5 constructor
- function __construct()
+ function __construct($db_conn)
{
-
+ $this->db = $db_conn;
}
// PHP 4 compatibility
- function rcube_imap()
+ function rcube_imap($db_conn)
{
- $this->__construct();
+ $this->__construct($db_conn);
}
@@ -95,6 +98,7 @@ class rcube_imap
// get account namespace
if ($this->conn)
{
+ $this->_parse_capability($this->conn->capability);
iil_C_NameSpace($this->conn);
if (!empty($this->conn->delimiter))
@@ -185,6 +189,13 @@ class rcube_imap
}
+ function get_capability($cap)
+ {
+ $cap = strtoupper($cap);
+ return $this->capabilities[$cap];
+ }
+
+
function get_hierarchy_delimiter()
{
if ($this->conn && empty($this->delimiter))
@@ -298,200 +309,131 @@ class rcube_imap
// private method for listing message header
- // by DrSlump <drslump@drslump.biz>
- function __list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
+ function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
{
- $a_out = array();
- $cached_count = 0;
-
if (!strlen($mailbox))
- return $a_out;
+ return array();
+
+ $max = $this->_messagecount($mailbox);
+ $start_msg = ($this->list_page-1) * $this->page_size;
+
+ if ($page=='all')
+ {
+ $begin = 0;
+ $end = $max;
+ }
+ else if ($sort_order=='DESC')
+ {
+ $begin = $max - $this->page_size - $start_msg;
+ $end = $max - $start_msg;
+ }
+ else
+ {
+ $begin = $start_msg;
+ $end = $start_msg + $this->page_size;
+ }
- $mbox_count = $this->_messagecount($mailbox /*, 'ALL', TRUE*/);
+ if ($begin < 0) $begin = 0;
+ if ($end < 0) $end = $max;
+ if ($end > $max) $end = $max;
- $revalidate = false;
- if ($mbox_count)
+//console("fetch headers $start_msg to ".($start_msg+$this->page_size)." (msg $begin to $end)");
+
+ $headers_sorted = FALSE;
+ $cache_key = $mailbox.'.msg';
+ $cache_status = $this->check_cache_status($mailbox, $cache_key);
+
+//console("Cache status = $cache_status");
+
+ // cache is OK, we can get all messages from local cache
+ if ($cache_status>0)
+ {
+ $a_msg_headers = $this->get_message_cache($cache_key, $start_msg, $start_msg+$this->page_size, $sort_field, $sort_order);
+ $headers_sorted = TRUE;
+ }
+ else
{
- // get cached headers
- $a_out = $this->get_cache($mailbox.'.msg');
- $a_out = is_array($a_out) ? $a_out : array(); // make sure we get an array
-
- $cached_count = count($a_out);
- $a_new = array();
- $revalidate = true; // revalidate by default
-
- // if the cache count is greater then there have been changes for sure
- if ($cached_count <= $mbox_count)
+ // retrieve headers from IMAP
+ if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $sort_field)))
{
- $from = $cached_count?$cached_count:1;
-
- //get new headers (at least one is returned)
- $a_temp = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $mbox_count);
- $duplicated = $cached_count?true:false;
-
- foreach ($a_temp as $hdr)
+//console("$mailbox: ".count($msg_index));
+
+ $msgs = $msg_index[$begin];
+ for ($i=$begin; $i < $end; $i++)
{
- //skip the first one if duplicated
- if ($duplicated)
- {
- //check for changes using the UID
- $lastCacheHdr = end($a_out);
- if ($hdr->uid === $lastCacheHdr->uid)
- $revalidate = false;
-
- $duplicated = false;
- continue;
- }
-
- //skip deleted ones
- if (! $hdr->deleted)
- $a_new[ $hdr->uid ] = $hdr;
+ if ($sort_order == 'DESC')
+ $msgs = $msg_index[$i].','.$msgs;
+ else
+ $msgs = $msgs.','.$msg_index[$i];
}
- }
- //revalidate cache if needed
- $to = $mbox_count - count($a_new);
- if ($revalidate && $to !== 0) //we'll need to reindex the array so we have to make a copy
+ $sorted = TRUE;
+ }
+ else
{
- $a_dirty = $a_out;
- $a_out = array();
- $a_buffers = array();
+ $msgs = sprintf("%d:%d", $begin+1, $end);
+ $sorted = FALSE;
+ }
- //fetch chunks of 20 headers
- $step = 20;
- $found = false;
-
- //fetch headers in blocks starting from new to old
- do {
- $from = $to-$step;
- if ($from < 1) $from = 1;
- //store the block in a temporal buffer
- $a_buffers[$from] = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $to);
+ // cache is dirty, sync it
+ if ($this->caching_enabled && $cache_status==-1)
+ {
+ $this->sync_header_index($mailbox);
+ return $this->_list_headers($mailbox, $page, $sort_field, $sort_order);
+ }
+
- //compare the fetched headers with the ones in the cache
- $idx = 0;
- foreach ($a_buffers[$from] as $k=>$hdr)
+ // cache is incomplete
+ $cache_index = $this->get_message_cache_index($cache_key);
+
+ // fetch reuested headers from server
+ $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs);
+ $a_msg_headers = array();
+
+
+ if (!empty($a_header_index))
+ {
+ foreach ($a_header_index as $i => $headers)
+ {
+ if ($headers->deleted)
{
- //if it's different the comparison ends
- if (!isset($a_dirty[$hdr->uid]) || $a_dirty[$hdr->uid]->id !== $hdr->id)
- break;
+ // delete from cache
+ if ($cache_index[$headers->id] && $cache_index[$headers->id] == $headers->uid)
+ $this->remove_message_cache($cache_key, $headers->id);
- //if we arrive here then we know that the older messages in cache are ok
- $found = $hdr->id;
- $idx++;
+ continue;
}
- //remove from the buffer the headers which are already cached
- if ($found)
- $a_buffers[$from] = array_splice($a_buffers[$from], 0, $idx );
-
- $to = $from-1;
- }
- while ($found===false && $from > 1);
+ // add message to cache
+ if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid)
+ $this->add_message_cache($cache_key, $headers->id, $headers);
- //just keep the headers we are certain that didn't change in the cache
- if ($found !== false)
- {
- foreach ($a_dirty as $hdr)
- {
- if ($hdr->id > $found) break;
- $a_out[$hdr->uid] = $hdr;
- }
- }
-
- //we builded the block buffers from new to older, we process them in reverse order
- ksort($a_buffers, SORT_NUMERIC);
- foreach ($a_buffers as $a_buff)
- {
- foreach ($a_buff as $hdr)
- {
- if (! $hdr->deleted)
- $a_out[$hdr->uid] = $hdr;
- }
+ $a_msg_headers[$headers->uid] = $headers;
}
}
-
- //array_merge() would reindex the keys, so we use this 'hack'
- $a_out += $a_new;
- }
-
- //write headers list to cache if needed
- if ($revalidate || count($a_out)!=$cached_count) {
- $this->update_cache($mailbox.'.msg', $a_out);
- }
-
- //sort headers by a specific col
- $a_out = iil_SortHeaders( $a_out, $sort_field, $sort_order );
-
- // return complete list of messages
- if (strtolower($page)=='all')
- return $a_out;
- $start_msg = ($this->list_page-1) * $this->page_size;
- return array_slice($a_out, $start_msg, $this->page_size);
- }
+ // delete cached messages with a higher index than $max
+ $this->clear_message_cache($cache_key, $max);
- // original function; replaced 2005/10/18
- // private method for listing message header
- function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
- {
- $max = $this->_messagecount($mailbox);
-
- if (!strlen($mailbox))
- return array();
-
- // get cached headers
- $a_msg_headers = $this->get_cache($mailbox.'.msg');
-
- // retrieve headers from IMAP
- if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max)
- {
- $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max");
- $a_msg_headers = array();
-
- if (!empty($a_header_index))
- foreach ($a_header_index as $i => $headers)
- if (!$headers->deleted)
- $a_msg_headers[$headers->uid] = $headers;
- }
- else
- $headers_cached = TRUE;
-
- if (!is_array($a_msg_headers))
- return array();
-
- // sort headers by a specific col
- $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
- $headers_count = count($a_headers);
-
- // free memory
- unset($a_msg_headers);
-
- // write headers list to cache
- if (!$headers_cached)
- $this->update_cache($mailbox.'.msg', $a_headers);
+ // kick child process to sync cache
- // update message count cache
- $a_mailbox_cache = $this->get_cache('messagecount');
- if (isset($a_mailbox_cache[$mailbox]['ALL']) && $a_mailbox_cache[$mailbox]['ALL'] != $headers_count)
- {
- $a_mailbox_cache[$mailbox]['ALL'] = (int)$headers_count;
- $this->update_cache('messagecount', $a_mailbox_cache);
}
- if (empty($a_headers))
+
+ // return empty array if no messages found
+ if (!is_array($a_msg_headers) || empty($a_msg_headers))
return array();
-
- // return complete list of messages
- if (strtolower($page)=='all')
- return $a_headers;
- $start_msg = ($this->list_page-1) * $this->page_size;
- return array_slice($a_headers, $start_msg, $this->page_size);
+
+ // if not already sorted
+ if (!$headers_sorted)
+ $a_msg_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
+
+ return array_values($a_msg_headers);
}
-
+
// return sorted array of message UIDs
function message_index($mbox='', $sort_field='date', $sort_order='DESC')
@@ -510,9 +452,54 @@ class rcube_imap
}
- function sync_header_index($mbox=NULL)
+ function sync_header_index($mailbox)
{
-
+ $cache_key = $mailbox.'.msg';
+ $cache_index = $this->get_message_cache_index($cache_key);
+ $msg_count = $this->_messagecount($mailbox);
+
+ // fetch complete message index
+ $a_message_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:$msg_count", 'UID');
+
+ foreach ($a_message_index as $id => $uid)
+ {
+ // message in cache at correct position
+ if ($cache_index[$id] == $uid)
+ {
+// console("$id / $uid: OK");
+ unset($cache_index[$id]);
+ continue;
+ }
+
+ // message in cache but in wrong position
+ if (in_array((string)$uid, $cache_index, TRUE))
+ {
+// console("$id / $uid: Moved");
+ unset($cache_index[$id]);
+ }
+
+ // other message at this position
+ if (isset($cache_index[$id]))
+ {
+// console("$id / $uid: Delete");
+ $this->remove_message_cache($cache_key, $id);
+ unset($cache_index[$id]);
+ }
+
+
+// console("$id / $uid: Add");
+
+ // fetch complete headers and add to cache
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $id);
+ $this->add_message_cache($cache_key, $headers->id, $headers);
+ }
+
+ // those ids that are still in cache_index have been deleted
+ if (!empty($cache_index))
+ {
+ foreach ($cache_index as $id => $uid)
+ $this->remove_message_cache($cache_key, $id);
+ }
}
@@ -527,22 +514,19 @@ class rcube_imap
function get_headers($uid, $mbox=NULL)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
-
+
// get cached headers
- $a_msg_headers = $this->get_cache($mailbox.'.msg');
-
- // return cached header
- if ($a_msg_headers[$uid])
- return $a_msg_headers[$uid];
+ if ($headers = $this->get_cached_message($mailbox.'.msg', $uid))
+ return $headers;
$msg_id = $this->_uid2id($uid);
- $header = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
+ $headers = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
// write headers cache
- $a_msg_headers[$uid] = $header;
- $this->update_cache($mailbox.'.msg', $a_msg_headers);
+ if ($headers)
+ $this->add_message_cache($mailbox.'.msg', $msg_id, $headers);
- return $header;
+ return $headers;
}
@@ -595,19 +579,20 @@ class rcube_imap
// reload message headers if cached
$cache_key = $this->mailbox.'.msg';
- if ($this->caching_enabled && $result && ($a_cached_headers = $this->get_cache($cache_key)))
+ if ($this->caching_enabled)
{
- // close and re-open connection
- $this->reconnect();
-
- foreach ($uids as $uid)
+ foreach ($msg_ids as $id)
{
- if (isset($a_cached_headers[$uid]))
+ if ($cached_headers = $this->get_cached_message($cache_key, $id))
{
- unset($this->cache[$cache_key][$uid]);
- $this->get_headers($uid);
+ $this->remove_message_cache($cache_key, $id);
+ //$this->get_headers($uid);
}
}
+
+ // close and re-open connection
+ // this prevents connection problems with Courier
+ $this->reconnect();
}
// set nr of messages that were flaged
@@ -633,7 +618,7 @@ class rcube_imap
// make shure mailbox exists
if (in_array($mailbox, $this->_list_mailboxes()))
$saved = iil_C_Append($this->conn, $mailbox, $message);
-
+
if ($saved)
{
// increase messagecount of the target mailbox
@@ -672,20 +657,24 @@ class rcube_imap
// really deleted from the source mailbox
if ($moved)
{
- $this->expunge($from_mbox, FALSE);
- $this->clear_cache($to_mbox.'.msg');
+ $this->_expunge($from_mbox, FALSE);
$this->_clear_messagecount($from_mbox);
$this->_clear_messagecount($to_mbox);
}
// update cached message headers
$cache_key = $from_mbox.'.msg';
- if ($moved && ($a_cached_headers = $this->get_cache($cache_key)))
+ if ($moved && ($a_cache_index = $this->get_message_cache_index($cache_key)))
{
+ $start_index = 100000;
foreach ($a_uids as $uid)
- unset($a_cached_headers[$uid]);
+ {
+ $index = array_search($uid, $a_cache_index);
+ $start_index = min($index, $start_index);
+ }
- $this->update_cache($cache_key, $a_cached_headers);
+ // clear cache from the lowest index on
+ $this->clear_message_cache($cache_key, $start_index);
}
return $moved;
@@ -716,17 +705,23 @@ class rcube_imap
// really deleted from the mailbox
if ($deleted)
{
- $this->expunge($mailbox, FALSE);
+ $this->_expunge($mailbox, FALSE);
$this->_clear_messagecount($mailbox);
}
// remove deleted messages from cache
- if ($deleted && ($a_cached_headers = $this->get_cache($mailbox.'.msg')))
+ $cache_key = $mailbox.'.msg';
+ if ($deleted && ($a_cache_index = $this->get_message_cache_index($cache_key)))
{
+ $start_index = 100000;
foreach ($a_uids as $uid)
- unset($a_cached_headers[$uid]);
+ {
+ $index = array_search($uid, $a_cache_index);
+ $start_index = min($index, $start_index);
+ }
- $this->update_cache($mailbox.'.msg', $a_cached_headers);
+ // clear cache from the lowest index on
+ $this->clear_message_cache($cache_key, $start_index);
}
return $deleted;
@@ -740,7 +735,10 @@ class rcube_imap
$msg_count = $this->_messagecount($mailbox, 'ALL');
if ($msg_count>0)
+ {
+ $this->clear_message_cache($mailbox.'.msg');
return iil_C_ClearFolder($this->conn, $mailbox);
+ }
else
return 0;
}
@@ -750,12 +748,18 @@ class rcube_imap
function expunge($mbox='', $clear_cache=TRUE)
{
$mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
-
+ return $this->_expunge($mailbox, $clear_cache);
+ }
+
+
+ // send IMAP expunge command and clear cache
+ function _expunge($mailbox, $clear_cache=TRUE)
+ {
$result = iil_C_Expunge($this->conn, $mailbox);
if ($result>=0 && $clear_cache)
{
- $this->clear_cache($mailbox.'.msg');
+ //$this->clear_message_cache($mailbox.'.msg');
$this->_clear_messagecount($mailbox);
}
@@ -763,7 +767,6 @@ class rcube_imap
}
-
/* --------------------------------
* folder managment
* --------------------------------*/
@@ -824,13 +827,18 @@ class rcube_imap
function create_mailbox($name, $subscribe=FALSE)
{
$result = FALSE;
+
+ // replace backslashes
+ $name = preg_replace('/[\\\]+/', '-', $name);
+
$name_enc = UTF7EncodeString($name);
+
+ // reduce mailbox name to 100 chars
+ $name_enc = substr($name_enc, 0, 100);
+
$abs_name = $this->_mod_mailbox($name_enc);
$a_mailbox_cache = $this->get_cache('mailboxes');
-
- //if (strlen($this->root_ns))
- // $abs_name = $this->root_ns.$abs_name;
-
+
if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
$result = iil_C_CreateFolder($this->conn, $abs_name);
@@ -875,37 +883,41 @@ class rcube_imap
// clear mailboxlist cache
if ($deleted)
+ {
+ $this->clear_message_cache($mailbox.'.msg');
$this->clear_cache('mailboxes');
+ }
- return $updated;
+ return $deleted;
}
/* --------------------------------
- * internal caching functions
+ * internal caching methods
* --------------------------------*/
function set_caching($set)
{
- if ($set && function_exists('rcube_read_cache'))
+ if ($set && is_object($this->db))
$this->caching_enabled = TRUE;
else
$this->caching_enabled = FALSE;
}
+
function get_cache($key)
{
// read cache
if (!isset($this->cache[$key]) && $this->caching_enabled)
{
- $cache_data = rcube_read_cache('IMAP.'.$key);
+ $cache_data = $this->_read_cache_record('IMAP.'.$key);
$this->cache[$key] = strlen($cache_data) ? unserialize($cache_data) : FALSE;
}
- return $this->cache[$key];
+ return $this->cache[$key];
}
@@ -924,7 +936,7 @@ class rcube_imap
foreach ($this->cache as $key => $data)
{
if ($this->cache_changes[$key])
- rcube_write_cache('IMAP.'.$key, serialize($data));
+ $this->_write_cache_record('IMAP.'.$key, serialize($data));
}
}
}
@@ -935,7 +947,7 @@ class rcube_imap
if ($key===NULL)
{
foreach ($this->cache as $key => $data)
- rcube_clear_cache('IMAP.'.$key);
+ $this->_clear_cache_record('IMAP.'.$key);
$this->cache = array();
$this->cache_changed = FALSE;
@@ -943,7 +955,7 @@ class rcube_imap
}
else
{
- rcube_clear_cache('IMAP.'.$key);
+ $this->_clear_cache_record('IMAP.'.$key);
$this->cache_changes[$key] = FALSE;
unset($this->cache[$key]);
}
@@ -951,8 +963,276 @@ class rcube_imap
+ function _read_cache_record($key)
+ {
+ $cache_data = FALSE;
+
+ if ($this->db)
+ {
+ // get cached data from DB
+ $sql_result = $this->db->query(
+ "SELECT cache_id, data
+ FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $cache_data = $sql_arr['data'];
+ $this->cache_keys[$key] = $sql_arr['cache_id'];
+ }
+ }
+
+ return $cache_data;
+ }
+
+
+ function _write_cache_record($key, $data)
+ {
+ if (!$this->db)
+ return FALSE;
+
+ // check if we already have a cache entry for this key
+ if (!isset($this->cache_keys[$key]))
+ {
+ $sql_result = $this->db->query(
+ "SELECT cache_id
+ FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ $this->cache_keys[$key] = $sql_arr['cache_id'];
+ else
+ $this->cache_keys[$key] = FALSE;
+ }
+
+ // update existing cache record
+ if ($this->cache_keys[$key])
+ {
+ $this->db->query(
+ "UPDATE ".get_table_name('cache')."
+ SET created=now(),
+ data=?
+ WHERE user_id=?
+ AND cache_key=?",
+ $data,
+ $_SESSION['user_id'],
+ $key);
+ }
+ // add new cache record
+ else
+ {
+ $this->db->query(
+ "INSERT INTO ".get_table_name('cache')."
+ (created, user_id, cache_key, data)
+ VALUES (now(), ?, ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $data);
+ }
+ }
+
+
+ function _clear_cache_record($key)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $key);
+ }
+
+
+
+ /* --------------------------------
+ * message caching methods
+ * --------------------------------*/
+
+
+ // checks if the cache is up-to-date
+ // return: -3 = off, -2 = incomplete, -1 = dirty
+ function check_cache_status($mailbox, $cache_key)
+ {
+ if (!$this->caching_enabled)
+ return -3;
+
+ $cache_index = $this->get_message_cache_index($cache_key, TRUE);
+ $msg_count = $this->_messagecount($mailbox);
+ $cache_count = count($cache_index);
+
+ // console("Cache check: $msg_count !== ".count($cache_index));
+
+ if ($cache_count==$msg_count)
+ {
+ // get highest index
+ $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count");
+ $cache_uid = array_pop($cache_index);
+
+ // uids of highes message matches -> cache seems OK
+ if ($cache_uid == $header->uid)
+ return 1;
+
+ // cache is dirty
+ return -1;
+ }
+ // if cache count differs less that 10% report as dirty
+ else if (abs($msg_count - $cache_count) < $msg_count/10)
+ return -1;
+ else
+ return -2;
+ }
+
+
+
+ function get_message_cache($key, $from, $to, $sort_field, $sort_order)
+ {
+ $cache_key = "$key:$from:$to:$sort_field:$sort_order";
+ $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size');
+
+ if (!in_array($sort_field, $db_header_fields))
+ $sort_field = 'idx';
+
+ if ($this->caching_enabled && !isset($this->cache[$cache_key]))
+ {
+ $this->cache[$cache_key] = array();
+ $sql_result = $this->db->limitquery(
+ "SELECT idx, uid, headers
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ ORDER BY ".$this->db->quoteIdentifier($sort_field)." ".
+ strtoupper($sort_order),
+ $from,
+ $to-$from,
+ $_SESSION['user_id'],
+ $key);
+
+ while ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $uid = $sql_arr['uid'];
+ $this->cache[$cache_key][$uid] = unserialize($sql_arr['headers']);
+ }
+ }
+
+ return $this->cache[$cache_key];
+ }
+
+
+ function get_cached_message($key, $uid, $body=FALSE)
+ {
+ if (!$this->caching_enabled)
+ return FALSE;
+
+ $internal_key = '__single_msg';
+ if ($this->caching_enabled && (!isset($this->cache[$internal_key][$uid]) || $body))
+ {
+ $sql_select = "idx, uid, headers";
+ if ($body)
+ $sql_select .= ", body";
+
+ $sql_result = $this->db->query(
+ "SELECT $sql_select
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND uid=?",
+ $_SESSION['user_id'],
+ $key,
+ $uid);
+
+ if ($sql_arr = $this->db->fetch_assoc($sql_result))
+ {
+ $headers = unserialize($sql_arr['headers']);
+ if (is_object($headers) && !empty($sql_arr['body']))
+ $headers->body = $sql_arr['body'];
+
+ $this->cache[$internal_key][$uid] = $headers;
+ }
+ }
+
+ return $this->cache[$internal_key][$uid];
+ }
+
+
+ function get_message_cache_index($key, $force=FALSE)
+ {
+ static $sa_message_index = array();
+
+ if (!empty($sa_message_index[$key]) && !$force)
+ return $sa_message_index[$key];
+
+ $sa_message_index[$key] = array();
+ $sql_result = $this->db->query(
+ "SELECT idx, uid
+ FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ ORDER BY idx ASC",
+ $_SESSION['user_id'],
+ $key);
+
+ while ($sql_arr = $this->db->fetch_assoc($sql_result))
+ $sa_message_index[$key][$sql_arr['idx']] = $sql_arr['uid'];
+
+ return $sa_message_index[$key];
+ }
+
+
+ function add_message_cache($key, $index, $headers)
+ {
+ $this->db->query(
+ "INSERT INTO ".get_table_name('messages')."
+ (user_id, del, cache_key, idx, uid, subject, ".$this->db->quoteIdentifier('from').", ".$this->db->quoteIdentifier('to').", cc, date, size, headers)
+ VALUES (?, 0, ?, ?, ?, ?, ?, ?, ?, ".$this->db->fromunixtime($headers->timestamp).", ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $index,
+ $headers->uid,
+ $this->decode_header($headers->subject, TRUE),
+ $this->decode_header($headers->from, TRUE),
+ $this->decode_header($headers->to, TRUE),
+ $this->decode_header($headers->cc, TRUE),
+ $headers->size,
+ serialize($headers));
+ }
+
+
+ function remove_message_cache($key, $index)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND idx=?",
+ $_SESSION['user_id'],
+ $key,
+ $index);
+ }
+
+
+ function clear_message_cache($key, $start_index=1)
+ {
+ $this->db->query(
+ "DELETE FROM ".get_table_name('messages')."
+ WHERE user_id=?
+ AND cache_key=?
+ AND idx>=?",
+ $_SESSION['user_id'],
+ $key,
+ $start_index);
+ }
+
+
+
+
/* --------------------------------
- * encoding/decoding functions
+ * encoding/decoding methods
* --------------------------------*/
@@ -986,9 +1266,15 @@ class rcube_imap
}
- function decode_header($input)
+ function decode_header($input, $remove_quotes=FALSE)
{
- return $this->decode_mime_string($input);
+ $str = $this->decode_mime_string($input);
+ if ($str{0}=='"' && $remove_quotes)
+ {
+ $str = str_replace('"', '', $str);
+ }
+
+ return $str;
}
@@ -1094,6 +1380,7 @@ class rcube_imap
}
+
/* --------------------------------
* private methods
* --------------------------------*/
@@ -1149,6 +1436,33 @@ class rcube_imap
}
+ // parse string or array of server capabilities and put them in internal array
+ function _parse_capability($caps)
+ {
+ if (!is_array($caps))
+ $cap_arr = explode(' ', $caps);
+ else
+ $cap_arr = $caps;
+
+ foreach ($cap_arr as $cap)
+ {
+ if ($cap=='CAPABILITY')
+ continue;
+
+ if (strpos($cap, '=')>0)
+ {
+ list($key, $value) = explode('=', $cap);
+ if (!is_array($this->capabilities[$key]))
+ $this->capabilities[$key] = array();
+
+ $this->capabilities[$key][] = $value;
+ }
+ else
+ $this->capabilities[$cap] = TRUE;
+ }
+ }
+
+
// subscribe/unsubscribe a list of mailboxes and update local cache
function _change_subscription($a_mboxes, $mode)
{
diff --git a/program/include/rcube_mdb2.inc b/program/include/rcube_mdb2.inc
index 35973ad5d..54a40e796 100755
--- a/program/include/rcube_mdb2.inc
+++ b/program/include/rcube_mdb2.inc
@@ -238,6 +238,22 @@ class rcube_db
}
+ function format_date($timestamp)
+ {
+ switch($this->db_provider)
+ {
+ case 'mysqli':
+ case 'mysql':
+ return "FROM_UNIXTIME($timestamp)";
+ break;
+ case 'sqlite':
+ return "datetime('$timestamp')";
+ break;
+ default:
+ return date("Y-m-d H:i:s", $timestamp);
+ }
+ }
+
function _add_result($res, $query)
{
// sql error occured
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index 400e345c0..75db7603f 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -1185,99 +1185,6 @@ function send_future_expire_header()
}
-// replace specials characters to a specific encoding type
-function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
- {
- global $OUTPUT_TYPE, $CHARSET;
- static $html_encode_arr, $js_rep_table, $rtf_rep_table, $xml_rep_table;
-
- if (!$enctype)
- $enctype = $GLOBALS['OUTPUT_TYPE'];
-
- // convert nbsps back to normal spaces if not html
- if ($enctype!='html')
- $str = str_replace(chr(160), ' ', $str);
-
-
- // encode for plaintext
- if ($enctype=='text')
- return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
-
- // encode for HTML output
- if ($enctype=='html')
- {
- if (!$html_encode_arr)
- {
- if ($CHARSET=='ISO-8859-1')
- {
- $html_encode_arr = get_html_translation_table(HTML_ENTITIES);
- $html_encode_arr[chr(128)] = '&euro;';
- }
- else
- $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
-
- unset($html_encode_arr['?']);
- unset($html_encode_arr['&']);
- }
-
- $ltpos = strpos($str, '<');
- $encode_arr = $html_encode_arr;
-
- // don't replace quotes and html tags
- if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
- {
- unset($encode_arr['"']);
- unset($encode_arr['<']);
- unset($encode_arr['>']);
- }
- else if ($mode=='remove')
- $str = strip_tags($str);
-
- $out = strtr($str, $encode_arr);
-
- return $newlines ? nl2br($out) : $out;
- }
-
-
- if ($enctype=='url')
- return rawurlencode($str);
-
-
- // if the replace tables for RTF, XML and JS are not yet defined
- if (!$js_rep_table)
- {
- $js_rep_table = $rtf_rep_table = $xml_rep_table = array();
-
- for ($c=160; $c<256; $c++) // can be increased to support more charsets
- {
- $hex = dechex($c);
- $rtf_rep_table[Chr($c)] = "\\'$hex";
- $xml_rep_table[Chr($c)] = "&#$c;";
-
- if ($CHARSET=='ISO-8859-1')
- $js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
- }
-
- $js_rep_table['"'] = sprintf("\u%s%s", str_repeat('0', 4-strlen(dechex(34))), dechex(34));
- $xml_rep_table['"'] = '&quot;';
- }
-
- // encode for RTF
- if ($enctype=='xml')
- return strtr($str, $xml_rep_table);
-
- // encode for javascript use
- if ($enctype=='js')
- return preg_replace(array("/\r\n/", '/"/', "/([^\\\])'/"), array('\n', '\"', "$1\'"), strtr($str, $js_rep_table));
-
- // encode for RTF
- if ($enctype=='rtf')
- return preg_replace("/\r\n/", "\par ", strtr($str, $rtf_rep_table));
-
- // no encoding given -> return original string
- return $str;
- }
-
function decode_specialchars($input, $charset='')
{
@@ -1462,7 +1369,21 @@ function abbrevate_string($str, $maxlength, $place_holder='...')
return $str;
}
-
+
+
+// delete all files within a folder
+function clear_directory($dir_path)
+ {
+ $dir = @opendir($dir_path);
+ if(!$dir) return FALSE;
+
+ while ($file = readdir($dir))
+ if (strlen($file)>2)
+ unlink("$dir_path/$file");
+
+ closedir($dir);
+ return TRUE;
+ }
?> \ No newline at end of file
diff --git a/program/include/rcube_sqlite.inc b/program/include/rcube_sqlite.inc
new file mode 100644
index 000000000..78c671d38
--- /dev/null
+++ b/program/include/rcube_sqlite.inc
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_sqlite.inc |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Provide callback functions for sqlite that will emulate |
+ | sone MySQL functions |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+
+function rcube_sqlite_from_unixtime($timestamp)
+ {
+ $timestamp = trim($timestamp);
+ if (!preg_match("/^[0-9]+$/is", $timestamp))
+ $ret = strtotime($timestamp);
+ else
+ $ret = $timestamp;
+
+ $ret = date("Y-m-d H:i:s", $ret);
+ rcube_sqlite_debug("FROM_UNIXTIME ($timestamp) = $ret");
+ return $ret;
+ }
+
+
+function rcube_sqlite_unix_timestamp($timestamp="")
+ {
+ $timestamp = trim($timestamp);
+ if (!$timestamp)
+ $ret = time();
+ else if (!preg_match("/^[0-9]+$/is", $timestamp))
+ $ret = strtotime($timestamp);
+ else
+ $ret = $timestamp;
+
+ rcube_sqlite_debug("UNIX_TIMESTAMP ($timestamp) = $ret");
+ return $ret;
+ }
+
+
+function rcube_sqlite_now()
+ {
+ rcube_sqlite_debug("NOW() = ".date("Y-m-d H:i:s"));
+ return date("Y-m-d H:i:s");
+ }
+
+
+function rcube_sqlite_md5($str)
+ {
+ return md5($str);
+ }
+
+
+function rcube_sqlite_debug($str)
+ {
+ //console($str);
+ }
+
+?> \ No newline at end of file
diff --git a/program/include/session.inc b/program/include/session.inc
index 54ed798fc..f10a2b37e 100644
--- a/program/include/session.inc
+++ b/program/include/session.inc
@@ -45,7 +45,7 @@ function sess_read($key)
if ($sql_arr = $DB->fetch_assoc($sql_result))
{
- $SESS_CHANGED = $sql_arr['changed'];
+ $SESS_CHANGED = mktime(); //$sql_arr['changed'];
if (strlen($sql_arr['vars']))
return $sql_arr['vars'];
@@ -59,7 +59,7 @@ function sess_read($key)
function sess_write($key, $vars)
{
global $DB;
-
+
$sql_result = $DB->query("SELECT 1
FROM ".get_table_name('session')."
WHERE sess_id=?",
@@ -83,6 +83,8 @@ function sess_write($key, $vars)
$key,
$vars,
$_SERVER['REMOTE_ADDR']);
+
+
}
return TRUE;
@@ -102,7 +104,9 @@ function sess_destroy($key)
$DB->query("DELETE FROM ".get_table_name('session')."
WHERE sess_id=?",
$key);
-
+
+ rcmail_clear_session_temp($key);
+
return TRUE;
}
@@ -115,7 +119,7 @@ function sess_gc($maxlifetime)
// get all expired sessions
$sql_result = $DB->query("SELECT sess_id
FROM ".get_table_name('session')."
- WHERE ".$DB->unixtimestamp('now()')."-".$DB->unixtimestamp('created')." > ?",
+ WHERE ".$DB->unixtimestamp('now()')."-".$DB->unixtimestamp('changed')." > ?",
$maxlifetime);
$a_exp_sessions = array();
@@ -134,6 +138,10 @@ function sess_gc($maxlifetime)
WHERE sess_id IN ('".join("','", $a_exp_sessions)."')");
}
+ // remove session specific temp dirs
+ foreach ($a_exp_sessions as $key)
+ rcmail_clear_session_temp($key);
+
return TRUE;
}
diff --git a/program/js/app.js b/program/js/app.js
index 095c89d3a..d65af420e 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -210,7 +210,7 @@ function rcube_webmail()
this.enable_command('logout', true);
// disable browser's contextmenus
- //document.oncontextmenu = function(){ return false; }
+ // document.oncontextmenu = function(){ return false; }
// flag object as complete
this.loaded = true;
@@ -286,6 +286,7 @@ function rcube_webmail()
return false;
//this.messageform = this.gui_objects.messageform;
+ var input_from = rcube_find_object('_from');
var input_to = rcube_find_object('_to');
var input_cc = rcube_find_object('_cc');
var input_bcc = rcube_find_object('_bcc');
@@ -300,6 +301,10 @@ function rcube_webmail()
this.init_address_input_events(input_cc);
if (input_bcc)
this.init_address_input_events(input_bcc);
+
+ // add signature according to selected identity
+ if (input_from && input_from.type=='select-one')
+ this.change_identity(input_from);
if (input_to && input_to.value=='')
input_to.focus();
@@ -461,9 +466,18 @@ function rcube_webmail()
// get the type of sorting
var a_sort = props.split('_');
var sort_col = a_sort[0];
- var sort_order = a_sort[1].toUpperCase();
+ var sort_order = a_sort[1] ? a_sort[1].toUpperCase() : null;
var header;
+ // 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;
@@ -478,7 +492,7 @@ function rcube_webmail()
this.env.sort_order = sort_order;
// reload message list
- this.list_mailbox('', '', props);
+ this.list_mailbox('', '', sort_col+'_'+sort_order);
break;
case 'nextpage':
@@ -805,7 +819,7 @@ function rcube_webmail()
break;
case 'delete-folder':
- if (confirm('Do you really want to delete this folder?'))
+ if (confirm(this.get_label('deletefolderconfirm')))
this.delete_folder(props);
break;
@@ -933,8 +947,8 @@ function rcube_webmail()
if (!this.in_selection_before)
{
- var shift = this.check_shiftkey(e);
- this.select(id, shift);
+ var ctrl = this.check_ctrlkey(e);
+ this.select(id, ctrl);
}
if (this.selection.length)
@@ -951,7 +965,7 @@ function rcube_webmail()
// onmouseup-handler of message list row
this.click_row = function(e, id)
{
- var shift = this.check_shiftkey(e);
+ var ctrl = this.check_ctrlkey(e);
// don't do anything (another action processed before)
if (this.dont_select)
@@ -961,13 +975,13 @@ function rcube_webmail()
}
if (!this.drag_active && this.in_selection_before==id)
- this.select(id, (shift && this.task!='settings'));
+ this.select(id, (ctrl && this.task!='settings'));
this.drag_start = false;
this.in_selection_before = false;
// row was double clicked
- if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !shift)
+ if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !ctrl)
{
this.show_message(id);
return false;
@@ -1332,6 +1346,38 @@ function rcube_webmail()
/*********************************************************/
/********* message compose methods *********/
/*********************************************************/
+
+
+ this.change_identity = function(obj)
+ {
+ if (!obj || !obj.options)
+ return false;
+
+ var id = obj.options[obj.selectedIndex].value;
+ var input_message = rcube_find_object('_message');
+ var message = input_message ? input_message.value : '';
+
+ // remove the 'old' signature
+ if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
+ {
+ var sig = this.env.signatures[this.env.identity];
+
+ if (p = message.lastIndexOf(sig))
+ message = message.substring(0, p-1) + message.substring(p+sig.length, message.length);
+ }
+
+ // add the new signature string
+ if (this.env.signatures && this.env.signatures[id])
+ {
+ var sig = this.env.signatures[id];
+ message += '\n'+sig;
+ }
+
+ if (input_message && message)
+ input_message.value = message;
+
+ this.env.identity = id;
+ };
this.show_attachment_form = function(a)
@@ -1854,19 +1900,23 @@ function rcube_webmail()
{
if (folder)
{
- for (var id in this.env.subscriptionrows)
- if (this.env.subscriptionrows[id]==folder)
- break;
-
- var row;
- if (id && (row = document.getElementById(id)))
- row.style.display = 'none';
-
this.http_request('delete-folder', '_mboxes='+escape(folder));
}
};
+ this.remove_folder_row = function(folder)
+ {
+ for (var id in this.env.subscriptionrows)
+ if (this.env.subscriptionrows[id]==folder)
+ break;
+
+ var row;
+ if (id && (row = document.getElementById(id)))
+ row.style.display = 'none';
+ };
+
+
this.subscribe_folder = function(folder)
{
var form;
@@ -2491,6 +2541,21 @@ function rcube_webmail()
return false;
}
+ // check if Shift-key is pressed on event
+ this.check_ctrlkey = function(e)
+ {
+ if(!e && window.event)
+ e = window.event;
+
+ if(bw.linux && bw.ns4 && e.modifiers)
+ return true;
+ else if (bw.mac)
+ return this.check_shiftkey(e);
+ else if((bw.ns4 && e.modifiers & Event.CTRL_MASK) || (e && e.ctrlKey))
+ return true;
+ else
+ return false;
+ }
this.get_mouse_pos = function(e)
{
diff --git a/program/localization/de/labels.inc b/program/localization/de/labels.inc
index 4bbb14c95..12ec06e8c 100644
--- a/program/localization/de/labels.inc
+++ b/program/localization/de/labels.inc
@@ -109,6 +109,7 @@ $labels['unread'] = 'Ungelesene';
$labels['compose'] = 'Neue Nachricht verfassen';
$labels['sendmessage'] = 'Nachricht jetzt senden';
$labels['addattachment'] = 'Datei anfügen';
+$labels['charset'] = 'Zeichensatz';
$labels['attachments'] = 'Anhänge';
$labels['upload'] = 'Hochladen';
@@ -121,7 +122,6 @@ $labels['high'] = 'Hoch';
$labels['highest'] = 'Höchste';
$labels['nosubject'] = '(kein Betreff)';
-
$labels['showimages'] = 'Bilder anzeigen';
@@ -165,7 +165,7 @@ $labels['setdefault'] = 'Als Standard';
$labels['language'] = 'Sprache';
$labels['timezone'] = 'Zeitzone';
$labels['pagesize'] = 'Einträge pro Seite';
-
+$labels['signature'] = 'Signatur';
$labels['folders'] = 'Ordner';
$labels['foldername'] = 'Ordnername';
diff --git a/program/localization/de/messages.inc b/program/localization/de/messages.inc
index e8eabe10a..145c7b4a7 100644
--- a/program/localization/de/messages.inc
+++ b/program/localization/de/messages.inc
@@ -54,6 +54,8 @@ $messages['sendingfailed'] = 'Versand der Nachricht fehlgeschlagen';
$messages['errorsaving'] = 'Beim Speichern ist ein Fehler aufgetreten';
+$messages['deletefolderconfirm'] = 'Wollen Sie diesen Ordner wirklich löschen?';
+
$messages['formincomplete'] = 'Das Formular wurde nicht vollständig ausgefüllt';
$messages['noemailwarning'] = 'Bitte geben Sie eine gültige E-Mail-Adresse ein';
diff --git a/program/localization/ee/labels.inc b/program/localization/ee/labels.inc
new file mode 100644
index 000000000..76050726f
--- /dev/null
+++ b/program/localization/ee/labels.inc
@@ -0,0 +1,182 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | language/ee/labels.inc |
+ | |
+ | Language file of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundQube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Üllar Pajus <yllar.pajus@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+$labels = array();
+
+// login page
+$labels['username'] = 'Kasutajanimi';
+$labels['password'] = 'Parool';
+$labels['server'] = 'Server';
+$labels['login'] = 'Logi sisse';
+
+// taskbar
+$labels['logout'] = 'Logi välja';
+$labels['mail'] = 'Postkast';
+$labels['settings'] = 'Seaded';
+$labels['addressbook'] = 'Aadressiraamat';
+
+// mailbox names
+$labels['inbox'] = 'Sissetulevad';
+$labels['sent'] = 'Saadetud';
+$labels['trash'] = 'Prügikast';
+$labels['drafts'] = 'Ootel';
+$labels['junk'] = 'Rämps';
+
+// message listing
+$labels['subject'] = 'Pealkiri';
+$labels['from'] = 'Saatja';
+$labels['to'] = 'Saaja';
+$labels['cc'] = 'Koopia';
+$labels['bcc'] = 'Bcc';
+$labels['replyto'] = 'Vastus aadressile';
+$labels['date'] = 'Kuupäev';
+$labels['size'] = 'Suurus';
+$labels['priority'] = 'Tähtsus';
+$labels['organization'] = 'Organisatsioon';
+
+// aliases
+$labels['reply-to'] = $labels['replyto'];
+
+$labels['mailboxlist'] = 'Kaustad';
+$labels['messagesfromto'] = 'Kirjed $from kuni $to, kokku $count';
+$labels['messagenrof'] = 'Kiri $nr, kokku $count';
+
+$labels['moveto'] = 'liiguta kausta...';
+$labels['download'] = 'lae arvutisse';
+
+$labels['filename'] = 'Faili nimi';
+$labels['filesize'] = 'Faili suurus';
+
+$labels['preferhtml'] = 'Eelista HTMLi';
+$labels['htmlmessage'] = 'HTML kirjad';
+$labels['prettydate'] = 'Kenad kuupäevad';
+
+$labels['addtoaddressbook'] = 'Lisa aadressiraamatusse';
+
+// weekdays short
+$labels['sun'] = 'P';
+$labels['mon'] = 'E';
+$labels['tue'] = 'T';
+$labels['wed'] = 'K';
+$labels['thu'] = 'N';
+$labels['fri'] = 'R';
+$labels['sat'] = 'L';
+
+// weekdays long
+$labels['sunday'] = 'Pühapäev';
+$labels['monday'] = 'Esmaspäev';
+$labels['tuesday'] = 'Teisipäev';
+$labels['wednesday'] = 'Kolmapäev';
+$labels['thursday'] = 'Neljapäev';
+$labels['friday'] = 'Reede';
+$labels['saturday'] = 'Laupäev';
+
+$labels['today'] = 'Täna';
+
+// toolbar buttons
+$labels['writenewmessage'] = 'Kirjuta uus kiri';
+$labels['replytomessage'] = 'Vasta kirjale';
+$labels['replytoallmessage'] = 'Vasta saatjale ja teistele kirja saanutele';
+$labels['forwardmessage'] = 'Edasta see kiri';
+$labels['deletemessage'] = 'Liiguta kiri prügikasti';
+$labels['printmessage'] = 'Trüki kiri';
+$labels['previousmessages'] = 'Näita eelmisi kirju';
+$labels['nextmessages'] = 'Näita järgmisi kirju';
+$labels['backtolist'] = 'Tagasi kirjade nimekirja';
+$labels['viewsource'] = 'Näita lähtekoodi';
+
+$labels['select'] = 'Vali';
+$labels['all'] = 'kõik';
+$labels['none'] = 'mitte midagi';
+$labels['unread'] = 'mitte loetud';
+
+// message compose
+$labels['compose'] = 'Koosta kiri';
+$labels['sendmessage'] = 'Saada kiri kohe';
+$labels['addattachment'] = 'Lisa fail';
+
+$labels['attachments'] = 'Manused';
+$labels['upload'] = 'Kinnita manus';
+$labels['close'] = 'Sulge';
+
+$labels['low'] = 'Madal';
+$labels['lowest'] = 'Madalaim';
+$labels['normal'] = 'Tavaline';
+$labels['high'] = 'Kõrge';
+$labels['highest'] = 'Kõrgeim';
+
+$labels['nosubject'] = '(teema puudub)';
+
+$labels['showimages'] = 'Näita pilte';
+
+
+// address boook
+$labels['name'] = 'Näidatav nimi';
+$labels['firstname'] = 'Eesnimi';
+$labels['surname'] = 'Perekonnanimi';
+$labels['email'] = 'E-Mail';
+
+$labels['addcontact'] = 'Lisa uus kontakt';
+$labels['editcontact'] = 'Muuda kontakti';
+
+$labels['edit'] = 'Muuda';
+$labels['cancel'] = 'Katkesta';
+$labels['save'] = 'Salvesta';
+$labels['delete'] = 'Kustuta';
+
+$labels['newcontact'] = 'Loo uus sissekanne';
+$labels['deletecontact'] = 'Kustuta märgistatud kontaktid';
+$labels['composeto'] = 'Kirjuta kiri';
+$labels['contactsfromto'] = 'Kirjed $from kuni $to, kokku $count';
+$labels['print'] = 'Trüki';
+$labels['export'] = 'Ekspordi';
+
+
+// settings
+$labels['settingsfor'] = 'Kasutajaeelistused kontole';
+
+$labels['preferences'] = 'Eelistused';
+$labels['userpreferences'] = 'Kasutaja eelistused';
+$labels['editpreferences'] = 'Muuda kasutaja eelistusi';
+
+$labels['identities'] = 'Identiteedid';
+$labels['manageidentities'] = 'Halda selle konto identiteete';
+$labels['newidentity'] = 'Uus identiteet';
+
+$labels['newitem'] = 'Uus sissekanne';
+$labels['edititem'] = 'Muuda sissekannet';
+
+$labels['setdefault'] = 'Muuda vaikeseadeks';
+$labels['language'] = 'Keel';
+$labels['timezone'] = 'Ajatsoon';
+$labels['pagesize'] = 'Ridu lehe kohta';
+
+
+$labels['folders'] = 'Kaustad';
+$labels['foldername'] = 'Kausta nimi';
+$labels['subscribed'] = 'Näitan';
+$labels['create'] = 'Loo';
+$labels['createfolder'] = 'Loo uus kaust';
+$labels['deletefolder'] = 'Kustuta kaust';
+$labels['managefolders'] = 'Manage folders';
+
+$labels['sortby'] = 'Järjesta';
+$labels['sortasc'] = 'Järjesta kasvavalt';
+$labels['sortdesc'] = 'Järjesta kahanevalt';
+
+?>
diff --git a/program/localization/ee/messages.inc b/program/localization/ee/messages.inc
new file mode 100644
index 000000000..6aeff2834
--- /dev/null
+++ b/program/localization/ee/messages.inc
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | language/ee/messages.inc |
+ | |
+ | Language file of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Üllar Pajus <yllar.pajus@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+$messages = array();
+
+$messages['loginfailed'] = 'Sisselogimine ebaõnnestus';
+
+$messages['cookiesdisabled'] = 'Sinu veebilehitseja ei võta präänikuid vastu';
+
+$messages['sessionerror'] = 'Sinu sessioon on aegunud või vigane';
+
+$messages['imaperror'] = 'Ei õnnestunud IMAP serveriga ühendust luua';
+
+$messages['nomessagesfound'] = 'Postkast paistab tühi olevat';
+
+$messages['loggedout'] = 'Sinu sessioon on edukalt lõpetatud. Nägemiseni!';
+
+$messages['mailboxempty'] = 'Postkast on tühi';
+
+$messages['loading'] = 'Laen...';
+
+$messages['loadingdata'] = 'Laen andmeid...';
+
+$messages['sendingmessage'] = 'Saadan kirja...';
+
+$messages['messagesent'] = 'Kiri edukalt saadetud';
+
+$messages['successfullysaved'] = 'Edukalt salvestatud';
+
+$messages['addedsuccessfully'] = 'Kontakt lisati edukalt aadressiraamatusse';
+
+$messages['contactexists'] = 'Sama e-maili aadressiga kontakt on juba olemas';
+
+$messages['blockedimages'] = 'Sinu privaatsuse kaitsmiseks on selles kirjas välised pildid blokeeritud.';
+
+$messages['encryptedmessage'] = 'See on krüpteeritud kiri ja kahjuks pole seda võimalik näidata. Andestust!';
+
+$messages['nocontactsfound'] = 'Ei leidnud ühtegi kontakti';
+
+$messages['sendingfailed'] = 'Kirja saatmine ebaõnnestus';
+
+$messages['errorsaving'] = 'Salvestamie ajal ilmnes viga';
+
+$messages['errormoving'] = 'Ei suutnud seda kirja liigutada';
+
+$messages['errordeleting'] = 'Ei suutnud seda kirja kustutada';
+
+$messages['errordeleting'] = 'Ei suutnud seda kirja kustutada';
+
+$messages['formincomplete'] = 'Vormi kõik väljad ei ole täidetud';
+
+$messages['noemailwarning'] = 'Palun sisesta toimiv e-maili aadress';
+
+$messages['nonamewarning'] = 'Palun sisesta nimi';
+
+$messages['nopagesizewarning'] = 'Palun sisesta lehekülje suurus';
+
+$messages['norecipientwarning'] = 'Palun sisesta vähemalt üks kirjasaaja';
+
+$messages['nosubjectwarning'] = 'Väli "Pealkiri" on tühi. Soovid selle ära täita ?';
+
+$messages['nobodywarning'] = 'Saadan selle kirja ilma tekstita ?';
+
+
+?>
diff --git a/program/localization/en/labels.inc b/program/localization/en/labels.inc
index 35813cdb0..b37b48140 100644
--- a/program/localization/en/labels.inc
+++ b/program/localization/en/labels.inc
@@ -109,6 +109,7 @@ $labels['unread'] = 'Unread';
$labels['compose'] = 'Compose a message';
$labels['sendmessage'] = 'Send the message now';
$labels['addattachment'] = 'Attach a file';
+$labels['charset'] = 'Charset';
$labels['attachments'] = 'Attachments';
$labels['upload'] = 'Upload';
@@ -121,7 +122,6 @@ $labels['high'] = 'High';
$labels['highest'] = 'Highest';
$labels['nosubject'] = '(no subject)';
-
$labels['showimages'] = 'Display images';
@@ -165,7 +165,7 @@ $labels['setdefault'] = 'Set default';
$labels['language'] = 'Language';
$labels['timezone'] = 'Time zone';
$labels['pagesize'] = 'Rows per page';
-
+$labels['signature'] = 'Signature';
$labels['folders'] = 'Folders';
$labels['foldername'] = 'Folder name';
diff --git a/program/localization/en/messages.inc b/program/localization/en/messages.inc
index 1ce6bba6d..d0286e229 100644
--- a/program/localization/en/messages.inc
+++ b/program/localization/en/messages.inc
@@ -60,13 +60,13 @@ $messages['errormoving'] = 'Could not move the message';
$messages['errordeleting'] = 'Could not delete the message';
-$messages['errordeleting'] = 'Could not delete the message';
+$messages['deletefolderconfirm'] = 'Do you really want to delete this folder?';
-$messages['formincomplete'] = 'The form was not completely filled out';
+$messages['formincomplete'] = 'The form was not completely filled out';
-$messages['noemailwarning'] = 'Please enter a valid email address';
+$messages['noemailwarning'] = 'Please enter a valid email address';
-$messages['nonamewarning'] = 'Please enter a name';
+$messages['nonamewarning'] = 'Please enter a name';
$messages['nopagesizewarning'] = 'Please enter a page size';
diff --git a/program/localization/en_GB/labels.inc b/program/localization/en_GB/labels.inc
index d1a274971..cd9b5032d 100644
--- a/program/localization/en_GB/labels.inc
+++ b/program/localization/en_GB/labels.inc
@@ -120,6 +120,7 @@ $labels['normal'] = 'Normal';
$labels['high'] = 'High';
$labels['highest'] = 'Highest';
+$labels['nosubject'] = '(no subject)';
$labels['showimages'] = 'Display images';
@@ -163,7 +164,7 @@ $labels['setdefault'] = 'Set default';
$labels['language'] = 'Language';
$labels['timezone'] = 'Time zone';
$labels['pagesize'] = 'Rows per page';
-
+$labels['signature'] = 'Signature';
$labels['folders'] = 'Folders';
$labels['foldername'] = 'Folder name';
diff --git a/program/localization/index.inc b/program/localization/index.inc
index 3386ebd68..82424e602 100644
--- a/program/localization/index.inc
+++ b/program/localization/index.inc
@@ -32,6 +32,7 @@
'da' => 'Dansk',
'de' => 'Deutsch',
'es' => 'Espa&ntilde;ol',
+ 'ee' => 'Estonian',
'fr' => 'Fran&ccedil;ais',
'ga' => 'Galician',
'el' => 'Greek',
diff --git a/program/steps/addressbook/delete.inc b/program/steps/addressbook/delete.inc
index a3fcefbf7..b95988d12 100644
--- a/program/steps/addressbook/delete.inc
+++ b/program/steps/addressbook/delete.inc
@@ -24,7 +24,7 @@ $REMOTE_REQUEST = TRUE;
if ($_GET['_cid'])
{
$DB->query("UPDATE ".get_table_name('contacts')."
- SET del='1'
+ SET del=1
WHERE user_id=?
AND contact_id IN (".$_GET['_cid'].")",
$_SESSION['user_id']);
@@ -40,7 +40,7 @@ if ($_GET['_cid'])
// count contacts for this user
$sql_result = $DB->query("SELECT COUNT(contact_id) AS rows
FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?",
$_SESSION['user_id']);
@@ -60,7 +60,7 @@ if ($_GET['_cid'])
// get contacts from DB
$sql_result = $DB->limitquery("SELECT * FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?
ORDER BY name",
$start_row,
diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc
index feb794f4d..a129d0094 100644
--- a/program/steps/addressbook/edit.inc
+++ b/program/steps/addressbook/edit.inc
@@ -26,7 +26,7 @@ if (($_GET['_cid'] || $_POST['_cid']) && $_action=='edit')
$DB->query("SELECT * FROM ".get_table_name('contacts')."
WHERE contact_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$cid,
$_SESSION['user_id']);
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 4cc79bad6..8065219b0 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -43,7 +43,7 @@ function rcmail_contacts_list($attrib)
// count contacts for this user
$sql_result = $DB->query("SELECT COUNT(contact_id) AS rows
FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?",
$_SESSION['user_id']);
@@ -56,7 +56,7 @@ function rcmail_contacts_list($attrib)
// get contacts from DB
$sql_result = $DB->limitquery("SELECT * FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id= ?
ORDER BY name",
$start_row,
@@ -173,7 +173,7 @@ function rcmail_get_rowcount_text($max=NULL)
if ($max===NULL)
{
$sql_result = $DB->query("SELECT 1 FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?",
$_SESSION['user_id']);
diff --git a/program/steps/addressbook/list.inc b/program/steps/addressbook/list.inc
index ecb634b6f..0aa4873b3 100644
--- a/program/steps/addressbook/list.inc
+++ b/program/steps/addressbook/list.inc
@@ -24,7 +24,7 @@ $REMOTE_REQUEST = TRUE;
// count contacts for this user
$sql_result = $DB->query("SELECT COUNT(contact_id) AS rows
FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?",
$_SESSION['user_id']);
@@ -40,7 +40,7 @@ $start_row = ($CONTACTS_LIST['page']-1) * $CONFIG['pagesize'];
// get contacts from DB
$sql_result = $DB->limitquery("SELECT * FROM ".get_table_name('contacts')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?
ORDER BY name",
$start_row,
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index 2f54e435b..f5ba139b9 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -52,7 +52,7 @@ if ($_POST['_cid'])
SET changed=now(), ".join(', ', $a_write_sql)."
WHERE contact_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$_POST['_cid'],
$_SESSION['user_id']);
@@ -73,7 +73,7 @@ if ($_POST['_cid'])
$sql_result = $DB->query("SELECT * FROM ".get_table_name('contacts')."
WHERE contact_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$_POST['_cid'],
$_SESSION['user_id']);
@@ -109,7 +109,7 @@ else
$sql_result = $DB->query("SELECT 1 FROM ".get_table_name('contacts')."
WHERE user_id=?
AND email=?
- AND del<>'1'",
+ AND del<>1",
$_SESSION['user_id'],
$_POST['_email']);
@@ -134,11 +134,11 @@ else
if (sizeof($a_insert_cols))
{
$DB->query("INSERT INTO ".get_table_name('contacts')."
- (user_id, changed, ".join(', ', $a_insert_cols).")
- VALUES (?, now(), ".join(', ', $a_insert_values).")",
+ (user_id, changed, del, ".join(', ', $a_insert_cols).")
+ VALUES (?, now(), 0, ".join(', ', $a_insert_values).")",
$_SESSION['user_id']);
- $insert_id = $DB->insert_id();
+ $insert_id = $DB->insert_id(get_sequence_name('contacts'));
}
if ($insert_id)
diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc
index 83db486cc..960ea1c45 100644
--- a/program/steps/addressbook/show.inc
+++ b/program/steps/addressbook/show.inc
@@ -26,7 +26,7 @@ if ($_GET['_cid'] || $_POST['_cid'])
$DB->query("SELECT * FROM ".get_table_name('contacts')."
WHERE contact_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$cid,
$_SESSION['user_id']);
diff --git a/program/steps/mail/addcontact.inc b/program/steps/mail/addcontact.inc
index ad1544e71..b1129ec9d 100644
--- a/program/steps/mail/addcontact.inc
+++ b/program/steps/mail/addcontact.inc
@@ -32,7 +32,7 @@ if ($_GET['_address'])
$sql_result = $DB->query("SELECT 1 FROM ".get_table_name('contacts')."
WHERE user_id=?
AND email=?
- AND del<>'1'",
+ AND del<>1",
$_SESSION['user_id'],$contact['mailto']);
// contact entry with this mail address exists
@@ -42,13 +42,13 @@ if ($_GET['_address'])
else if ($contact['mailto'])
{
$DB->query("INSERT INTO ".get_table_name('contacts')."
- (user_id, changed, name, email)
- VALUES (?, now(), ?, ?)",
+ (user_id, changed, del, name, email)
+ VALUES (?, now(), 0, ?, ?)",
$_SESSION['user_id'],
$contact['name'],
$contact['mailto']);
- $added = $DB->insert_id();
+ $added = $DB->insert_id(get_sequence_name('contacts'));
}
}
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 9509b492b..45f111263 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -88,50 +88,20 @@ function rcmail_compose_headers($attrib)
switch ($part)
{
case 'from':
- // pass the following attributes to the form class
- $field_attrib = array('name' => '_from');
- foreach ($attrib as $attr => $value)
- if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
- $field_attrib[$attr] = $value;
-
- // get this user's identities
- $sql_result = $DB->query("SELECT identity_id, name, email
- FROM ".get_table_name('identities')." WHERE user_id=?
- AND del<>'1'
- ORDER BY ".$DB->quoteIdentifier('default')." DESC, name ASC",
- $_SESSION['user_id']);
-
- if ($DB->num_rows($sql_result))
- {
- $select_from = new select($field_attrib);
- while ($sql_arr = $DB->fetch_assoc($sql_result))
- $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $sql_arr['identity_id']);
-
- $out = $select_from->show($_POST['_from']);
- }
- else
- {
- $input_from = new textfield($field_attrib);
- $out = $input_from->show($_POST['_from']);
- }
-
- if ($form_start)
- $out = $form_start.$out;
-
- return $out;
-
+ return rcmail_compose_header_from($attrib);
case 'to':
$fname = '_to';
$header = 'to';
-
+
// we have contact id's as get parameters
- if (!empty($_GET['_to']) && preg_match('/[0-9]+,?/', $_GET['_to']))
+ if (!empty($_GET['_to']) && preg_match('/^([0-9]+,?)+$/', $_GET['_to']))
{
$a_recipients = array();
$sql_result = $DB->query("SELECT name, email
- FROM ".get_table_name('contacts')." WHERE user_id=?
- AND del<>'1'
+ FROM ".get_table_name('contacts')."
+ WHERE user_id=?
+ AND del<>1
AND contact_id IN (".$_GET['_to'].")",
$_SESSION['user_id']);
@@ -229,71 +199,91 @@ function rcmail_compose_headers($attrib)
}
-/*function rcube_compose_headers($attrib)
- {
- global $CONFIG, $OUTPUT;
-
- list($form_start, $form_end) = get_form_tags($attrib);
-
- // allow the following attributes to be added to the headers table
- $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border'));
-
- $labels = array();
- $labels['from'] = rcube_label('from');
- $labels['to'] = rcube_label('to');
- $labels['cc'] = rcube_label('cc');
- $labels['bcc'] = rcube_label('bcc');
- $labels['replyto'] = rcube_label('replyto');
-
- $input_from = new textfield(array('name' => '_from', 'size' => 30));
- $input_to = new textfield(array('name' => '_to', 'size' => 30));
- $input_cc = new textfield(array('name' => '_cc', 'size' => 30));
- $input_bcc = new textfield(array('name' => '_bcc', 'size' => 30));
- $input_replyto = new textfield(array('name' => '_replyto', 'size' => 30));
-
- $fields = array();
- $fields['from'] = $input_from->show($_POST['_from']);
- $fields['to'] = $input_to->show($_POST['_to']);
- $fields['cc'] = $input_cc->show($_POST['_cc']);
- $fields['bcc'] = $input_bcc->show($_POST['_bcc']);
- $fields['replyto'] = $input_replyto->show($_POST['_replyto']);
-
-
- $out = <<<EOF
-$form_start
-<table$attrib_str><tr>
-
-<td class="title">$labels[from]</td>
-<td>$fields[from]</td>
-
-</tr><tr>
-
-<td class="title">$labels[to]</td>
-<td>$fields[to]</td>
-</tr><tr>
+function rcmail_compose_header_from($attrib)
+ {
+ global $IMAP, $REPLY_MESSAGE, $DB, $OUTPUT, $JS_OBJECT_NAME;
+
+ // pass the following attributes to the form class
+ $field_attrib = array('name' => '_from');
+ foreach ($attrib as $attr => $value)
+ if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
+ $field_attrib[$attr] = $value;
+
+ // extract all recipients of the reply-message
+ $a_recipients = array();
+ if ($REPLY_MESSAGE && is_object($REPLY_MESSAGE['headers']))
+ {
+ $a_to = $IMAP->decode_address_list($REPLY_MESSAGE['headers']->to);
+ foreach ($a_to as $addr)
+ {
+ if (!empty($addr['mailto']))
+ $a_recipients[] = $addr['mailto'];
+ }
-<td class="title">$labels[cc]</td>
-<td>$fields[cc]</td>
+ if (!empty($REPLY_MESSAGE['headers']->cc))
+ {
+ $a_cc = $IMAP->decode_address_list($REPLY_MESSAGE['headers']->cc);
+ foreach ($a_cc as $addr)
+ {
+ if (!empty($addr['mailto']))
+ $a_recipients[] = $addr['mailto'];
+ }
+ }
+ }
-</tr><tr>
+ // get this user's identities
+ $sql_result = $DB->query("SELECT identity_id, name, email, signature
+ FROM ".get_table_name('identities')."
+ WHERE user_id=?
+ AND del<>1
+ ORDER BY ".$DB->quoteIdentifier('standard')." DESC, name ASC",
+ $_SESSION['user_id']);
+
+ if ($DB->num_rows($sql_result))
+ {
+ $from_id = 0;
+ $a_signatures = array();
+
+ $field_attrib['onchange'] = "$JS_OBJECT_NAME.change_identity(this)";
+ $select_from = new select($field_attrib);
+
+ while ($sql_arr = $DB->fetch_assoc($sql_result))
+ {
+ $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $sql_arr['identity_id']);
-<td class="title">$labels[bcc]</td>
-<td>$fields[bcc]</td>
+ // add signature to array
+ if (!empty($sql_arr['signature']))
+ $a_signatures[$sql_arr['identity_id']] = $sql_arr['signature'];
+
+ // set identity if it's one of the reply-message recipients
+ if (in_array($sql_arr['email'], $a_recipients))
+ $from_id = $sql_arr['identity_id'];
+ }
-</tr><tr>
+ // overwrite identity selection with post parameter
+ if (isset($_POST['_from']))
+ $from_id = $_POST['_from'];
-<td class="title">$labels[replyto]</td>
-<td>$fields[replyto]</td>
+ $out = $select_from->show($from_id);
+
-</tr></table>
-$form_end
-EOF;
+ // add signatures to client
+ $OUTPUT->add_script(sprintf("%s.set_env('signatures', %s);", $JS_OBJECT_NAME, array2js($a_signatures)));
+ }
+ else
+ {
+ $input_from = new textfield($field_attrib);
+ $out = $input_from->show($_POST['_from']);
+ }
+
+ if ($form_start)
+ $out = $form_start.$out;
- return $out;
+ return $out;
}
-*/
+
function rcmail_compose_body($attrib)
{
@@ -360,6 +350,14 @@ function rcmail_create_reply_body($body)
$pefix = sprintf("\n\n\nOn %s, %s wrote:\n",
$REPLY_MESSAGE['headers']->date,
$IMAP->decode_header($REPLY_MESSAGE['headers']->from));
+
+
+ // try to remove the signature
+ if ($sp = strrpos($body, '--'))
+ {
+ if ($body{$sp+3}==' ' || $body{$sp+3}=="\n" || $body{$sp+3}=="\r")
+ $body = substr($body, 0, $sp-1);
+ }
return $pefix.$body;
}
@@ -596,7 +594,7 @@ function rcmail_charset_pulldown($selected='ISO-8859-1')
$sql_result = $DB->query("SELECT name, email
FROM ".get_table_name('contacts')." WHERE user_id=?
- AND del<>'1'",$_SESSION['user_id']);
+ AND del<>1",$_SESSION['user_id']);
if ($DB->num_rows($sql_result))
{
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index ca72f7437..c81dd2fd2 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -305,26 +305,41 @@ function rcmail_message_list($attrib)
// make sort links
$sort = '';
- if (in_array($col, $a_sort_cols) && (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton'])))
+ if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols))
{
- $sort = '&nbsp;&nbsp;';
-
- // asc link
- if (!empty($attrib['sortascbutton']))
+ // have buttons configured
+ if (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))
{
- $sort .= rcube_button(array('command' => 'sort',
- 'prop' => $col.'_ASC',
- 'image' => $attrib['sortascbutton'],
- 'title' => 'sortasc'));
- }
+ $sort = '&nbsp;&nbsp;';
+
+ // asc link
+ if (!empty($attrib['sortascbutton']))
+ {
+ $sort .= rcube_button(array('command' => 'sort',
+ 'prop' => $col.'_ASC',
+ 'image' => $attrib['sortascbutton'],
+ 'align' => 'absmiddle',
+ 'title' => 'sortasc'));
+ }
- // desc link
- if (!empty($attrib['sortdescbutton']))
+ // desc link
+ if (!empty($attrib['sortdescbutton']))
+ {
+ $sort .= rcube_button(array('command' => 'sort',
+ 'prop' => $col.'_DESC',
+ 'image' => $attrib['sortdescbutton'],
+ 'align' => 'absmiddle',
+ 'title' => 'sortdesc'));
+ }
+ }
+ // just add a link tag to the header
+ else
{
- $sort .= rcube_button(array('command' => 'sort',
- 'prop' => $col.'_DESC',
- 'image' => $attrib['sortdescbutton'],
- 'title' => 'sortdesc'));
+ $col_name = sprintf('<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
+ $JS_OBJECT_NAME,
+ $col,
+ rcube_label('sortby'),
+ $col_name);
}
}
@@ -1128,20 +1143,76 @@ function rcmail_first_text_part($message_parts)
// get source code of a specific message and cache it
function rcmail_message_source($uid)
{
- global $IMAP, $DB;
+ global $IMAP, $DB, $CONFIG;
+
+ // get message ID if uid is given
+ $cache_key = $IMAP->mailbox.'.msg';
+ $cached = $IMAP->get_cached_message($cache_key, $uid, FALSE);
+
+ // message is cached in database
+ if ($cached && !empty($cached->body))
+ return $cached->body;
+
+ if (!$cached)
+ $headers = $IMAP->get_headers($uid);
+ else
+ $headers = &$cached;
+
- // get message ID if uid is given
- $headers = $IMAP->get_headers($uid);
$message_id = $headers->messageID;
- // get cached message source
- $msg_source = rcube_read_cache($message_id);
+ $temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '');
+ $cache_dir = $temp_dir.$_SESSION['client_id'];
+ $cache_path = $cache_dir.'/'.$message_id;
+
+ // message is cached in temp dir
+ if (is_dir($cache_dir) && is_file($cache_path))
+ {
+ if ($fp = fopen($cache_path, 'r'))
+ {
+ $msg_source = fread($fp, filesize($cache_path));
+ fclose($fp);
+ return $msg_source;
+ }
+ }
+
+
+ // get message from server
+ $msg_source = $IMAP->get_raw_body($uid);
+
+ // let's cache the message body within the database
+ if ($CONFIG['enable_caching'] && $cached && ($CONFIG['db_max_length'] -300) > $headers->size)
+ {
+ $DB->query("UPDATE ".get_table_name('messages')."
+ SET body=?
+ WHERE user_id=?
+ AND cache_key=?
+ AND uid=?",
+ $msg_source,
+ $_SESSION['user_id'],
+ $cache_key,
+ $uid);
+
+ return $msg_source;
+ }
+
+
+ // create dir for caching
+ if (!is_dir($cache_dir))
+ $dir = mkdir($cache_dir);
+ else
+ $dir = true;
- // get message from server and cache it
- if (!$msg_source)
+ // attempt to write a file with the message body
+ if ($dir && ($fp = fopen($cache_path, 'w')))
+ {
+ fwrite($fp, $msg_source);
+ fclose($fp);
+ }
+ else
{
- $msg_source = $IMAP->get_raw_body($uid);
- rcube_write_cache($message_id, $msg_source, TRUE);
+ raise_error(array('code' => 403, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => "Failed to write to temp dir"), TRUE, FALSE);
}
return $msg_source;
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 11fb559dd..8ec30b0a7 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -46,7 +46,7 @@ function rcmail_get_identity($id)
FROM ".get_table_name('identities')."
WHERE identity_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$id,$_SESSION['user_id']);
if ($DB->num_rows($sql_result))
@@ -78,8 +78,8 @@ if (empty($CHARSET))
$CHARSET = 'ISO-8859-1';
-$mailto_regexp = array('/,\s*[\r\n]+/', '/[\r\n]+/', '/,\s*$/m');
-$mailto_replace = array(' ', ', ', '');
+$mailto_regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m');
+$mailto_replace = array(', ', ', ', '');
// repalce new lines and strip ending ', '
$mailto = preg_replace($mailto_regexp, $mailto_replace, stripslashes($_POST['_to']));
@@ -175,13 +175,16 @@ if (is_array($_FILES['_attachments']['tmp_name']))
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath)
$MAIL_MIME->addAttachment($filepath, $files['type'][$i], $files['name'][$i], TRUE);
+
+$message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $CHARSET;
+
// encoding settings for mail composing
$message_param = array('text_encoding' => '7bit',
'html_encoding' => 'quoted-printable',
'head_encoding' => 'quoted-printable',
- 'head_charset' => $CHARSET,
- 'html_charset' => $CHARSET,
- 'text_charset' => $CHARSET);
+ 'head_charset' => $message_charset,
+ 'html_charset' => $message_charset,
+ 'text_charset' => $message_charset);
// compose message body and get headers
$msg_body = $MAIL_MIME->get($message_param);
diff --git a/program/steps/settings/delete_identity.inc b/program/steps/settings/delete_identity.inc
index 3bca860b3..b8f9f526c 100644
--- a/program/steps/settings/delete_identity.inc
+++ b/program/steps/settings/delete_identity.inc
@@ -24,7 +24,7 @@ $REMOTE_REQUEST = $_GET['_remote'] ? TRUE : FALSE;
if ($_GET['_iid'])
{
$DB->query("UPDATE ".get_table_name('identities')."
- SET del='1'
+ SET del=1
WHERE user_id=?
AND identity_id IN (".$_GET['_iid'].")",
$_SESSION['user_id']);
diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc
index 6649c209a..07cd8fa02 100644
--- a/program/steps/settings/edit_identity.inc
+++ b/program/steps/settings/edit_identity.inc
@@ -25,7 +25,7 @@ if (($_GET['_iid'] || $_POST['_iid']) && $_action=='edit-identity')
$DB->query("SELECT * FROM ".get_table_name('identities')."
WHERE identity_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$id,
$_SESSION['user_id']);
@@ -63,7 +63,8 @@ function rcube_identity_form($attrib)
'organization' => array('type' => 'text'),
'reply-to' => array('type' => 'text', 'label' => 'replyto'),
'bcc' => array('type' => 'text'),
- 'default' => array('type' => 'checkbox', 'label' => 'setdefault'));
+ 'signature' => array('type' => 'textarea'),
+ 'standard' => array('type' => 'checkbox', 'label' => 'setdefault'));
// a specific part is requested
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 01b692395..b33f8d434 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -146,9 +146,9 @@ function rcmail_identities_list($attrib)
// get contacts from DB
$sql_result = $DB->query("SELECT * FROM ".get_table_name('identities')."
- WHERE del<>'1'
+ WHERE del<>1
AND user_id=?
- ORDER BY ".$DB->quoteIdentifier('default')." DESC, name ASC",
+ ORDER BY standard DESC, name ASC",
$_SESSION['user_id']);
diff --git a/program/steps/settings/manage_folders.inc b/program/steps/settings/manage_folders.inc
index 04b2a461e..33d83dfff 100644
--- a/program/steps/settings/manage_folders.inc
+++ b/program/steps/settings/manage_folders.inc
@@ -69,10 +69,15 @@ else if ($_action=='create-folder')
else if ($_action=='delete-folder')
{
if (strlen($_GET['_mboxes']))
- $IMAP->delete_mailbox(explode(',', $_GET['_mboxes']));
+ $deleted = $IMAP->delete_mailbox(explode(',', $_GET['_mboxes']));
- if ($_GET['_remote'])
- rcube_remote_response('// deleted');
+ if ($_GET['_remote'] && $deleted)
+ rcube_remote_response(sprintf("this.remove_folder_row('%s')", rep_specialchars_output($_GET['_mboxes'], 'js')));
+ else if ($_GET['_remote'])
+ {
+ $commands = show_message('errorsaving', 'error');
+ rcube_remote_response($commands);
+ }
}
@@ -174,5 +179,9 @@ function rcube_create_folder_form($attrib)
}
+// add some labels to client
+rcube_add_label('deletefolderconfirm');
+
+
parse_template('managefolders');
?> \ No newline at end of file
diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc
index 2e42987bf..dc61b7875 100644
--- a/program/steps/settings/save_identity.inc
+++ b/program/steps/settings/save_identity.inc
@@ -19,7 +19,7 @@
*/
-$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'default');
+$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'standard', 'signature');
// check input
@@ -51,7 +51,7 @@ if ($_POST['_iid'])
SET ".join(', ', $a_write_sql)."
WHERE identity_id=?
AND user_id=?
- AND del<>'1'",
+ AND del<>1",
$_POST['_iid'],
$_SESSION['user_id']);
@@ -64,10 +64,10 @@ if ($_POST['_iid'])
// mark all other identities as 'not-default'
$DB->query("UPDATE ".get_table_name('identities')."
- SET ".$DB->quoteIdentifier('default')."='0'
+ SET ".$DB->quoteIdentifier('standard')."='0'
WHERE user_id=?
AND identity_id<>?
- AND del<>'1'",
+ AND del<>1",
$_SESSION['user_id'],
$_POST['_iid']);
@@ -106,8 +106,8 @@ else
(user_id, ".join(', ', $a_insert_cols).")
VALUES (?, ".join(', ', $a_insert_values).")",
$_SESSION['user_id']);
-
- $insert_id = $DB->insert_id();
+
+ $insert_id = $DB->insert_id(get_sequence_name('identities'));
}
if ($insert_id)
diff --git a/skins/default/images/sort_asc.gif b/skins/default/images/sort_asc.gif
new file mode 100644
index 000000000..244db104c
--- /dev/null
+++ b/skins/default/images/sort_asc.gif
Binary files differ
diff --git a/skins/default/images/sort_desc.gif b/skins/default/images/sort_desc.gif
new file mode 100644
index 000000000..2427311b4
--- /dev/null
+++ b/skins/default/images/sort_desc.gif
Binary files differ
diff --git a/skins/default/mail.css b/skins/default/mail.css
index f429407dd..9d507fe7b 100644
--- a/skins/default/mail.css
+++ b/skins/default/mail.css
@@ -75,9 +75,10 @@
position: absolute;
top: 60px;
right: 40px;
- width: 200px;
+ width: 220px;
height: 20px;
text-align: right;
+ white-space: nowrap;
}
#messagecountbar span
@@ -332,6 +333,26 @@ body.messagelist
background-image: url(images/listheader_dark.gif);
}
+#messagelist thead tr td.sortedASC a
+{
+ background: url(images/sort_asc.gif) top right no-repeat;
+}
+
+#messagelist thead tr td.sortedDESC a
+{
+ background: url(images/sort_desc.gif) top right no-repeat;
+}
+
+#messagelist thead tr td a,
+#messagelist thead tr td a:hover
+{
+ display: block;
+ width: auto !important;
+ width: 100%;
+ color: #333333;
+ text-decoration: none;
+}
+
#messagelist tbody tr td
{
height: 16px !important;
@@ -645,9 +666,10 @@ div.message-part pre
#compose-body
{
margin-top: 10px;
+ margin-bottom: 5px;
width: 99% !important;
width: 95%;
- height: 95%;
+ height: 90%;
min-height: 300px;
font-size: 9pt;
font-family: "Courier New", Courier, monospace;
@@ -702,4 +724,3 @@ div.message-part pre
margin-top: 8px;
}
-
diff --git a/skins/default/pngbehavior.htc b/skins/default/pngbehavior.htc
index 553699a2f..24bfd4c79 100644
--- a/skins/default/pngbehavior.htc
+++ b/skins/default/pngbehavior.htc
@@ -40,7 +40,7 @@ function fixImage() {
element.src = blankSrc;
// set filter
element.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
- src + "',sizingMethod='scale')";
+ src + "',sizingMethod='crop')";
}
else {
// remove filter
diff --git a/skins/default/templates/compose.html b/skins/default/templates/compose.html
index aa28098c8..0a3f874ae 100644
--- a/skins/default/templates/compose.html
+++ b/skins/default/templates/compose.html
@@ -87,8 +87,9 @@ function rcmail_toggle_display(id)
</tr><tr>
-<td style="width:100%; height:100%; vertical-align:top;">
-<roundcube:object name="composeBody" id="compose-body" form="form" cols="80" rows="20" warp="virtual" tabindex="7" />
+<td style="width:100%; height:95%; vertical-align:top;">
+<roundcube:object name="composeBody" id="compose-body" form="form" cols="80" rows="20" warp="virtual" tabindex="7" /><br />
+<roundcube:label name="charset" />:&nbsp;<roundcube:object name="charsetSelector" tabindex="8" />
</td>
</tr></table>
diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html
index 61d0e6d52..0f87c635d 100644
--- a/skins/default/templates/mail.html
+++ b/skins/default/templates/mail.html
@@ -37,9 +37,7 @@
messageIcon="/images/icons/dot.png"
unreadIcon="/images/icons/unread.png"
repliedIcon="/images/icons/replied.png"
- attachmentIcon="/images/icons/attachment.png"
- sortDescButton="/images/buttons/up_arrow.png"
- sortAscButton="/images/buttons/down_arrow.png" />
+ attachmentIcon="/images/icons/attachment.png" />
</div>
<div id="listcontrols">