From 4e17e6c9dbac8991ee8b302cb2581241247dc8bc Mon Sep 17 00:00:00 2001 From: thomascube Date: Sun, 25 Sep 2005 14:18:03 +0000 Subject: [PATCH] Initial revision --- .htaccess | 12 + CHANGELOG | 26 + INSTALL | 32 + SQL/initial.sql | 93 + UPGRADING | 15 + config/.htaccess | 2 + config/db.inc.php | 46 + config/main.inc.php | 96 + index.php | 273 ++ logs/.htaccess | 2 + logs/errors | 0 logs/sendmail | 0 program/blank.gif | Bin 0 -> 56 bytes program/include/bugs.inc | 104 + program/include/cache.inc | 112 + program/include/main.inc | 1020 +++++++ program/include/rcube_imap.inc | 1117 ++++++++ program/include/rcube_mysql.inc | 186 ++ program/include/rcube_shared.inc | 1417 ++++++++++ program/include/session.inc | 154 ++ program/js/app.js | 2388 +++++++++++++++++ program/js/common.js | 343 +++ program/lib/Mail/mime.php | 733 +++++ program/lib/Mail/mimeDecode.php | 842 ++++++ program/lib/Mail/mimePart.php | 351 +++ program/lib/PEAR.php | 927 +++++++ program/lib/des.inc | 218 ++ program/lib/enriched.inc | 114 + program/lib/html2text.inc | 440 +++ program/lib/icl_commons.inc | 81 + program/lib/imap.inc | 2038 ++++++++++++++ program/lib/mime.inc | 322 +++ program/lib/smtp.inc | 351 +++ program/lib/utf7.inc | 384 +++ program/lib/utf8.inc | 102 + program/localization/de/labels.inc | 171 ++ program/localization/de/messages.inc | 56 + program/localization/en/labels.inc | 171 ++ program/localization/en/messages.inc | 56 + program/steps/addressbook/delete.inc | 104 + program/steps/addressbook/edit.inc | 123 + program/steps/addressbook/func.inc | 198 ++ program/steps/addressbook/list.inc | 59 + program/steps/addressbook/save.inc | 168 ++ program/steps/addressbook/show.inc | 81 + program/steps/error.inc | 117 + program/steps/mail/addcontact.inc | 70 + program/steps/mail/compose.inc | 545 ++++ program/steps/mail/func.inc | 1101 ++++++++ program/steps/mail/get.inc | 159 ++ program/steps/mail/list.inc | 49 + program/steps/mail/mark.inc | 41 + program/steps/mail/move_del.inc | 82 + program/steps/mail/sendmail.inc | 251 ++ program/steps/mail/show.inc | 169 ++ program/steps/mail/upload.inc | 75 + program/steps/mail/viewsource.inc | 39 + program/steps/settings/delete_identity.inc | 55 + program/steps/settings/edit_identity.inc | 106 + program/steps/settings/func.inc | 194 ++ program/steps/settings/identities.inc | 48 + program/steps/settings/manage_folders.inc | 176 ++ program/steps/settings/save_identity.inc | 136 + program/steps/settings/save_prefs.inc | 59 + skins/default/addresses.css | 119 + skins/default/common.css | 277 ++ skins/default/images/blank.gif | Bin 0 -> 56 bytes skins/default/images/buttons/add_act.png | Bin 0 -> 295 bytes .../images/buttons/add_contact_act.png | Bin 0 -> 1626 bytes .../images/buttons/add_contact_pas.png | Bin 0 -> 1599 bytes skins/default/images/buttons/add_pas.png | Bin 0 -> 301 bytes skins/default/images/buttons/addressbook.png | Bin 0 -> 1768 bytes skins/default/images/buttons/attach_act.png | Bin 0 -> 1776 bytes skins/default/images/buttons/attach_pas.png | Bin 0 -> 1750 bytes skins/default/images/buttons/back_act.png | Bin 0 -> 1321 bytes skins/default/images/buttons/back_pas.png | Bin 0 -> 1317 bytes skins/default/images/buttons/bg.gif | Bin 0 -> 211 bytes skins/default/images/buttons/compose_act.png | Bin 0 -> 1650 bytes skins/default/images/buttons/compose_pas.png | Bin 0 -> 1617 bytes skins/default/images/buttons/contacts_act.png | Bin 0 -> 1742 bytes skins/default/images/buttons/contacts_pas.png | Bin 0 -> 1721 bytes skins/default/images/buttons/delete_act.png | Bin 0 -> 2107 bytes skins/default/images/buttons/delete_pas.png | Bin 0 -> 2070 bytes skins/default/images/buttons/download_act.png | Bin 0 -> 2133 bytes skins/default/images/buttons/download_pas.png | Bin 0 -> 2107 bytes .../images/buttons/edit_contact_act.png | Bin 0 -> 2157 bytes .../images/buttons/edit_contact_pas.png | Bin 0 -> 2135 bytes skins/default/images/buttons/forward_act.png | Bin 0 -> 1502 bytes skins/default/images/buttons/forward_pas.png | Bin 0 -> 1472 bytes skins/default/images/buttons/inbox_act.png | Bin 0 -> 1827 bytes skins/default/images/buttons/inbox_pas.png | Bin 0 -> 1804 bytes skins/default/images/buttons/logout.gif | Bin 0 -> 454 bytes skins/default/images/buttons/logout.png | Bin 0 -> 2036 bytes skins/default/images/buttons/mail.png | Bin 0 -> 1827 bytes skins/default/images/buttons/next_act.png | Bin 0 -> 267 bytes skins/default/images/buttons/next_pas.png | Bin 0 -> 260 bytes skins/default/images/buttons/previous_act.png | Bin 0 -> 262 bytes skins/default/images/buttons/previous_pas.png | Bin 0 -> 277 bytes skins/default/images/buttons/print_act.png | Bin 0 -> 1468 bytes skins/default/images/buttons/print_pas.png | Bin 0 -> 1464 bytes skins/default/images/buttons/reply_act.png | Bin 0 -> 1775 bytes skins/default/images/buttons/reply_pas.png | Bin 0 -> 1754 bytes skins/default/images/buttons/send_act.png | Bin 0 -> 1820 bytes skins/default/images/buttons/send_pas.png | Bin 0 -> 1836 bytes skins/default/images/buttons/settings.png | Bin 0 -> 1054 bytes skins/default/images/buttons/source_act.png | Bin 0 -> 1657 bytes skins/default/images/buttons/source_pas.png | Bin 0 -> 1632 bytes skins/default/images/buttons/spacer.gif | Bin 0 -> 43 bytes skins/default/images/display/confirm.png | Bin 0 -> 2135 bytes skins/default/images/display/info.png | Bin 0 -> 2162 bytes skins/default/images/display/loading.gif | Bin 0 -> 2964 bytes skins/default/images/display/warning.png | Bin 0 -> 1422 bytes skins/default/images/icons/abcard.png | Bin 0 -> 441 bytes skins/default/images/icons/attachment.png | Bin 0 -> 657 bytes skins/default/images/icons/dot.png | Bin 0 -> 244 bytes skins/default/images/icons/flagged.png | Bin 0 -> 514 bytes skins/default/images/icons/folder-closed.png | Bin 0 -> 662 bytes skins/default/images/icons/folder-inbox.png | Bin 0 -> 586 bytes skins/default/images/icons/folder-junk.png | Bin 0 -> 800 bytes skins/default/images/icons/folder-open.png | Bin 0 -> 796 bytes skins/default/images/icons/folder-sent.png | Bin 0 -> 629 bytes skins/default/images/icons/folder-trash.png | Bin 0 -> 775 bytes skins/default/images/icons/forwarded.png | Bin 0 -> 315 bytes skins/default/images/icons/plus.gif | Bin 0 -> 93 bytes skins/default/images/icons/replied.png | Bin 0 -> 317 bytes skins/default/images/icons/silhouette.png | Bin 0 -> 261 bytes skins/default/images/icons/unread.png | Bin 0 -> 460 bytes skins/default/images/listheader_aqua.gif | Bin 0 -> 270 bytes skins/default/images/listheader_dark.gif | Bin 0 -> 280 bytes skins/default/images/listheader_light.gif | Bin 0 -> 261 bytes skins/default/images/mailbox_list.gif | Bin 0 -> 207 bytes skins/default/images/mailbox_selected.gif | Bin 0 -> 158 bytes skins/default/images/rcube_watermark.png | Bin 0 -> 16441 bytes skins/default/images/roundcube_logo.gif | Bin 0 -> 2284 bytes skins/default/images/roundcube_logo.png | Bin 0 -> 4868 bytes skins/default/images/roundcube_logo_print.gif | Bin 0 -> 2400 bytes skins/default/images/tab_act.gif | Bin 0 -> 519 bytes skins/default/images/tab_pas.gif | Bin 0 -> 511 bytes skins/default/includes/header.html | 3 + skins/default/includes/settingscripts.html | 11 + skins/default/includes/settingstabs.html | 3 + skins/default/includes/taskbar.html | 14 + skins/default/mail.css | 647 +++++ skins/default/pngbehavior.htc | 52 + skins/default/print.css | 111 + skins/default/settings.css | 150 ++ skins/default/templates/addcontact.html | 24 + skins/default/templates/addidentity.html | 35 + skins/default/templates/addressbook.html | 37 + skins/default/templates/compose.html | 118 + skins/default/templates/editcontact.html | 24 + skins/default/templates/editidentity.html | 37 + skins/default/templates/error.html | 16 + skins/default/templates/identities.html | 23 + skins/default/templates/login.html | 30 + skins/default/templates/mail.html | 50 + skins/default/templates/managefolders.html | 38 + skins/default/templates/message.html | 41 + skins/default/templates/messagepart.html | 22 + skins/default/templates/printmessage.html | 18 + skins/default/templates/settings.html | 28 + skins/default/templates/showcontact.html | 19 + skins/default/watermark.html | 12 + temp/.htaccess | 2 + 164 files changed, 20961 insertions(+) create mode 100644 .htaccess create mode 100644 CHANGELOG create mode 100644 INSTALL create mode 100644 SQL/initial.sql create mode 100644 UPGRADING create mode 100644 config/.htaccess create mode 100644 config/db.inc.php create mode 100644 config/main.inc.php create mode 100644 index.php create mode 100644 logs/.htaccess create mode 100644 logs/errors create mode 100644 logs/sendmail create mode 100644 program/blank.gif create mode 100644 program/include/bugs.inc create mode 100644 program/include/cache.inc create mode 100644 program/include/main.inc create mode 100644 program/include/rcube_imap.inc create mode 100644 program/include/rcube_mysql.inc create mode 100644 program/include/rcube_shared.inc create mode 100644 program/include/session.inc create mode 100644 program/js/app.js create mode 100644 program/js/common.js create mode 100644 program/lib/Mail/mime.php create mode 100644 program/lib/Mail/mimeDecode.php create mode 100644 program/lib/Mail/mimePart.php create mode 100644 program/lib/PEAR.php create mode 100644 program/lib/des.inc create mode 100644 program/lib/enriched.inc create mode 100644 program/lib/html2text.inc create mode 100644 program/lib/icl_commons.inc create mode 100644 program/lib/imap.inc create mode 100644 program/lib/mime.inc create mode 100644 program/lib/smtp.inc create mode 100644 program/lib/utf7.inc create mode 100644 program/lib/utf8.inc create mode 100644 program/localization/de/labels.inc create mode 100644 program/localization/de/messages.inc create mode 100644 program/localization/en/labels.inc create mode 100644 program/localization/en/messages.inc create mode 100644 program/steps/addressbook/delete.inc create mode 100644 program/steps/addressbook/edit.inc create mode 100644 program/steps/addressbook/func.inc create mode 100644 program/steps/addressbook/list.inc create mode 100644 program/steps/addressbook/save.inc create mode 100644 program/steps/addressbook/show.inc create mode 100644 program/steps/error.inc create mode 100644 program/steps/mail/addcontact.inc create mode 100644 program/steps/mail/compose.inc create mode 100644 program/steps/mail/func.inc create mode 100644 program/steps/mail/get.inc create mode 100644 program/steps/mail/list.inc create mode 100644 program/steps/mail/mark.inc create mode 100644 program/steps/mail/move_del.inc create mode 100644 program/steps/mail/sendmail.inc create mode 100644 program/steps/mail/show.inc create mode 100644 program/steps/mail/upload.inc create mode 100644 program/steps/mail/viewsource.inc create mode 100644 program/steps/settings/delete_identity.inc create mode 100644 program/steps/settings/edit_identity.inc create mode 100644 program/steps/settings/func.inc create mode 100644 program/steps/settings/identities.inc create mode 100644 program/steps/settings/manage_folders.inc create mode 100644 program/steps/settings/save_identity.inc create mode 100644 program/steps/settings/save_prefs.inc create mode 100644 skins/default/addresses.css create mode 100755 skins/default/common.css create mode 100644 skins/default/images/blank.gif create mode 100644 skins/default/images/buttons/add_act.png create mode 100644 skins/default/images/buttons/add_contact_act.png create mode 100644 skins/default/images/buttons/add_contact_pas.png create mode 100644 skins/default/images/buttons/add_pas.png create mode 100644 skins/default/images/buttons/addressbook.png create mode 100644 skins/default/images/buttons/attach_act.png create mode 100644 skins/default/images/buttons/attach_pas.png create mode 100644 skins/default/images/buttons/back_act.png create mode 100644 skins/default/images/buttons/back_pas.png create mode 100644 skins/default/images/buttons/bg.gif create mode 100644 skins/default/images/buttons/compose_act.png create mode 100644 skins/default/images/buttons/compose_pas.png create mode 100644 skins/default/images/buttons/contacts_act.png create mode 100644 skins/default/images/buttons/contacts_pas.png create mode 100644 skins/default/images/buttons/delete_act.png create mode 100644 skins/default/images/buttons/delete_pas.png create mode 100644 skins/default/images/buttons/download_act.png create mode 100644 skins/default/images/buttons/download_pas.png create mode 100644 skins/default/images/buttons/edit_contact_act.png create mode 100644 skins/default/images/buttons/edit_contact_pas.png create mode 100644 skins/default/images/buttons/forward_act.png create mode 100644 skins/default/images/buttons/forward_pas.png create mode 100644 skins/default/images/buttons/inbox_act.png create mode 100644 skins/default/images/buttons/inbox_pas.png create mode 100644 skins/default/images/buttons/logout.gif create mode 100644 skins/default/images/buttons/logout.png create mode 100644 skins/default/images/buttons/mail.png create mode 100644 skins/default/images/buttons/next_act.png create mode 100644 skins/default/images/buttons/next_pas.png create mode 100644 skins/default/images/buttons/previous_act.png create mode 100644 skins/default/images/buttons/previous_pas.png create mode 100644 skins/default/images/buttons/print_act.png create mode 100644 skins/default/images/buttons/print_pas.png create mode 100644 skins/default/images/buttons/reply_act.png create mode 100644 skins/default/images/buttons/reply_pas.png create mode 100644 skins/default/images/buttons/send_act.png create mode 100644 skins/default/images/buttons/send_pas.png create mode 100644 skins/default/images/buttons/settings.png create mode 100644 skins/default/images/buttons/source_act.png create mode 100644 skins/default/images/buttons/source_pas.png create mode 100644 skins/default/images/buttons/spacer.gif create mode 100644 skins/default/images/display/confirm.png create mode 100644 skins/default/images/display/info.png create mode 100755 skins/default/images/display/loading.gif create mode 100644 skins/default/images/display/warning.png create mode 100644 skins/default/images/icons/abcard.png create mode 100644 skins/default/images/icons/attachment.png create mode 100644 skins/default/images/icons/dot.png create mode 100644 skins/default/images/icons/flagged.png create mode 100644 skins/default/images/icons/folder-closed.png create mode 100644 skins/default/images/icons/folder-inbox.png create mode 100644 skins/default/images/icons/folder-junk.png create mode 100644 skins/default/images/icons/folder-open.png create mode 100644 skins/default/images/icons/folder-sent.png create mode 100644 skins/default/images/icons/folder-trash.png create mode 100644 skins/default/images/icons/forwarded.png create mode 100755 skins/default/images/icons/plus.gif create mode 100644 skins/default/images/icons/replied.png create mode 100644 skins/default/images/icons/silhouette.png create mode 100644 skins/default/images/icons/unread.png create mode 100644 skins/default/images/listheader_aqua.gif create mode 100644 skins/default/images/listheader_dark.gif create mode 100644 skins/default/images/listheader_light.gif create mode 100644 skins/default/images/mailbox_list.gif create mode 100644 skins/default/images/mailbox_selected.gif create mode 100644 skins/default/images/rcube_watermark.png create mode 100644 skins/default/images/roundcube_logo.gif create mode 100644 skins/default/images/roundcube_logo.png create mode 100644 skins/default/images/roundcube_logo_print.gif create mode 100644 skins/default/images/tab_act.gif create mode 100644 skins/default/images/tab_pas.gif create mode 100644 skins/default/includes/header.html create mode 100644 skins/default/includes/settingscripts.html create mode 100644 skins/default/includes/settingstabs.html create mode 100644 skins/default/includes/taskbar.html create mode 100644 skins/default/mail.css create mode 100644 skins/default/pngbehavior.htc create mode 100644 skins/default/print.css create mode 100644 skins/default/settings.css create mode 100644 skins/default/templates/addcontact.html create mode 100644 skins/default/templates/addidentity.html create mode 100644 skins/default/templates/addressbook.html create mode 100644 skins/default/templates/compose.html create mode 100644 skins/default/templates/editcontact.html create mode 100644 skins/default/templates/editidentity.html create mode 100644 skins/default/templates/error.html create mode 100644 skins/default/templates/identities.html create mode 100644 skins/default/templates/login.html create mode 100644 skins/default/templates/mail.html create mode 100644 skins/default/templates/managefolders.html create mode 100644 skins/default/templates/message.html create mode 100644 skins/default/templates/messagepart.html create mode 100644 skins/default/templates/printmessage.html create mode 100644 skins/default/templates/settings.html create mode 100644 skins/default/templates/showcontact.html create mode 100644 skins/default/watermark.html create mode 100644 temp/.htaccess diff --git a/.htaccess b/.htaccess new file mode 100644 index 000000000..c0ab7f0ae --- /dev/null +++ b/.htaccess @@ -0,0 +1,12 @@ +php_flag display_errors On +php_value session.gc_maxlifetime 21600 +php_value session.gc_divisor 500 +php_value upload_max_filesize 2m + + + Order allow,deny + Deny from all + + +Order deny,allow +Allow from all diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 000000000..1fa699292 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,26 @@ +CHANGELOG RoundCube Webmail +--------------------------- + +2005/08/11 +---------- +- Write list header to client even if list is empty +- Add functions "select all", "select none" to message list +- Improved filter for HTML messages to remove potentially malicious tags (script, iframe, object) and event handlers. +- Buttons for next/previous message in view mode +- Add new created contact to list and show confirmation status +- Added folder management (subscribe/create/delete) +- Log message sending (SMTP log) +- Grant access for Camino browser +- Added German translation + + +2005/08/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 diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..5317b80d5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,32 @@ + +INSTALLATION +============ + +1. Decompress and put this folder somewhere inside your document root +2. Make shure that the following directories are writable by the webserver + - /temp + - /logs +3. Modify the files in /config to suit your local environment +4. Create database tables using the queries in file 'SQL/initial.sql' + Rename tables if you like, but make shure the names are also changed in /config/db.inc +5. Done! + + +REQUIREMENTS +============ + +* The Apache Webserver +* .htaccess support allowing overrides for DirectoryIndex +* PHP Version 4.3.1 or greater +* php.ini options: + - error_reporting E_ALL & ~E_NOTICE (or lower) + - file_uploads on (for attachment upload features) +* The MySQL database engine +* A database with permission to create tables + + +CONFIGURATION +============= + +Change the files in /config/ according your environment and you needs. +Details about the config paramaters can be found in the config files. diff --git a/SQL/initial.sql b/SQL/initial.sql new file mode 100644 index 000000000..64d650867 --- /dev/null +++ b/SQL/initial.sql @@ -0,0 +1,93 @@ +-- RoundCube Webmail initial database structure +-- Version 0.1a +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cache` +-- + +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, + `cache_key` varchar(128) NOT NULL default '', + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `data` longtext NOT NULL, + PRIMARY KEY (`cache_id`), + KEY `user_id` (`user_id`), + KEY `cache_key` (`cache_key`), + KEY `session_id` (`session_id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `contacts` +-- + +CREATE TABLE `contacts` ( + `contact_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', + `name` varchar(128) NOT NULL default '', + `email` varchar(128) NOT NULL default '', + `firstname` varchar(128) NOT NULL default '', + `surname` varchar(128) NOT NULL default '', + `vcard` text NOT NULL, + PRIMARY KEY (`contact_id`), + KEY `user_id` (`user_id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `identities` +-- + +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', + `name` varchar(128) NOT NULL default '', + `organization` varchar(128) NOT NULL default '', + `email` varchar(128) NOT NULL default '', + `reply-to` varchar(128) NOT NULL default '', + `bcc` varchar(128) NOT NULL default '', + `signature` text NOT NULL, + PRIMARY KEY (`identity_id`), + KEY `user_id` (`user_id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `session` +-- + +CREATE TABLE `session` ( + `sess_id` varchar(32) NOT NULL default '', + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `changed` datetime NOT NULL default '0000-00-00 00:00:00', + `vars` text NOT NULL, + PRIMARY KEY (`sess_id`) +) TYPE=MyISAM; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `user_id` int(10) unsigned NOT NULL auto_increment, + `username` varchar(128) NOT NULL default '', + `mail_host` varchar(255) NOT NULL default '', + `created` datetime NOT NULL default '0000-00-00 00:00:00', + `last_login` datetime NOT NULL default '0000-00-00 00:00:00', + `language` varchar(5) NOT NULL default 'en', + `preferences` text NOT NULL, + PRIMARY KEY (`user_id`) +) TYPE=MyISAM; diff --git a/UPGRADING b/UPGRADING new file mode 100644 index 000000000..368f0480e --- /dev/null +++ b/UPGRADING @@ -0,0 +1,15 @@ +UPDATE instructions +=================== + +Follow these instructions if upgrading from a previous version +of RoundCube Webmail. + + + +from versions 0.1-alpha and 0.1-20050811 +---------------------------------------- +- replace all files in folder /program/ +- add these line to /config/main.inc.php + $rcmail_config['trash_mbox'] = 'Trash'; + $rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash'); + $rcmail_config['prefer_html'] = TRUE; diff --git a/config/.htaccess b/config/.htaccess new file mode 100644 index 000000000..8e6a345dc --- /dev/null +++ b/config/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all \ No newline at end of file diff --git a/config/db.inc.php b/config/db.inc.php new file mode 100644 index 000000000..fb6d2bb8b --- /dev/null +++ b/config/db.inc.php @@ -0,0 +1,46 @@ + diff --git a/config/main.inc.php b/config/main.inc.php new file mode 100644 index 000000000..0e580318b --- /dev/null +++ b/config/main.inc.php @@ -0,0 +1,96 @@ + diff --git a/index.php b/index.php new file mode 100644 index 000000000..19623aa30 --- /dev/null +++ b/index.php @@ -0,0 +1,273 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +// define global vars +$INSTALL_PATH = './'; +$OUTPUT_TYPE = 'html'; +$JS_OBJECT_NAME = 'rcmail'; + + +// set environment first +ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.'program'.PATH_SEPARATOR.'program/lib'); +ini_set('session.name', 'sessid'); +ini_set('session.use_cookies', 1); +//ini_set('session.save_path', $INSTALL_PATH.'session'); + + +// increase maximum execution time for php scripts +set_time_limit('120'); + + +// include base files +require_once('include/rcube_shared.inc'); +require_once('include/rcube_imap.inc'); +require_once('include/rcube_mysql.inc'); +require_once('include/bugs.inc'); +require_once('include/main.inc'); +require_once('include/cache.inc'); + + +// catch some url/post parameters +$_auth = strlen($_POST['_auth']) ? $_POST['_auth'] : $_GET['_auth']; +$_task = strlen($_POST['_task']) ? $_POST['_task'] : ($_GET['_task'] ? $_GET['_task'] : 'mail'); +$_action = strlen($_POST['_action']) ? $_POST['_action'] : $_GET['_action']; +$_framed = ($_GET['_framed'] || $_POST['_framed']); + +// start session with requested task +rcmail_startup($_task); + + +// set session related variables +$COMM_PATH = sprintf('./?_auth=%s&_task=%s', $sess_auth, $_task); +$SESS_HIDDEN_FIELD = sprintf('', $sess_auth); + + +// add framed parameter +if ($_GET['_framed'] || $_POST['_framed']) + { + $COMM_PATH .= '&_framed=1'; + $SESS_HIDDEN_FIELD = "\n".''; + } + + +// init necessary objects for GUI +load_gui(); + + +// error steps +if ($_action=='error' && strlen($_GET['_code'])) + { + raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE); + } + + +// try to log in +if ($_action=='login' && $_task=='mail') + { + $host = $_POST['_host'] ? $_POST['_host'] : $CONFIG['default_host']; + + // check if client supports cookies + if (!$_COOKIE[session_name()]) + { + show_message("cookiesdisabled", 'warning'); + } + else if ($_POST['_user'] && $_POST['_pass'] && rcmail_login($_POST['_user'], $_POST['_pass'], $host)) + { + // send redirect + header("Location: $COMM_PATH"); + exit; + } + else + { + show_message("loginfailed", 'warning'); + $_SESSION['user_id'] = ''; + } + } + +// end session +else if ($_action=='logout' && $_SESSION['user_id']) + { + show_message('loggedout'); + rcmail_kill_session(); + } + +// check session cookie and auth string +else if ($_action!='login' && $_auth && $sess_auth) + { + if ($_auth !== $sess_auth || $_auth != rcmail_auth_hash($_SESSION['client_id'], $_SESSION['auth_time'])) + { + show_message('sessionerror', 'error'); + rcmail_kill_session(); + } + } + + +// log in to imap server +if ($_SESSION['user_id'] && $_task=='mail') + { + $conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password'])); + if (!$conn) + { + show_message('imaperror', 'error'); + $_SESSION['user_id'] = ''; + } + } + + +// not logged in -> set task to 'login +if (!$_SESSION['user_id']) + $_task = 'login'; + + + +// set taask and action to client +$script = sprintf("%s.set_env('task', '%s');", $JS_OBJECT_NAME, $_task); +if (!empty($_action)) + $script .= sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action); + +$OUTPUT->add_script($script); + + + +// not logged in -> show login page +if (!$_SESSION['user_id']) + { + parse_template('login'); + exit; + } + + + +// include task specific files +if ($_task=='mail') + { + include_once('program/steps/mail/func.inc'); + + if ($_action=='show' || $_action=='print') + include('program/steps/mail/show.inc'); + + if ($_action=='get') + include('program/steps/mail/get.inc'); + + if ($_action=='moveto' || $_action=='delete') + include('program/steps/mail/move_del.inc'); + + if ($_action=='mark') + include('program/steps/mail/mark.inc'); + + if ($_action=='viewsource') + include('program/steps/mail/viewsource.inc'); + + if ($_action=='send') + include('program/steps/mail/sendmail.inc'); + + if ($_action=='upload') + include('program/steps/mail/upload.inc'); + + if ($_action=='compose') + include('program/steps/mail/compose.inc'); + + if ($_action=='addcontact') + include('program/steps/mail/addcontact.inc'); + + if ($_action=='list' && $_GET['_remote']) + include('program/steps/mail/list.inc'); + + // kill compose entry from session + if (isset($_SESSION['compose'])) + rcmail_compose_cleanup(); + } + + +// include task specific files +if ($_task=='addressbook') + { + include_once('program/steps/addressbook/func.inc'); + + if ($_action=='save') + include('program/steps/addressbook/save.inc'); + + if ($_action=='edit' || $_action=='add') + include('program/steps/addressbook/edit.inc'); + + if ($_action=='delete') + include('program/steps/addressbook/delete.inc'); + + if ($_action=='show') + include('program/steps/addressbook/show.inc'); + + if ($_action=='list' && $_GET['_remote']) + include('program/steps/addressbook/list.inc'); + } + + +// include task specific files +if ($_task=='settings') + { + include_once('program/steps/settings/func.inc'); + + if ($_action=='save-identity') + include('program/steps/settings/save_identity.inc'); + + if ($_action=='add-identity' || $_action=='edit-identity') + include('program/steps/settings/edit_identity.inc'); + + if ($_action=='delete-identity') + include('program/steps/settings/delete_identity.inc'); + + if ($_action=='identities') + include('program/steps/settings/identities.inc'); + + if ($_action=='save-prefs') + include('program/steps/settings/save_prefs.inc'); + + if ($_action=='folders' || $_action=='subscribe' || $_action=='unsubscribe' || $_action=='create-folder' || $_action=='delete-folder') + include('program/steps/settings/manage_folders.inc'); + + } + + +// parse main template +parse_template($_task); + +?> \ No newline at end of file diff --git a/logs/.htaccess b/logs/.htaccess new file mode 100644 index 000000000..8e6a345dc --- /dev/null +++ b/logs/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all \ No newline at end of file diff --git a/logs/errors b/logs/errors new file mode 100644 index 000000000..e69de29bb diff --git a/logs/sendmail b/logs/sendmail new file mode 100644 index 000000000..e69de29bb diff --git a/program/blank.gif b/program/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..ea83374c17e3cf315d0ecaccc57f682fe3012fb7 GIT binary patch literal 56 zcmZ?wbhEHb6k-r!XkcJCaNqy~1B2pE7Dgb&paUX6G7e1qE&VG`zvW*%XUnbb&G+Vr HGgt!vX#5YS literal 0 HcmV?d00001 diff --git a/program/include/bugs.inc b/program/include/bugs.inc new file mode 100644 index 000000000..819887cc3 --- /dev/null +++ b/program/include/bugs.inc @@ -0,0 +1,104 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +// throw system error and show error page +function raise_error($arg=array(), $log=FALSE, $terminate=FALSE) + { + global $__page_content, $CONFIG, $OUTPUT, $ERROR_CODE, $ERROR_MESSAGE; + + /* $arg keys: + int code + string type (php, xpath, db, imap, javascript) + string message + sring file + int line + */ + + // report bug (if not incompatible browser) + if ($log && $arg['type'] && $arg['message']) + log_bug($arg); + + // display error page and terminate script + if ($terminate) + { + $ERROR_CODE = $arg['code']; + $ERROR_MESSAGE = $arg['message']; + include("program/steps/error.inc"); + exit; + } + } + + +// report error +function log_bug($arg_arr) + { + global $CONFIG, $INSTALL_PATH; + $program = $arg_arr['type']=='xpath' ? 'XPath' : strtoupper($arg_arr['type']); + + // write error to local log file + if ($CONFIG['debug_level'] & 1) + { + $log_entry = sprintf("[%s] %s Error: %s in %s on line %d\n", + date("d-M-Y H:i:s O", mktime()), + $program, + $arg_arr['message'], + $arg_arr['file'], + $arg_arr['line']); + + if ($fp = fopen($INSTALL_PATH.'logs/errors', 'a')) + { + fwrite($fp, $log_entry); + fclose($fp); + } + } + +/* + // resport the bug to the global bug reporting system + if ($CONFIG['debug_level'] & 2) + { + $delm = '%AC'; + http_request(sprintf('http://roundcube.net/log/bug.php?_type=%s&_domain=%s&_server_ip=%s&_client_ip=%s&_useragent=%s&_url=%s%%3A//%s&_errors=%s%s%s%s%s', + $arg_arr['type'], + $GLOBALS['HTTP_HOST'], + $GLOBALS['SERVER_ADDR'], + $GLOBALS['REMOTE_ADDR'], + rawurlencode($GLOBALS['HTTP_USER_AGENT']), + $GLOBALS['SERVER_PORT']==43 ? 'https' : 'http', + $GLOBALS['HTTP_HOST'].$GLOBALS['REQUEST_URI'], + $arg_arr['file'], $delm, + $arg_arr['line'], $delm, + rawurlencode($arg_arr['message']))); + } +*/ + + // show error if debug_mode is on + if ($CONFIG['debug_level'] & 4) + { + print "$program Error in $arg_arr[file] ($arg_arr[line]): "; + print nl2br($arg_arr['message']); + print '
'; + flush(); + } + } + + +?> \ No newline at end of file diff --git a/program/include/cache.inc b/program/include/cache.inc new file mode 100644 index 000000000..84ed8f07f --- /dev/null +++ b/program/include/cache.inc @@ -0,0 +1,112 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +function rcube_read_cache($key) + { + global $DB, $CACHE_KEYS; + + // query db + $sql_result = $DB->query(sprintf("SELECT cache_id, data + FROM %s + WHERE user_id=%d + AND cache_key='%s'", + get_table_name('cache'), + $_SESSION['user_id'], + $key)); + + // get cached data + if ($sql_arr = $DB->fetch_assoc($sql_result)) + { + $data = $sql_arr['data']; + $CACHE_KEYS[$key] = $sql_arr['cache_id']; + } + else + $data = FALSE; + + return $data; + } + + +function rcube_write_cache($key, $data, $session_cache=FALSE) + { + global $DB, $CACHE_KEYS, $sess_id; + + // check if we already have a cache entry for this key + if (!isset($CACHE_KEYS[$key])) + { + $sql_result = $DB->query(sprintf("SELECT cache_id + FROM %s + WHERE user_id=%d + AND cache_key='%s'", + get_table_name('cache'), + $_SESSION['user_id'], + $key)); + + if ($sql_arr = $DB->fetch_assoc($sql_result)) + $CACHE_KEYS[$key] = $sql_arr['cache_id']; + else + $CACHE_KEYS[$key] = FALSE; + } + + // update existing cache record + if ($CACHE_KEYS[$key]) + { + $DB->query(sprintf("UPDATE %s + SET created=NOW(), + data='%s' + WHERE user_id=%d + AND cache_key='%s'", + get_table_name('cache'), + addslashes($data), + $_SESSION['user_id'], + $key)); + } + // add new cache record + else + { + $DB->query(sprintf("INSERT INTO %s + (created, user_id, session_id, cache_key, data) + VALUES (NOW(), %d, %s, '%s', '%s')", + get_table_name('cache'), + $_SESSION['user_id'], + $session_cache ? "'$sess_id'" : 'NULL', + $key, + addslashes($data))); + } + } + + + +function rcube_clear_cache($key) + { + global $DB; + + $DB->query(sprintf("DELETE FROM %s + WHERE user_id=%d + AND cache_key='%s'", + get_table_name('cache'), + $_SESSION['user_id'], + $key)); + } + + +?> \ No newline at end of file diff --git a/program/include/main.inc b/program/include/main.inc new file mode 100644 index 000000000..8cbc271b1 --- /dev/null +++ b/program/include/main.inc @@ -0,0 +1,1020 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +require_once('lib/des.inc'); + + +// register session and connect to server +function rcmail_startup($task='mail') + { + global $sess_id, $sess_auth, $sess_user_lang; + global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB, $JS_OBJECT_NAME; + + // check client + $BROWSER = rcube_browser(); + + // load config file + include_once('config/main.inc.php'); + $CONFIG = is_array($rcmail_config) ? $rcmail_config : array(); + $CONFIG['skin_path'] = $CONFIG['skin_path'] ? preg_replace('/\/$/', '', $CONFIG['skin_path']) : 'skins/default'; + + // load db conf + include_once('config/db.inc.php'); + $CONFIG = array_merge($CONFIG, $rcmail_config); + + + // set PHP error logging according to config + if ($CONFIG['debug_level'] & 1) + { + ini_set('log_errors', 1); + ini_set('error_log', $INSTALL_PATH.'logs/errors'); + } + if ($CONFIG['debug_level'] & 4) + ini_set('display_errors', 1); + else + ini_set('display_errors', 0); + + + // prepare DB connection + if (strtolower($CONFIG['db_type'])=='mysql') + $DB = new rcube_mysql($CONFIG['db_name'], $CONFIG['db_user'], $CONFIG['db_pass'], $CONFIG['db_host']); + + // database not supported + else + { + raise_error(array('code' => 500, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Database not supported"), TRUE, TRUE); + return; + } + + + // we can use the database for storing session data + if (is_object($DB) && $DB->connect()) + include_once('include/session.inc'); + + + // init session + session_start(); + $sess_id = session_id(); + + // create session and set session vars + if (!$_SESSION['client_id']) + { + $_SESSION['client_id'] = $sess_id; + $_SESSION['user_lang'] = 'en'; + $_SESSION['auth_time'] = mktime(); + $_SESSION['auth'] = rcmail_auth_hash($sess_id, $_SESSION['auth_time']); + unset($GLOBALS['_auth']); + } + + // set session vars global + $sess_auth = $_SESSION['auth']; + $sess_user_lang = $_SESSION['user_lang']; + + + // overwrite config with user preferences + if (is_array($_SESSION['user_prefs'])) + $CONFIG = array_merge($CONFIG, $_SESSION['user_prefs']); + + + // reset some session parameters when changing task + if ($_SESSION['task'] != $task) + unset($_SESSION['page']); + + // set current task to session + $_SESSION['task'] = $task; + + + // create IMAP object + if ($task=='mail') + rcmail_imap_init(); + + + // set localization + if ($CONFIG['locale_string']) + setlocale(LC_ALL, $CONFIG['locale_string']); + else if ($sess_user_lang) + setlocale(LC_ALL, $sess_user_lang); + + + register_shutdown_function('rcmail_shutdown'); + } + + +// create authorization hash +function rcmail_auth_hash($sess_id, $ts) + { + global $CONFIG; + + $auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s', + $sess_id, + $ts, + $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***', + $_SERVER['HTTP_USER_AGENT']); + + if (function_exists('sha1')) + return sha1($auth_string); + else + return md5($auth_string); + } + + + +// create IMAP object and connect to server +function rcmail_imap_init($connect=FALSE) + { + global $CONFIG, $IMAP; + + $IMAP = new rcube_imap(); + + // set root dir from config + if (strlen($CONFIG['imap_root'])) + $IMAP->set_rootdir($CONFIG['imap_root']); + + if (is_array($CONFIG['default_imap_folders'])) + $IMAP->set_default_mailboxes($CONFIG['default_imap_folders']); + + if (strlen($_SESSION['mbox'])) + $IMAP->set_mailbox($_SESSION['mbox']); + + if (isset($_SESSION['page'])) + $IMAP->set_page($_SESSION['page']); + + // set pagesize from config + if (isset($CONFIG['pagesize'])) + $IMAP->set_pagesize($CONFIG['pagesize']); + + + // connect with stored session data + if ($connect) + { + if (!($conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password'])))) + show_message('imaperror', 'error'); + } + } + + +// do these things on script shutdown +function rcmail_shutdown() + { + global $IMAP; + + if (is_object($IMAP)) + { + $IMAP->close(); + $IMAP->write_cache(); + } + } + + +// destroy session data and remove cookie +function rcmail_kill_session() + { +/* $sess_name = session_name(); + if (isset($_COOKIE[$sess_name])) + setcookie($sess_name, '', time()-42000, '/'); +*/ + $_SESSION = array(); + session_destroy(); + } + + +// return correct name for a specific database table +function get_table_name($table) + { + global $CONFIG; + + // return table name if configured + $config_key = 'db_table_'.$table; + + if (strlen($CONFIG[$config_key])) + return $CONFIG[$config_key]; + + return $table; + } + + + +// init output object for GUI and add common scripts +function load_gui() + { + global $CONFIG, $OUTPUT, $COMM_PATH, $IMAP, $JS_OBJECT_NAME; + + // init output page + $OUTPUT = new rcube_html_page(); + + // add common javascripts + $javascript = "var $JS_OBJECT_NAME = new rcube_webmail();\n"; + $javascript .= "$JS_OBJECT_NAME.set_env('comm_path', '$COMM_PATH');\n"; + + if ($_GET['_framed'] || $_POST['_framed']) + $javascript .= "$JS_OBJECT_NAME.set_env('framed', true);\n"; + + $OUTPUT->add_script($javascript); + $OUTPUT->include_script('program/js/common.js'); + $OUTPUT->include_script('program/js/app.js'); + } + + +// perfom login to the IMAP server and to the webmail service +function rcmail_login($user, $pass, $host=NULL) + { + global $CONFIG, $IMAP, $DB, $sess_user_lang; + + if (!$host) + $host = $CONFIG['default_host']; + + // exit if IMAP login failed + if (!($imap_login = $IMAP->connect($host, $user, $pass))) + return FALSE; + + // query if user already registered + $sql_result = $DB->query(sprintf("SELECT user_id, language, preferences + FROM %s + WHERE username='%s' AND mail_host='%s'", + get_table_name('users'), + $user, $host)); + + // user already registered + if ($sql_arr = $DB->fetch_assoc($sql_result)) + { + $user_id = $sql_arr['user_id']; + + // get user prefs + if (strlen($sql_arr['preferences'])) + { + $user_prefs = unserialize($sql_arr['preferences']); + $_SESSION['user_prefs'] = $user_prefs; + array_merge($CONFIG, $user_prefs); + } + + // set user specific language + if (strlen($sql_arr['language'])) + $sess_user_lang = $_SESSION['user_lang'] = $sql_arr['language']; + + // update user's record + $DB->query(sprintf("UPDATE %s + SET last_login=NOW() + WHERE user_id=%d", + get_table_name('users'), + $user_id)); + } + // create new system user + else if ($CONFIG['auto_create_user']) + { + $user_id = rcmail_create_user($user, $host); + } + + if ($user_id) + { + $_SESSION['user_id'] = $user_id; + $_SESSION['imap_host'] = $host; + $_SESSION['username'] = $user; + $_SESSION['password'] = encrypt_passwd($pass); + + // force reloading complete list of subscribed mailboxes + $IMAP->clear_cache('mailboxes'); + + return TRUE; + } + + return FALSE; + } + + +// create new entry in users and identities table +function rcmail_create_user($user, $host) + { + global $DB, $CONFIG, $IMAP; + + $DB->query(sprintf("INSERT INTO %s + (created, last_login, username, mail_host) + VALUES (NOW(), NOW(), '%s', '%s')", + get_table_name('users'), + $user, $host)); + + if ($user_id = $DB->insert_id()) + { + // also create a new identity record + $DB->query(sprintf("INSERT INTO %s + (user_id, `default`, name, email) + VALUES (%d, '1', '%s', '%s@%s')", + get_table_name('identities'), + $user_id, + $user, + $user, + $host)); + + // get existing mailboxes + $a_mailboxes = $IMAP->list_mailboxes(); + + // check if the configured mailbox for sent messages exists + if ($CONFIG['sent_mbox'] && !in_array_nocase($CONFIG['sent_mbox'], $a_mailboxes)) + $IMAP->create_mailbox($CONFIG['sent_mbox'], TRUE); + + // check if the configured mailbox for sent messages exists + if ($CONFIG['trash_mbox'] && !in_array_nocase($CONFIG['trash_mbox'], $a_mailboxes)) + $IMAP->create_mailbox($CONFIG['trash_mbox'], TRUE); + } + + return $user_id; + } + + +function show_message($message, $type='notice') + { + global $OUTPUT, $JS_OBJECT_NAME, $REMOTE_REQUEST; + + $framed = ($_GET['framed'] || $_POST['_framed']); + $command = sprintf("display_message('%s', '%s');", + addslashes(rep_specialchars_output(rcube_label($message))), + $type); + + if ($REMOTE_REQUEST) + return 'this.'.$command; + + else + $OUTPUT->add_script(sprintf("%s%s.%s", + $framed ? sprintf('if(parent.%s)parent.', $JS_OBJECT_NAME) : '', + $JS_OBJECT_NAME, + $command)); + + // console(rcube_label($message)); + } + + +function console($msg, $type=1) + { + print $msg; + print "\n
\n"; + } + + +function encrypt_passwd($pass) + { + $cypher = des('rcmail?24BitPwDkeyF**ECB', $pass, 1, 0, NULL); + return base64_encode($cypher); + } + + +function decrypt_passwd($cypher) + { + $pass = des('rcmail?24BitPwDkeyF**ECB', base64_decode($cypher), 0, 0, NULL); + return trim($pass); + } + + +// send correct response on a remote request +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"; + print $js_code; + exit; + } + + + + +// ************** template parsing and gui functions ************** + + +// return boolean if a specific template exists +function template_exists($name) + { + global $CONFIG, $OUTPUT; + $skin_path = $CONFIG['skin_path']; + + // check template file + return is_file("$skin_path/templates/$name.html"); + } + + +// get page template an replace variable +// similar function as used in nexImage +function parse_template($name='main', $exit=TRUE) + { + global $CONFIG, $OUTPUT; + $skin_path = $CONFIG['skin_path']; + + // read template file + $templ = ''; + $path = "$skin_path/templates/$name.html"; + + if($fp = @fopen($path, 'r')) + { + $templ = fread($fp, filesize($path)); + fclose($fp); + } + else + { + raise_error(array('code' => 500, + 'type' => 'php', + 'line' => __LINE__, + 'file' => __FILE__, + 'message' => "Error loading template for '$name'"), TRUE, TRUE); + return FALSE; + } + + + // parse for specialtags + $output = parse_rcube_xml($templ); + + $OUTPUT->write(trim(parse_with_globals($output)), $skin_path); + + if ($exit) + exit; + } + + + +// replace all strings ($varname) with the content of the according global variable +function parse_with_globals($input) + { + $output = preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input); + return $output; + } + + + +function parse_rcube_xml($input) + { + $output = preg_replace('/]+)>/Uie', "rcube_xml_command('\\1', '\\2')", $input); + return $output; + } + + +function rcube_xml_command($command, $str_attrib, $a_attrib=NULL) + { + global $IMAP, $CONFIG; + + $attrib = array(); + $command = strtolower($command); + + preg_match_all('/\s*([-_a-z]+)=["]([^"]+)["]?/i', stripslashes($str_attrib), $regs, PREG_SET_ORDER); + + // convert attributes to an associative array (name => value) + if ($regs) + foreach ($regs as $attr) + $attrib[strtolower($attr[1])] = $attr[2]; + else if ($a_attrib) + $attrib = $a_attrib; + + // execute command + switch ($command) + { + // return a button + case 'button': + if ($attrib['command']) + return rcube_button($attrib); + break; + + // show a label + case 'label': + if ($attrib['name'] || $attrib['command']) + return rcube_label($attrib); + break; + + // create a menu item + case 'menu': + if ($attrib['command'] && $attrib['group']) + rcube_menu($attrib); + break; + + // include a file + case 'include': + $path = realpath($CONFIG['skin_path'].$attrib['file']); + + if($fp = @fopen($path, 'r')) + { + $incl = fread($fp, filesize($path)); + fclose($fp); + return parse_rcube_xml($incl); + } + break; + + // return code for a specific application object + case 'object': + $object = strtolower($attrib['name']); + + 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); + + + else if ($object=='pagetitle') + { + $task = $GLOBALS['_task']; + if ($task=='mail' && isset($GLOBALS['MESSAGE']['subject'])) + return rep_specialchars_output("RoundCube|Mail :: ".$GLOBALS['MESSAGE']['subject']); + else if (isset($GLOBALS['PAGE_TITLE'])) + return rep_specialchars_output("RoundCube|Mail :: ".$GLOBALS['PAGE_TITLE']); + else if ($task=='mail' && ($mbox_name = $IMAP->get_mailbox_name())) + return "RoundCube|Mail :: $mbox_name"; + else + return "RoundCube|Mail :: $task"; + } + + else if ($object=='about') + return ''; + + break; + } + + return ''; + } + + +// create and register a button +function rcube_button($attrib) + { + global $CONFIG, $OUTPUT, $JS_OBJECT_NAME; + static $sa_buttons = array(); + static $s_button_count = 100; + + $skin_path = $CONFIG['skin_path']; + + if (!($attrib['command'] || $attrib['name'])) + return ''; + + // try to find out the button type + if ($attrib['type']) + $attrib['type'] = strtolower($attrib['type']); + else + $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $arg['imagect']) ? 'image' : 'link'; + + + $command = $attrib['command']; + + // take the button from the stack + if($attrib['name'] && $sa_buttons[$attrib['name']]) + $attrib = $sa_buttons[$attrib['name']]; + + // add button to button stack + else if($attrib['image'] || $arg['imagect'] || $attrib['imagepas'] || $attrib['class']) + { + if(!$attrib['name']) + $attrib['name'] = $command; + + if (!$attrib['image']) + $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact']; + + $sa_buttons[$attrib['name']] = $attrib; + } + + // get saved button for this command/name + else if ($command && $sa_buttons[$command]) + $attrib = $sa_buttons[$command]; + + //else + // return ''; + + + // set border to 0 because of the link arround the button + if ($attrib['type']=='image' && !isset($attrib['border'])) + $attrib['border'] = 0; + + if (!$attrib['id']) + $attrib['id'] = sprintf('rcmbtn%d', $s_button_count++); + + // get localized text for labels and titles + if ($attrib['title']) + $attrib['title'] = rep_specialchars_output(rcube_label($attrib['title'])); + if ($attrib['label']) + $attrib['label'] = rep_specialchars_output(rcube_label($attrib['label'])); + + if ($attrib['alt']) + $attrib['alt'] = rep_specialchars_output(rcube_label($attrib['alt'])); + + // add empty alt attribute for XHTML compatibility + if (!isset($attrib['alt'])) + $attrib['alt'] = ''; + + + // register button in the system + if ($attrib['command']) + $OUTPUT->add_script(sprintf("%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');", + $JS_OBJECT_NAME, + $command, + $attrib['id'], + $attrib['type'], + $attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'], + $attirb['imagesel'] ? $skin_path.$attirb['imagesel'] : $attrib['classsel'], + $attrib['imageover'] ? $skin_path.$attrib['imageover'] : '')); + + // overwrite attributes + if (!$attrib['href']) + $attrib['href'] = '#'; + + if ($command) + $attrib['onclick'] = sprintf("return %s.command('%s','%s',this)", $JS_OBJECT_NAME, $command, $attrib['prop']); + + if ($command && $attrib['imageover']) + { + $attrib['onmouseover'] = sprintf("return %s.button_over('%s','%s')", $JS_OBJECT_NAME, $command, $attrib['id']); + $attrib['onmouseout'] = sprintf("return %s.button_out('%s','%s')", $JS_OBJECT_NAME, $command, $attrib['id']); + } + + + $out = ''; + + // generate image tag + if ($attrib['type']=='image') + { + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'alt')); + $img_tag = sprintf('', $attrib_str); + $btn_content = sprintf($img_tag, $skin_path.$attrib['image']); + if ($attrib['label']) + $btn_content .= ' '.$attrib['label']; + + $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'title'); + } + else if ($attrib['type']=='link') + { + $btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command']; + $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style'); + } + else if ($attrib['type']=='input') + { + $attrib['type'] = 'button'; + + if ($attrib['label']) + $attrib['value'] = $attrib['label']; + + $attrib_str = create_attrib_string($attrib, array('type', 'value', 'onclick', 'id', 'class', 'style')); + $out = sprintf('', $attrib_str); + } + + // generate html code for button + if ($btn_content) + { + $attrib_str = create_attrib_string($attrib, $link_attrib); + $out = sprintf('%s', $attrib_str, $btn_content); + } + + return $out; + } + + +function rcube_menu($attrib) + { + + return ''; + } + + + +function rcube_table_output($attrib, $sql_result, $a_show_cols, $id_col) + { + global $DB; + + // allow the following attributes to be added to the tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + + $table = '\n"; + + // add table title + $table .= "\n"; + + foreach ($a_show_cols as $col) + $table .= '\n"; + + $table .= "\n\n"; + + $c = 0; + while ($sql_result && ($sql_arr = $DB->fetch_assoc($sql_result))) + { + $zebra_class = $c%2 ? 'even' : 'odd'; + + $table .= sprintf(''."\n", $sql_arr[$id_col]); + + // format each col + foreach ($a_show_cols as $col) + { + $cont = rep_specialchars_output($sql_arr[$col]); + $table .= '\n"; + } + + $table .= "\n"; + $c++; + } + + // complete message table + $table .= "
' . rcube_label($col) . "
' . $cont . "
\n"; + + return $table; + } + + + +function rcmail_get_edit_field($col, $value, $attrib, $type='text') + { + $fname = '_'.$col; + $attrib['name'] = $fname; + + if ($type=='checkbox') + { + $attrib['value'] = '1'; + $input = new checkbox($attrib); + } + else if ($type=='textarea') + { + $attrib['cols'] = $attrib['size']; + $input = new textarea($attrib); + } + else + $input = new textfield($attrib); + + // use value from post + if ($_POST[$fname]) + $value = $_POST[$fname]; + + $out = $input->show($value); + + return $out; + } + + +function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style')) + { + // allow the following attributes to be added to the '; + document.body.insertAdjacentHTML('BeforeEnd',html); + } + else // for standards-compilant browsers + { + var frame = document.createElement('IFRAME'); + frame.name = frame_name; + frame.width = 10; + frame.height = 10; + frame.style.visibility = 'hidden'; + document.body.appendChild(frame); + } + + form.target = frame_name; + form.action = this.env.comm_path+'&_action=upload'; + form.setAttribute('enctype', 'multipart/form-data'); + form.submit(); + } + + // set reference to the form object + this.gui_objects.attachmentform = form; + }; + + + // add file name to attachment list + // called from upload page + this.add2attachment_list = function(name) + { + if (!this.gui_objects.attachmentlist) + return false; + + var li = document.createElement('LI'); + li.innerHTML = name; + this.gui_objects.attachmentlist.appendChild(li); + }; + + + // send remote request to add a new contact + this.add_contact = function(value) + { + if (value) + this.http_request('addcontact', '_address='+value); + }; + + + /*********************************************************/ + /********* keyboard live-search methods *********/ + /*********************************************************/ + + + // handler for keyboard events on address-fields + this.ksearch_keypress = function(e, obj) + { + if (typeof(this.env.contacts)!='object' || !this.env.contacts.length) + return true; + + if (this.ksearch_timer) + clearTimeout(this.ksearch_timer); + + if (!e) + e = window.event; + + var highlight; + var key = e.keyCode ? e.keyCode : e.which; + + switch (key) + { + case 38: // key up + case 40: // key down + if (!this.ksearch_pane) + break; + + var dir = key==38 ? 1 : 0; + var next; + + highlight = document.getElementById('rcmksearchSelected'); + if (!highlight) + highlight = this.ksearch_pane.ul.firstChild; + + if (highlight && (next = dir ? highlight.previousSibling : highlight.nextSibling)) + { + highlight.removeAttribute('id'); + //highlight.removeAttribute('class'); + this.set_classname(highlight, 'selected', false); + } + + if (next) + { + next.setAttribute('id', 'rcmksearchSelected'); + this.set_classname(next, 'selected', true); + this.ksearch_selected = next._rcm_id; + } + + if (e.preventDefault) + e.preventDefault(); + return false; + + case 9: // tab + if(e.shiftKey) + break; + + case 13: // enter + if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value) + break; + + // get cursor pos + var inp_value = this.ksearch_input.value.toLowerCase(); + var cpos = this.get_caret_pos(this.ksearch_input); + var p = inp_value.lastIndexOf(this.ksearch_value, cpos); + + // replace search string with full address + var pre = this.ksearch_input.value.substring(0, p); + var end = this.ksearch_input.value.substring(p+this.ksearch_value.length, this.ksearch_input.value.length); + var insert = this.env.contacts[this.ksearch_selected]+', '; + this.ksearch_input.value = pre + insert + end; + + //this.ksearch_input.value = this.ksearch_input.value.substring(0, p)+insert; + + // set caret to insert pos + cpos = p+insert.length; + if (this.ksearch_input.setSelectionRange) + this.ksearch_input.setSelectionRange(cpos, cpos); + + // hide ksearch pane + this.ksearch_hide(); + + if (e.preventDefault) + e.preventDefault(); + return false; + + case 27: // escape + this.ksearch_hide(); + break; + + } + + // start timer + this.ksearch_timer = setTimeout(this.ref+'.ksearch_get_results()', 200); + this.ksearch_input = obj; + + return true; + }; + + + // address search processor + this.ksearch_get_results = function() + { + var inp_value = this.ksearch_input ? this.ksearch_input.value : null; + if (inp_value===null) + return; + + // get string from current cursor pos to last comma + var cpos = this.get_caret_pos(this.ksearch_input); + var p = inp_value.lastIndexOf(',', cpos-1); + var q = inp_value.substring(p+1, cpos); + + // trim query string + q = q.replace(/(^\s+|\s+$)/g, '').toLowerCase(); + + if (!q.length || q==this.ksearch_value) + { + if (!q.length && this.ksearch_pane && this.ksearch_pane.visible) + this.ksearch_pane.show(0); + + return; + } + + this.ksearch_value = q; + + // start searching the contact list + var a_results = new Array(); + var a_result_ids = new Array(); + var c=0; + for (var i=0; i=0) + { + a_results[c] = this.env.contacts[i]; + a_result_ids[c++] = i; + + if (c==15) // limit search results + break; + } + } + + // display search results + if (c && a_results.length) + { + var p, ul, li; + + // create results pane if not present + if (!this.ksearch_pane) + { + ul = document.createElement('UL'); + this.ksearch_pane = new rcube_layer('rcmKSearchpane', {vis:0, zindex:30000}); + this.ksearch_pane.elm.appendChild(ul); + this.ksearch_pane.ul = ul; + } + else + ul = this.ksearch_pane.ul; + + // remove all search results + ul.innerHTML = ''; + + // add each result line to list + for (i=0; i/, '>'); + li._rcm_id = a_result_ids[i]; + ul.appendChild(li); + } + + // check if last selected item is still in result list + if (this.ksearch_selected!==null) + { + p = find_in_array(this.ksearch_selected, a_result_ids); + if (p>=0 && ul.childNodes) + { + ul.childNodes[p].setAttribute('id', 'rcmksearchSelected'); + this.set_classname(ul.childNodes[p], 'selected', true); + } + else + this.ksearch_selected = null; + } + + // if no item selected, select the first one + if (this.ksearch_selected===null) + { + ul.firstChild.setAttribute('id', 'rcmksearchSelected'); + this.set_classname(ul.firstChild, 'selected', true); + this.ksearch_selected = a_result_ids[0]; + } + + // resize the containing layer to fit the list + //this.ksearch_pane.resize(ul.offsetWidth, ul.offsetHeight); + + // move the results pane right under the input box and make it visible + var pos = rcube_get_object_pos(this.ksearch_input); + this.ksearch_pane.move(pos.x, pos.y+this.ksearch_input.offsetHeight); + this.ksearch_pane.show(1); + } + // hide results pane + else + this.ksearch_hide(); + }; + + + this.ksearch_blur = function(e, obj) + { + if (this.ksearch_timer) + clearTimeout(this.ksearch_timer); + + this.ksearch_value = ''; + this.ksearch_input = null; + + this.ksearch_hide(); + }; + + + this.ksearch_hide = function() + { + this.ksearch_selected = null; + + if (this.ksearch_pane) + this.ksearch_pane.show(0); + }; + + + + /*********************************************************/ + /********* address book methods *********/ + /*********************************************************/ + + + this.list_contacts = function(page) + { + var add_url = ''; + var target = window; + + if (page && this.current_page==page) + return false; + + // load contacts remotely + if (this.gui_objects.contactslist) + { + this.list_contacts_remote(page); + return; + } + + if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) + { + target = window.frames[this.env.contentframe]; + add_url = '&_framed=1'; + } + + this.set_busy(true, 'loading'); + location.href = this.env.comm_path+(page ? '&_page='+page : '')+add_url; + }; + + + // send remote request to load contacts list + this.list_contacts_remote = function(page) + { + // clear list + var table = this.gui_objects.contactslist; + var tbody = document.createElement('TBODY'); + table.insertBefore(tbody, table.tBodies[0]); + table.tBodies[1].style.display = 'none'; + + this.contact_rows = new Array(); + this.list_rows = this.contact_rows; + + // send request to server + var url = page ? '&_page='+page : ''; + this.set_busy(true, 'loading'); + this.http_request('list', url); + }; + + + // load contact record + this.load_contact = function(cid, action, framed) + { + var add_url = ''; + var target = window; + if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) + { + add_url = '&_framed=1'; + target = window.frames[this.env.contentframe]; + document.getElementById(this.env.contentframe).style.visibility = 'inherit'; + } + else if (framed) + return false; + + //if (this.env.framed && add_url=='') + // add_url = '&_framed=1'; + + if (action && (cid || action=='add')) + { + this.set_busy(true); + target.location.href = this.env.comm_path+'&_action='+action+'&_cid='+cid+add_url; + } + }; + + + this.delete_contacts = function() + { + // exit if no mailbox specified or if selection is empty + if (!(this.selection.length || this.env.cid)) + return; + + var a_cids = new Array(); + + if (this.env.cid) + a_cids[a_cids.length] = this.env.cid; + else + { + var id; + for (var n=0; n this.env.current_page)); + this.enable_command('previouspage', (this.env.current_page > 1)); + } + + + // set button to a specific state + this.set_button = function(command, state) + { + var a_buttons = this.buttons[command]; + var button, obj; + + if(!a_buttons || !a_buttons.length) + return; + + for(var n=0; n'+cont+''; + + this.gui_objects.message.innerHTML = cont; + this.gui_objects.message.style.display = 'block'; + + if (!hold) + this.message_timer = setTimeout(this.ref+'.hide_message()', this.message_time); + }; + + + // make a message row disapear + this.hide_message = function() + { + if (this.gui_objects.message) + this.gui_objects.message.style.display = 'none'; + }; + + + // mark a mailbox as selected and set environment variable + this.select_mailbox = function(mbox) + { + if (this.gui_objects.mailboxlist) + { + var item, reg, text_obj; + var s_mbox = String(mbox).toLowerCase().replace(this.mbox_expression, ''); + var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, ''); + for (var n=0; n=0) + this.set_classname(item, 'selected', true); + else if (item.className && item.className.indexOf('mailbox '+s_current)>=0) + this.set_classname(item, 'selected', false); + } + } + + this.env.mailbox = mbox; + }; + + + // create a table row in the message list + this.add_message_row = function(uid, cols, flags, attachment) + { + if (!this.gui_objects.messagelist || !this.gui_objects.messagelist.tBodies[0]) + return false; + + var tbody = this.gui_objects.messagelist.tBodies[0]; + var rowcount = tbody.rows.length; + var even = rowcount%2; + + this.env.messages[uid] = {replied:flags.replied?1:0, + unread:flags.unread?1:0}; + + var row = document.createElement('TR'); + row.id = 'rcmrow'+uid; + row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : ''); + + if (this.in_selection(uid)) + row.className += ' selected'; + + var icon = flags.unread && this.env.unreadicon ? this.env.unreadicon : + (flags.replied && this.env.repliedicon ? this.env.repliedicon : this.env.messageicon); + + var col = document.createElement('TD'); + col.className = 'icon'; + col.innerHTML = icon ? '' : ''; + row.appendChild(col); + + // add each submitted col + for (var c in cols) + { + col = document.createElement('TD'); + col.className = String(c).toLowerCase(); + col.innerHTML = cols[c]; + row.appendChild(col); + } + + col = document.createElement('TD'); + col.className = 'icon'; + col.innerHTML = attachment && this.env.attachmenticon ? '' : ''; + row.appendChild(col); + + tbody.appendChild(row); + this.init_message_row(row); + }; + + + // replace content of row count display + this.set_rowcount = function(text) + { + if (this.gui_objects.countdisplay) + this.gui_objects.countdisplay.innerHTML = text; + + // update page navigation buttons + this.set_page_buttons(); + }; + + + // update the mailboxlist + this.set_unread_count = function(mbox, count) + { + if (!this.gui_objects.mailboxlist) + return false; + + mbox = String(mbox).toLowerCase().replace(this.mbox_expression, ''); + + var item, reg, text_obj; + for (var n=0; n=0) + { + // set new text + text_obj = item.firstChild; + reg = /\s+\([0-9]+\)$/i; + + if (count && text_obj.innerHTML.match(reg)) + text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+count+')'); + else if (count) + text_obj.innerHTML += ' ('+count+')'; + else + text_obj.innerHTML = text_obj.innerHTML.replace(reg, ''); + + // set the right classes + this.set_classname(item, 'unread', count>0 ? true : false); + break; + } + } + }; + + + // add row to contacts list + this.add_contact_row = function(cid, cols) + { + if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0]) + return false; + + var tbody = this.gui_objects.contactslist.tBodies[0]; + var rowcount = tbody.rows.length; + var even = rowcount%2; + + var row = document.createElement('TR'); + row.id = 'rcmrow'+cid; + row.className = 'contact '+(even ? 'even' : 'odd'); + + if (this.in_selection(cid)) + row.className += ' selected'; + + // add each submitted col + for (var c in cols) + { + col = document.createElement('TD'); + col.className = String(c).toLowerCase(); + col.innerHTML = cols[c]; + row.appendChild(col); + } + + tbody.appendChild(row); + this.init_table_row(row, 'contact_rows'); + }; + + + + /********************************************************/ + /********* drag & drop methods *********/ + /********************************************************/ + + + this.drag_mouse_move = function(e) + { + if (this.drag_start) + { + if (!this.draglayer) + this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000}); + + // get subjects of selectedd messages + var names = ''; + var c, subject, obj; + for(var n=0; n12) // only show 12 lines + { + names += '...'; + break; + } + + if (this.message_rows[this.selection[n]].obj) + { + obj = this.message_rows[this.selection[n]].obj; + subject = ''; + + for(c=0; c 50 ? subject.substring(0, 50)+'...' : subject) + '
'; + } + } + } + + this.draglayer.write(names); + this.draglayer.show(1); + } + + var pos = this.get_mouse_pos(e); + this.draglayer.move(pos.x+20, pos.y-5); + + this.drag_start = false; + this.drag_active = true; + + return false; + }; + + + this.drag_mouse_up = function() + { + document.onmousemove = null; + + if (this.draglayer && this.draglayer.visible) + this.draglayer.show(0); + + this.drag_active = false; + + return false; + }; + + + + /********************************************************/ + /********* remote request methods *********/ + /********************************************************/ + + + // send a http request to the server + this.http_request = function(action, querystring) + { + if (window.XMLHttpRequest) + this.request_obj = new XMLHttpRequest(); + else if (window.ActiveXObject) + this.request_obj = new ActiveXObject("Microsoft.XMLHTTP"); + else + { + + } + + querystring += '&_remote=1'; + + // add timestamp to request url to avoid cacheing problems in Safari + if (bw.safari) + querystring += '&_ts='+(new Date().getTime()); + + // send request + if (this.request_obj) + { + // prompt('request', this.env.comm_path+'&_action='+escape(action)+'&'+querystring); + console('HTTP request: '+this.env.comm_path+'&_action='+escape(action)+'&'+querystring); + this.set_busy(true); + this.request_action = action; + this.request_obj.onreadystatechange = function(){ rcube_webmail_client.http_response(); }; + this.request_obj.open('GET', this.env.comm_path+'&_action='+escape(action)+'&'+querystring); + this.request_obj.send(null); + } + }; + + + // handle http response + this.http_response = function() + { + if (this.request_obj.readyState == 4) // || this.request_obj.readyState == 2) + { + var ctype = this.request_obj.getResponseHeader('Content-Type'); + if (ctype) + ctype = String(ctype).toLowerCase(); + + this.set_busy(false); + + console(this.request_obj.responseText); + + // if we get javascript code from server -> execute it + if (this.request_obj.responseText && (ctype=='text/javascript' || ctype=='application/x-javascript')) + eval(this.request_obj.responseText); + + // process the response data according to the sent action + switch (this.request_action) + { + case 'delete': + case 'moveto': + if (this.env.action=='show') + this.command('list'); + break; + + case 'list': + this.enable_command('select-all', 'select-none', this.env.messagecount ? true : false); + break; + } + } + }; + + + /********************************************************/ + /********* helper methods *********/ + /********************************************************/ + + // check if we're in show mode or if we have a unique selection + // and return the message uid + this.get_single_uid = function() + { + return this.env.uid ? this.env.uid : (this.selection.length==1 ? this.selection[0] : null); + }; + + // same as above but for contacts + this.get_single_cid = function() + { + return this.env.cid ? this.env.cid : (this.selection.length==1 ? this.selection[0] : null); + }; + + + // check if Shift-key is pressed on event + this.check_shiftkey = function(e) + { + if(!e && window.event) + e = window.event; + + if(bw.linux && bw.ns4 && e.modifiers) + return true; + else if((bw.ns4 && e.modifiers & Event.SHIFT_MASK) || (e && e.shiftKey)) + return true; + else + return false; + } + + + this.get_mouse_pos = function(e) + { + if(!e) e = window.event; + var mX = (e.pageX) ? e.pageX : e.clientX; + var mY = (e.pageY) ? e.pageY : e.clientY; + + if(document.body && document.all) + { + mX += document.body.scrollLeft; + mY += document.body.scrollTop; + } + + return { x:mX, y:mY }; + }; + + + this.get_caret_pos = function(obj) + { + if (typeof(obj.selectionEnd)!='undefined') + return obj.selectionEnd; + + else if (document.selection && document.selection.createRange) + { + var range = document.selection.createRange(); + if (range.parentElement()!=obj) + return 0; + + var gm = range.duplicate(); + if (obj.tagName=='TEXTAREA') + gm.moveToElementText(obj); + else + gm.expand('textedit'); + + gm.setEndPoint('EndToStart', range); + var p = gm.text.length; + + return p<=obj.value.length ? p : -1; + } + + else + return obj.value.length; + }; + + + this.set_caret2start = function(obj) + { + if (obj.createTextRange) + { + var range = obj.createTextRange(); + range.collapse(true); + range.select(); + } + else if (obj.setSelectionRange) + obj.setSelectionRange(0,0); + + obj.focus(); + }; + + + // set all fields of a form disabled + this.lock_form = function(form, lock) + { + if (!form || !form.elements) + return; + + var type; + for (var n=0; n | + +-----------------------------------------------------------------------+ +*/ + + +// default browsercheck +function roundcube_browser() + { + this.ver = parseFloat(navigator.appVersion); + this.appver = navigator.appVersion; + this.agent = navigator.userAgent; + this.name = navigator.appName; + this.vendor = navigator.vendor ? navigator.vendor : ''; + this.vendver = navigator.vendorSub ? parseFloat(navigator.vendorSub) : 0; + this.product = navigator.product ? navigator.product : ''; + this.platform = String(navigator.platform).toLowerCase(); + this.lang = (navigator.language) ? navigator.language.substring(0,2) : + (navigator.browserLanguage) ? navigator.browserLanguage.substring(0,2) : + (navigator.systemLanguage) ? navigator.systemLanguage.substring(0,2) : 'en'; + + this.win = (this.platform.indexOf('win')>=0) ? true : false; + this.mac = (this.platform.indexOf('mac')>=0) ? true : false; + this.linux = (this.platform.indexOf('linux')>=0) ? true : false; + this.unix = (this.platform.indexOf('unix')>=0) ? true : false; + + this.dom = document.getElementById ? true : false; + this.dom2 = (document.addEventListener && document.removeEventListener); + + this.ie = (document.all) ? true : false; + this.ie4 = (this.ie && !this.dom); + this.ie5 = (this.dom && this.appver.indexOf('MSIE 5')>0); + this.ie6 = (this.dom && this.appver.indexOf('MSIE 6')>0); + + this.mz = (this.dom && this.ver>=5); // (this.dom && this.product=='Gecko') + this.ns = ((this.ver<5 && this.name=='Netscape') || (this.ver>=5 && this.vendor.indexOf('Netscape')>=0)); + this.ns4 = (this.ns && parseInt(this.ver)==4); + this.ns6 = (this.ns && parseInt(this.vendver)==6); // (this.mz && this.ns) ? true : false; + this.ns7 = (this.ns && parseInt(this.vendver)==7); // this.agent.indexOf('Netscape/7')>0); + this.safari = this.agent.toLowerCase().indexOf('safari')>0; + this.konq = (this.agent.toLowerCase().indexOf('konqueror')>0); + + this.opera = (window.opera) ? true : false; + this.opera5 = (this.opera5 && this.agent.indexOf('Opera 5')>0) ? true : false; + this.opera6 = (this.opera && this.agent.indexOf('Opera 6')>0) ? true : false; + this.opera7 = (this.opera && this.agent.indexOf('Opera 7')>0) ? true : false; + + if(this.opera && window.RegExp) + this.vendver = (/opera(\s|\/)([0-9\.]+)/i.test(navigator.userAgent)) ? parseFloat(RegExp.$2) : -1; + else if(!this.vendver && this.safari) + this.vendver = (/safari\/([0-9]+)/i.test(this.agent)) ? parseInt(RegExp.$1) : 0; + else if((!this.vendver && this.mz) || this.agent.indexOf('Camino')>0) + this.vendver = (/rv:([0-9\.]+)/.test(this.agent)) ? parseFloat(RegExp.$1) : 0; + else if(this.ie && window.RegExp) + this.vendver = (/msie\s+([0-9\.]+)/i.test(this.agent)) ? parseFloat(RegExp.$1) : 0; + + // get real language out of safari's user agent + if(this.safari && (/;\s+([a-z]{2})-[a-z]{2}\)/i.test(this.agent))) + this.lang = RegExp.$1; + + this.dhtml = ((this.ie4 && this.win) || this.ie5 || this.ie6 || this.ns4 || this.mz); + this.layers = this.ns4; // (document.layers); + this.div = (this.ie4 || this.dom); + this.vml = (this.win && this.ie && this.dom && !this.opera); + this.linkborder = (this.ie || this.mz); + this.rollover = (this.ver>=4 || (this.ns && this.ver>=3)); // (document.images) ? true : false; + this.pngalpha = (this.mz || (this.opera && this.vendver>=6) || (this.ie && this.mac && this.vendver>=5) || + (this.ie && this.win && this.vendver>=5.5) || this.safari); + this.opacity = (this.mz || (this.ie && this.vendver>=5.5 && !this.opera) || (this.safari && this.vendver>=100)); + this.cookies = navigator.cookieEnabled; + } + + + + +var rcube_layer_objects = new Array(); + +function rcube_layer(id, attributes) + { + this.name = id; + + // create a new layer in the current document + this.create = function(arg) + { + var l = (arg.x) ? arg.x : 0; + var t = (arg.y) ? arg.y : 0; + var w = arg.width; + var h = arg.height; + var z = arg.zindex; + var vis = arg.vis; + var parent = arg.parent; + var obj; + + obj = document.createElement('DIV'); + with(obj) + { + id = this.name; + with(style) + { + position = 'absolute'; + visibility = (vis) ? (vis==2) ? 'inherit' : 'visible' : 'hidden'; + left = l+'px'; + top = t+'px'; + if(w) width = w+'px'; + if(h) height = h+'px'; + if(z) zIndex = z; + } + } + + if(parent) parent.appendChild(obj); + else document.body.appendChild(obj); + + this.elm = obj; + }; + + + // create new layer + if(attributes!=null) + { + this.create(attributes); + this.name = this.elm.id; + } + else // just refer to the object + this.elm = document.getElementById(id); + + + if(!this.elm) + return false; + + + // ********* layer object properties ********* + + this.css = this.elm.style; + this.event = this.elm; + this.width = this.elm.offsetWidth; + this.height = this.elm.offsetHeight; + this.x = parseInt(this.elm.offsetLeft); + this.y = parseInt(this.elm.offsetTop); + this.visible = (this.css.visibility=='visible' || this.css.visibility=='show' || this.css.visibility=='inherit') ? true : false; + + this.id = rcube_layer_objects.length; + this.obj = 'rcube_layer_objects['+this.id+']'; + rcube_layer_objects[this.id] = this; + + + // ********* layer object methods ********* + + + // move the layer to a specific position + this.move = function(x, y) + { + this.x = x; + this.y = y; + this.css.left = Math.round(this.x)+'px'; + this.css.top = Math.round(this.y)+'px'; + } + + + // move the layer for a specific step + this.shift = function(x,y) + { + x = Math.round(x*100)/100; + y = Math.round(y*100)/100; + this.move(this.x+x, this.y+y); + } + + + // change the layers width and height + this.resize = function(w,h) + { + this.css.width = w+'px'; + this.css.height = h+'px'; + this.width = w; + this.height = h; + } + + + // cut the layer (top,width,height,left) + this.clip = function(t,w,h,l) + { + this.css.clip='rect('+t+' '+w+' '+h+' '+l+')'; + this.clip_height = h; + this.clip_width = w; + } + + + // show or hide the layer + this.show = function(a) + { + if(a==1) + { + this.css.visibility = 'visible'; + this.visible = true; + } + else if(a==2) + { + this.css.visibility = 'inherit'; + this.visible = true; + } + else + { + this.css.visibility = 'hidden'; + this.visible = false; + } + } + + + // write new content into a Layer + this.write = function(cont) + { + this.elm.innerHTML = cont; + } + + + // set the given color to the layer background + this.set_bgcolor = function(c) + { + if(!c || c=='#') + c = 'transparent'; + + this.css.backgroundColor = c; + } + + + // set the opacity of a layer to the given ammount (in %) + this.set_opacity = function(v) + { + if(!bw.opacity) + return; + + var op = v<=1 ? Math.round(v*100) : parseInt(v); + + if(bw.ie) + this.css.filter = 'alpha(opacity:'+op+')'; + else if(bw.safari) + { + this.css.opacity = op/100; + this.css.KhtmlOpacity = op/100; + } + else if(bw.mz) + this.css.MozOpacity = op/100; + } + } + + + +// find a value in a specific array and returns the index +function find_in_array() + { + var args = find_in_array.arguments; + if(!args.length) return -1; + + var haystack = typeof(args[0])=='object' ? args[0] : args.length>1 && typeof(args[1])=='object' ? args[1] : new Array(); + var needle = typeof(args[0])!='object' ? args[0] : args.length>1 && typeof(args[1])!='object' ? args[1] : ''; + var nocase = args.length==3 ? args[2] : false; + + if(!haystack.length) return -1; + + for(var i=0; i | +// | Tomas V.V.Cox (port to PEAR) | +// +-----------------------------------------------------------------------+ +// +// $Id$ + +require_once('PEAR.php'); +require_once('Mail/mimePart.php'); + +/** + * Mime mail composer class. Can handle: text and html bodies, embedded html + * images and attachments. + * Documentation and examples of this class are avaible here: + * http://pear.php.net/manual/ + * + * @notes This class is based on HTML Mime Mail class from + * Richard Heyes which was based also + * in the mime_mail.class by Tobias Ratschiller and + * Sascha Schumann + * + * Function _encodeHeaders() changed by Thomas Bruederli + * in order to be read correctly by Google Gmail + * + * @author Richard Heyes + * @author Tomas V.V.Cox + * @package Mail + * @access public + */ +class Mail_mime +{ + /** + * Contains the plain text part of the email + * @var string + */ + var $_txtbody; + /** + * Contains the html part of the email + * @var string + */ + var $_htmlbody; + /** + * contains the mime encoded text + * @var string + */ + var $_mime; + /** + * contains the multipart content + * @var string + */ + var $_multipart; + /** + * list of the attached images + * @var array + */ + var $_html_images = array(); + /** + * list of the attachements + * @var array + */ + var $_parts = array(); + /** + * Build parameters + * @var array + */ + var $_build_params = array(); + /** + * Headers for the mail + * @var array + */ + var $_headers = array(); + /** + * End Of Line sequence (for serialize) + * @var string + */ + var $_eol; + + + /** + * Constructor function + * + * @access public + */ + function Mail_mime($crlf = "\r\n") + { + $this->_setEOL($crlf); + $this->_build_params = array( + 'text_encoding' => '7bit', + 'html_encoding' => 'quoted-printable', + '7bit_wrap' => 998, + 'html_charset' => 'ISO-8859-1', + 'text_charset' => 'ISO-8859-1', + 'head_charset' => 'ISO-8859-1' + ); + } + + /** + * Wakeup (unserialize) - re-sets EOL constant + * + * @access private + */ + function __wakeup() + { + $this->_setEOL($this->_eol); + } + + /** + * Accessor function to set the body text. Body text is used if + * it's not an html mail being sent or else is used to fill the + * text/plain part that emails clients who don't support + * html should show. + * + * @param string $data Either a string or + * the file name with the contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @param bool $append If true the text or file is appended to + * the existing body, else the old body is + * overwritten + * @return mixed true on success or PEAR_Error object + * @access public + */ + function setTXTBody($data, $isfile = false, $append = false) + { + if (!$isfile) { + if (!$append) { + $this->_txtbody = $data; + } else { + $this->_txtbody .= $data; + } + } else { + $cont = $this->_file2str($data); + if (PEAR::isError($cont)) { + return $cont; + } + if (!$append) { + $this->_txtbody = $cont; + } else { + $this->_txtbody .= $cont; + } + } + return true; + } + + /** + * Adds a html part to the mail + * + * @param string $data Either a string or the file name with the + * contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @return mixed true on success or PEAR_Error object + * @access public + */ + function setHTMLBody($data, $isfile = false) + { + if (!$isfile) { + $this->_htmlbody = $data; + } else { + $cont = $this->_file2str($data); + if (PEAR::isError($cont)) { + return $cont; + } + $this->_htmlbody = $cont; + } + + return true; + } + + /** + * Adds an image to the list of embedded images. + * + * @param string $file The image file name OR image data itself + * @param string $c_type The content type + * @param string $name The filename of the image. + * Only use if $file is the image data + * @param bool $isfilename Whether $file is a filename or not + * Defaults to true + * @return mixed true on success or PEAR_Error object + * @access public + */ + function addHTMLImage($file, $c_type='application/octet-stream', + $name = '', $isfilename = true) + { + $filedata = ($isfilename === true) ? $this->_file2str($file) + : $file; + if ($isfilename === true) { + $filename = ($name == '' ? basename($file) : basename($name)); + } else { + $filename = basename($name); + } + if (PEAR::isError($filedata)) { + return $filedata; + } + $this->_html_images[] = array( + 'body' => $filedata, + 'name' => $filename, + 'c_type' => $c_type, + 'cid' => md5(uniqid(time())) + ); + return true; + } + + /** + * Adds a file to the list of attachments. + * + * @param string $file The file name of the file to attach + * OR the file data itself + * @param string $c_type The content type + * @param string $name The filename of the attachment + * Only use if $file is the file data + * @param bool $isFilename Whether $file is a filename or not + * Defaults to true + * @return mixed true on success or PEAR_Error object + * @access public + */ + function addAttachment($file, $c_type = 'application/octet-stream', + $name = '', $isfilename = true, + $encoding = 'base64') + { + $filedata = ($isfilename === true) ? $this->_file2str($file) + : $file; + if ($isfilename === true) { + // Force the name the user supplied, otherwise use $file + $filename = (!empty($name)) ? $name : $file; + } else { + $filename = $name; + } + if (empty($filename)) { + return PEAR::raiseError( + 'The supplied filename for the attachment can\'t be empty' + ); + } + $filename = basename($filename); + if (PEAR::isError($filedata)) { + return $filedata; + } + + $this->_parts[] = array( + 'body' => $filedata, + 'name' => $filename, + 'c_type' => $c_type, + 'encoding' => $encoding + ); + return true; + } + + /** + * Get the contents of the given file name as string + * + * @param string $file_name path of file to process + * @return string contents of $file_name + * @access private + */ + function &_file2str($file_name) + { + if (!is_readable($file_name)) { + return PEAR::raiseError('File is not readable ' . $file_name); + } + if (!$fd = fopen($file_name, 'rb')) { + return PEAR::raiseError('Could not open ' . $file_name); + } + $cont = fread($fd, filesize($file_name)); + fclose($fd); + return $cont; + } + + /** + * Adds a text subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @param string The text to add. + * @return object The text mimePart object + * @access private + */ + function &_addTextPart(&$obj, $text) + { + $params['content_type'] = 'text/plain'; + $params['encoding'] = $this->_build_params['text_encoding']; + $params['charset'] = $this->_build_params['text_charset']; + if (is_object($obj)) { + return $obj->addSubpart($text, $params); + } else { + return new Mail_mimePart($text, $params); + } + } + + /** + * Adds a html subpart to the mimePart object and + * returns it during the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @return object The html mimePart object + * @access private + */ + function &_addHtmlPart(&$obj) + { + $params['content_type'] = 'text/html'; + $params['encoding'] = $this->_build_params['html_encoding']; + $params['charset'] = $this->_build_params['html_charset']; + if (is_object($obj)) { + return $obj->addSubpart($this->_htmlbody, $params); + } else { + return new Mail_mimePart($this->_htmlbody, $params); + } + } + + /** + * Creates a new mimePart object, using multipart/mixed as + * the initial content-type and returns it during the + * build process. + * + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addMixedPart() + { + $params['content_type'] = 'multipart/mixed'; + return new Mail_mimePart('', $params); + } + + /** + * Adds a multipart/alternative part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created. + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addAlternativePart(&$obj) + { + $params['content_type'] = 'multipart/alternative'; + if (is_object($obj)) { + return $obj->addSubpart('', $params); + } else { + return new Mail_mimePart('', $params); + } + } + + /** + * Adds a multipart/related part to a mimePart + * object (or creates one), and returns it during + * the build process. + * + * @param mixed The object to add the part to, or + * null if a new object is to be created + * @return object The multipart/mixed mimePart object + * @access private + */ + function &_addRelatedPart(&$obj) + { + $params['content_type'] = 'multipart/related'; + if (is_object($obj)) { + return $obj->addSubpart('', $params); + } else { + return new Mail_mimePart('', $params); + } + } + + /** + * Adds an html image subpart to a mimePart object + * and returns it during the build process. + * + * @param object The mimePart to add the image to + * @param array The image information + * @return object The image mimePart object + * @access private + */ + function &_addHtmlImagePart(&$obj, $value) + { + $params['content_type'] = $value['c_type']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'inline'; + $params['dfilename'] = $value['name']; + $params['cid'] = $value['cid']; + $obj->addSubpart($value['body'], $params); + } + + /** + * Adds an attachment subpart to a mimePart object + * and returns it during the build process. + * + * @param object The mimePart to add the image to + * @param array The attachment information + * @return object The image mimePart object + * @access private + */ + function &_addAttachmentPart(&$obj, $value) + { + $params['content_type'] = $value['c_type']; + $params['encoding'] = $value['encoding']; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $value['name']; + $obj->addSubpart($value['body'], $params); + } + + /** + * Builds the multipart message from the list ($this->_parts) and + * returns the mime content. + * + * @param array Build parameters that change the way the email + * is built. Should be associative. Can contain: + * text_encoding - What encoding to use for plain text + * Default is 7bit + * html_encoding - What encoding to use for html + * Default is quoted-printable + * 7bit_wrap - Number of characters before text is + * wrapped in 7bit encoding + * Default is 998 + * html_charset - The character set to use for html. + * Default is iso-8859-1 + * text_charset - The character set to use for text. + * Default is iso-8859-1 + * head_charset - The character set to use for headers. + * Default is iso-8859-1 + * @return string The mime content + * @access public + */ + function &get($build_params = null) + { + if (isset($build_params)) { + while (list($key, $value) = each($build_params)) { + $this->_build_params[$key] = $value; + } + } + + if (!empty($this->_html_images) AND isset($this->_htmlbody)) { + foreach ($this->_html_images as $value) { + $regex = '#src\s*=\s*(["\']?)' . preg_quote($value['name']) . + '(["\'])?#'; + $rep = 'src=\1cid:' . $value['cid'] .'\2'; + $this->_htmlbody = preg_replace($regex, $rep, + $this->_htmlbody + ); + } + } + + $null = null; + $attachments = !empty($this->_parts) ? true : false; + $html_images = !empty($this->_html_images) ? true : false; + $html = !empty($this->_htmlbody) ? true : false; + $text = (!$html AND !empty($this->_txtbody)) ? true : false; + + switch (true) { + case $text AND !$attachments: + $message =& $this->_addTextPart($null, $this->_txtbody); + break; + + case !$text AND !$html AND $attachments: + $message =& $this->_addMixedPart(); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $text AND $attachments: + $message =& $this->_addMixedPart(); + $this->_addTextPart($message, $this->_txtbody); + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html AND !$attachments AND !$html_images: + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + $this->_addHtmlPart($message); + } else { + $message =& $this->_addHtmlPart($null); + } + break; + + case $html AND !$attachments AND $html_images: + if (isset($this->_txtbody)) { + $message =& $this->_addAlternativePart($null); + $this->_addTextPart($message, $this->_txtbody); + $related =& $this->_addRelatedPart($message); + } else { + $message =& $this->_addRelatedPart($null); + $related =& $message; + } + $this->_addHtmlPart($related); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($related, $this->_html_images[$i]); + } + break; + + case $html AND $attachments AND !$html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $this->_addHtmlPart($alt); + } else { + $this->_addHtmlPart($message); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + case $html AND $attachments AND $html_images: + $message =& $this->_addMixedPart(); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $rel =& $this->_addRelatedPart($alt); + } else { + $rel =& $this->_addRelatedPart($message); + } + $this->_addHtmlPart($rel); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($rel, $this->_html_images[$i]); + } + for ($i = 0; $i < count($this->_parts); $i++) { + $this->_addAttachmentPart($message, $this->_parts[$i]); + } + break; + + } + + if (isset($message)) { + $output = $message->encode(); + $this->_headers = array_merge($this->_headers, + $output['headers']); + return $output['body']; + + } else { + return false; + } + } + + /** + * Returns an array with the headers needed to prepend to the email + * (MIME-Version and Content-Type). Format of argument is: + * $array['header-name'] = 'header-value'; + * + * @param array $xtra_headers Assoc array with any extra headers. + * Optional. + * @return array Assoc array with the mime headers + * @access public + */ + function &headers($xtra_headers = null) + { + // Content-Type header should already be present, + // So just add mime version header + $headers['MIME-Version'] = '1.0'; + if (isset($xtra_headers)) { + $headers = array_merge($headers, $xtra_headers); + } + $this->_headers = array_merge($headers, $this->_headers); + + return $this->_encodeHeaders($this->_headers); + } + + /** + * Get the text version of the headers + * (usefull if you want to use the PHP mail() function) + * + * @param array $xtra_headers Assoc array with any extra headers. + * Optional. + * @return string Plain text headers + * @access public + */ + function txtHeaders($xtra_headers = null) + { + $headers = $this->headers($xtra_headers); + $ret = ''; + foreach ($headers as $key => $val) { + $ret .= "$key: $val" . MAIL_MIME_CRLF; + } + return $ret; + } + + /** + * Sets the Subject header + * + * @param string $subject String to set the subject to + * access public + */ + function setSubject($subject) + { + $this->_headers['Subject'] = $subject; + } + + /** + * Set an email to the From (the sender) header + * + * @param string $email The email direction to add + * @access public + */ + function setFrom($email) + { + $this->_headers['From'] = $email; + } + + /** + * Add an email to the Cc (carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * @access public + */ + function addCc($email) + { + if (isset($this->_headers['Cc'])) { + $this->_headers['Cc'] .= ", $email"; + } else { + $this->_headers['Cc'] = $email; + } + } + + /** + * Add an email to the Bcc (blank carbon copy) header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * @access public + */ + function addBcc($email) + { + if (isset($this->_headers['Bcc'])) { + $this->_headers['Bcc'] .= ", $email"; + } else { + $this->_headers['Bcc'] = $email; + } + } + + /** + * Encodes a header as per RFC2047 + * + * @param string $input The header data to encode + * @return string Encoded data + * @access private + */ + function _encodeHeaders($input) + { + $enc_prefix = '=?' . $this->_build_params['head_charset'] . '?Q?'; + foreach ($input as $hdr_name => $hdr_value) { + if (preg_match('/(\w*[\x80-\xFF]+\w*)/', $hdr_value)) { + $enc_value = preg_replace('/([\x80-\xFF])/e', '"=".strtoupper(dechex(ord("\1")))', $hdr_value); + // check for in string + if (preg_match('/<[a-z0-9\-\.\+\_]+@[a-z0-9]([a-z0-9\-].?)*[a-z0-9]\\.[a-z]{2,5}>/i', $enc_value) && ($p = strrpos($enc_value, '<'))) { + $hdr_value = $enc_prefix . substr($enc_value, 0, $p-1) . '?= ' . substr($enc_value, $p, strlen($enc_value)-$p); + } else { + $hdr_value = $enc_prefix . $enc_value . '?='; + } + } + $input[$hdr_name] = $hdr_value; + } + + return $input; + } + + /* replaced 2005/07/08 by roundcube@gmail.com + + function _encodeHeaders_old($input) + { + foreach ($input as $hdr_name => $hdr_value) { + preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches); + foreach ($matches[1] as $value) { + $replacement = preg_replace('/([\x80-\xFF])/e', + '"=" . + strtoupper(dechex(ord("\1")))', + $value); + $hdr_value = str_replace($value, '=?' . + $this->_build_params['head_charset'] . + '?Q?' . $replacement . '?=', + $hdr_value); + } + $input[$hdr_name] = $hdr_value; + } + + return $input; + } + */ + + /** + * Set the object's end-of-line and define the constant if applicable + * + * @param string $eol End Of Line sequence + * @access private + */ + function _setEOL($eol) + { + $this->_eol = $eol; + if (!defined('MAIL_MIME_CRLF')) { + define('MAIL_MIME_CRLF', $this->_eol, true); + } + } + + + +} // End of class +?> diff --git a/program/lib/Mail/mimeDecode.php b/program/lib/Mail/mimeDecode.php new file mode 100644 index 000000000..92827b727 --- /dev/null +++ b/program/lib/Mail/mimeDecode.php @@ -0,0 +1,842 @@ + | +// +-----------------------------------------------------------------------+ + +require_once 'PEAR.php'; + +/** +* +----------------------------- IMPORTANT ------------------------------+ +* | Usage of this class compared to native php extensions such as | +* | mailparse or imap, is slow and may be feature deficient. If available| +* | you are STRONGLY recommended to use the php extensions. | +* +----------------------------------------------------------------------+ +* +* Mime Decoding class +* +* This class will parse a raw mime email and return +* the structure. Returned structure is similar to +* that returned by imap_fetchstructure(). +* +* USAGE: (assume $input is your raw email) +* +* $decode = new Mail_mimeDecode($input, "\r\n"); +* $structure = $decode->decode(); +* print_r($structure); +* +* Or statically: +* +* $params['input'] = $input; +* $structure = Mail_mimeDecode::decode($params); +* print_r($structure); +* +* TODO: +* o Implement multipart/appledouble +* o UTF8: ??? + + > 4. We have also found a solution for decoding the UTF-8 + > headers. Therefore I made the following function: + > + > function decode_utf8($txt) { + > $trans=array("Å‘"=>"õ","ű"=>"û","Å"=>"Õ","Ű" + =>"Û"); + > $txt=strtr($txt,$trans); + > return(utf8_decode($txt)); + > } + > + > And I have inserted the following line to the class: + > + > if (strtolower($charset)=="utf-8") $text=decode_utf8($text); + > + > ... before the following one in the "_decodeHeader" function: + > + > $input = str_replace($encoded, $text, $input); + > + > This way from now on it can easily decode the UTF-8 headers too. + +* +* @author Richard Heyes +* @version $Revision$ +* @package Mail +*/ +class Mail_mimeDecode extends PEAR +{ + /** + * The raw email to decode + * @var string + */ + var $_input; + + /** + * The header part of the input + * @var string + */ + var $_header; + + /** + * The body part of the input + * @var string + */ + var $_body; + + /** + * If an error occurs, this is used to store the message + * @var string + */ + var $_error; + + /** + * Flag to determine whether to include bodies in the + * returned object. + * @var boolean + */ + var $_include_bodies; + + /** + * Flag to determine whether to decode bodies + * @var boolean + */ + var $_decode_bodies; + + /** + * Flag to determine whether to decode headers + * @var boolean + */ + var $_decode_headers; + + /** + * Constructor. + * + * Sets up the object, initialise the variables, and splits and + * stores the header and body of the input. + * + * @param string The input to decode + * @access public + */ + function Mail_mimeDecode($input) + { + list($header, $body) = $this->_splitBodyHeader($input); + + $this->_input = $input; + $this->_header = $header; + $this->_body = $body; + $this->_decode_bodies = false; + $this->_include_bodies = true; + } + + /** + * Begins the decoding process. If called statically + * it will create an object and call the decode() method + * of it. + * + * @param array An array of various parameters that determine + * various things: + * include_bodies - Whether to include the body in the returned + * object. + * decode_bodies - Whether to decode the bodies + * of the parts. (Transfer encoding) + * decode_headers - Whether to decode headers + * input - If called statically, this will be treated + * as the input + * @return object Decoded results + * @access public + */ + function decode($params = null) + { + // determine if this method has been called statically + $isStatic = !(isset($this) && get_class($this) == __CLASS__); + + // Have we been called statically? + // If so, create an object and pass details to that. + if ($isStatic AND isset($params['input'])) { + + $obj = new Mail_mimeDecode($params['input']); + $structure = $obj->decode($params); + + // Called statically but no input + } elseif ($isStatic) { + return PEAR::raiseError('Called statically and no input given'); + + // Called via an object + } else { + $this->_include_bodies = isset($params['include_bodies']) ? + $params['include_bodies'] : false; + $this->_decode_bodies = isset($params['decode_bodies']) ? + $params['decode_bodies'] : false; + $this->_decode_headers = isset($params['decode_headers']) ? + $params['decode_headers'] : false; + + $structure = $this->_decode($this->_header, $this->_body); + if ($structure === false) { + $structure = $this->raiseError($this->_error); + } + } + + return $structure; + } + + /** + * Performs the decoding. Decodes the body string passed to it + * If it finds certain content-types it will call itself in a + * recursive fashion + * + * @param string Header section + * @param string Body section + * @return object Results of decoding process + * @access private + */ + function _decode($headers, $body, $default_ctype = 'text/plain') + { + $return = new stdClass; + $return->headers = array(); + $headers = $this->_parseHeaders($headers); + + foreach ($headers as $value) { + if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) { + $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]); + $return->headers[strtolower($value['name'])][] = $value['value']; + + } elseif (isset($return->headers[strtolower($value['name'])])) { + $return->headers[strtolower($value['name'])][] = $value['value']; + + } else { + $return->headers[strtolower($value['name'])] = $value['value']; + } + } + + reset($headers); + while (list($key, $value) = each($headers)) { + $headers[$key]['name'] = strtolower($headers[$key]['name']); + switch ($headers[$key]['name']) { + + case 'content-type': + $content_type = $this->_parseHeaderValue($headers[$key]['value']); + + if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) { + $return->ctype_primary = $regs[1]; + $return->ctype_secondary = $regs[2]; + } + + if (isset($content_type['other'])) { + while (list($p_name, $p_value) = each($content_type['other'])) { + $return->ctype_parameters[$p_name] = $p_value; + } + } + break; + + case 'content-disposition': + $content_disposition = $this->_parseHeaderValue($headers[$key]['value']); + $return->disposition = $content_disposition['value']; + if (isset($content_disposition['other'])) { + while (list($p_name, $p_value) = each($content_disposition['other'])) { + $return->d_parameters[$p_name] = $p_value; + } + } + break; + + case 'content-transfer-encoding': + $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']); + break; + } + } + + if (isset($content_type)) { + switch (strtolower($content_type['value'])) { + case 'text/plain': + $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; + $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null; + break; + + case 'text/html': + $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; + $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null; + break; + + case 'multipart/parallel': + case 'multipart/report': // RFC1892 + case 'multipart/signed': // PGP + case 'multipart/digest': + case 'multipart/alternative': + case 'multipart/related': + case 'multipart/mixed': + if(!isset($content_type['other']['boundary'])){ + $this->_error = 'No boundary found for ' . $content_type['value'] . ' part'; + return false; + } + + $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; + $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); + for ($i = 0; $i < count($parts); $i++) { + list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); + $part = $this->_decode($part_header, $part_body, $default_ctype); + if($part === false) + $part = $this->raiseError($this->_error); + $return->parts[] = $part; + } + break; + + case 'message/rfc822': + $obj = &new Mail_mimeDecode($body); + $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies, + 'decode_bodies' => $this->_decode_bodies, + 'decode_headers' => $this->_decode_headers)); + unset($obj); + break; + + default: + if(!isset($content_transfer_encoding['value'])) + $content_transfer_encoding['value'] = '7bit'; + $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null; + break; + } + + } else { + $ctype = explode('/', $default_ctype); + $return->ctype_primary = $ctype[0]; + $return->ctype_secondary = $ctype[1]; + $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null; + } + + return $return; + } + + /** + * Given the output of the above function, this will return an + * array of references to the parts, indexed by mime number. + * + * @param object $structure The structure to go through + * @param string $mime_number Internal use only. + * @return array Mime numbers + */ + function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '') + { + $return = array(); + if (!empty($structure->parts)) { + if ($mime_number != '') { + $structure->mime_id = $prepend . $mime_number; + $return[$prepend . $mime_number] = &$structure; + } + for ($i = 0; $i < count($structure->parts); $i++) { + + + if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') { + $prepend = $prepend . $mime_number . '.'; + $_mime_number = ''; + } else { + $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1)); + } + + $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend); + foreach ($arr as $key => $val) { + $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key]; + } + } + } else { + if ($mime_number == '') { + $mime_number = '1'; + } + $structure->mime_id = $prepend . $mime_number; + $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure; + } + + return $return; + } + + /** + * Given a string containing a header and body + * section, this function will split them (at the first + * blank line) and return them. + * + * @param string Input to split apart + * @return array Contains header and body section + * @access private + */ + function _splitBodyHeader($input) + { + if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { + return array($match[1], $match[2]); + } + $this->_error = 'Could not split header and body'; + return false; + } + + /** + * Parse headers given in $input and return + * as assoc array. + * + * @param string Headers to parse + * @return array Contains parsed headers + * @access private + */ + function _parseHeaders($input) + { + + if ($input !== '') { + // Unfold the input + $input = preg_replace("/\r?\n/", "\r\n", $input); + $input = preg_replace("/\r\n(\t| )+/", ' ', $input); + $headers = explode("\r\n", trim($input)); + + foreach ($headers as $value) { + $hdr_name = substr($value, 0, $pos = strpos($value, ':')); + $hdr_value = substr($value, $pos+1); + if($hdr_value[0] == ' ') + $hdr_value = substr($hdr_value, 1); + + $return[] = array( + 'name' => $hdr_name, + 'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value + ); + } + } else { + $return = array(); + } + + return $return; + } + + /** + * Function to parse a header value, + * extract first part, and any secondary + * parts (after ;) This function is not as + * robust as it could be. Eg. header comments + * in the wrong place will probably break it. + * + * @param string Header value to parse + * @return array Contains parsed result + * @access private + */ + function _parseHeaderValue($input) + { + + if (($pos = strpos($input, ';')) !== false) { + + $return['value'] = trim(substr($input, 0, $pos)); + $input = trim(substr($input, $pos+1)); + + if (strlen($input) > 0) { + + // This splits on a semi-colon, if there's no preceeding backslash + // Now works with quoted values; had to glue the \; breaks in PHP + // the regex is already bordering on incomprehensible + $splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/'; + preg_match_all($splitRegex, $input, $matches); + $parameters = array(); + for ($i=0; $i_quotedPrintableDecode($input); + break; + + case 'base64': + return base64_decode($input); + break; + + default: + return $input; + } + } + + /** + * Given a quoted-printable string, this + * function will decode and return it. + * + * @param string Input body to decode + * @return string Decoded body + * @access private + */ + function _quotedPrintableDecode($input) + { + // Remove soft line breaks + $input = preg_replace("/=\r?\n/", '', $input); + + // Replace encoded characters + $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input); + + return $input; + } + + /** + * Checks the input for uuencoded files and returns + * an array of them. Can be called statically, eg: + * + * $files =& Mail_mimeDecode::uudecode($some_text); + * + * It will check for the begin 666 ... end syntax + * however and won't just blindly decode whatever you + * pass it. + * + * @param string Input body to look for attahcments in + * @return array Decoded bodies, filenames and permissions + * @access public + * @author Unknown + */ + function &uudecode($input) + { + // Find all uuencoded sections + preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches); + + for ($j = 0; $j < count($matches[3]); $j++) { + + $str = $matches[3][$j]; + $filename = $matches[2][$j]; + $fileperm = $matches[1][$j]; + + $file = ''; + $str = preg_split("/\r?\n/", trim($str)); + $strlen = count($str); + + for ($i = 0; $i < $strlen; $i++) { + $pos = 1; + $d = 0; + $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077); + + while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) { + $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); + $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); + $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); + $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20); + $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); + + $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); + + $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077)); + + $pos += 4; + $d += 3; + } + + if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) { + $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); + $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); + $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); + $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); + + $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); + + $pos += 3; + $d += 2; + } + + if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) { + $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); + $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); + $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); + + } + } + $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file); + } + + return $files; + } + + /** + * getSendArray() returns the arguments required for Mail::send() + * used to build the arguments for a mail::send() call + * + * Usage: + * $mailtext = Full email (for example generated by a template) + * $decoder = new Mail_mimeDecode($mailtext); + * $parts = $decoder->getSendArray(); + * if (!PEAR::isError($parts) { + * list($recipents,$headers,$body) = $parts; + * $mail = Mail::factory('smtp'); + * $mail->send($recipents,$headers,$body); + * } else { + * echo $parts->message; + * } + * @return mixed array of recipeint, headers,body or Pear_Error + * @access public + * @author Alan Knowles + */ + function getSendArray() + { + // prevent warning if this is not set + $this->_decode_headers = FALSE; + $headerlist =$this->_parseHeaders($this->_header); + $to = ""; + if (!$headerlist) { + return $this->raiseError("Message did not contain headers"); + } + foreach($headerlist as $item) { + $header[$item['name']] = $item['value']; + switch (strtolower($item['name'])) { + case "to": + case "cc": + case "bcc": + $to = ",".$item['value']; + default: + break; + } + } + if ($to == "") { + return $this->raiseError("Message did not contain any recipents"); + } + $to = substr($to,1); + return array($to,$header,$this->_body); + } + + /** + * Returns a xml copy of the output of + * Mail_mimeDecode::decode. Pass the output in as the + * argument. This function can be called statically. Eg: + * + * $output = $obj->decode(); + * $xml = Mail_mimeDecode::getXML($output); + * + * The DTD used for this should have been in the package. Or + * alternatively you can get it from cvs, or here: + * http://www.phpguru.org/xmail/xmail.dtd. + * + * @param object Input to convert to xml. This should be the + * output of the Mail_mimeDecode::decode function + * @return string XML version of input + * @access public + */ + function getXML($input) + { + $crlf = "\r\n"; + $output = '' . $crlf . + '' . $crlf . + '' . $crlf . + Mail_mimeDecode::_getXML($input) . + ''; + + return $output; + } + + /** + * Function that does the actual conversion to xml. Does a single + * mimepart at a time. + * + * @param object Input to convert to xml. This is a mimepart object. + * It may or may not contain subparts. + * @param integer Number of tabs to indent + * @return string XML version of input + * @access private + */ + function _getXML($input, $indent = 1) + { + $htab = "\t"; + $crlf = "\r\n"; + $output = ''; + $headers = @(array)$input->headers; + + foreach ($headers as $hdr_name => $hdr_value) { + + // Multiple headers with this name + if (is_array($headers[$hdr_name])) { + for ($i = 0; $i < count($hdr_value); $i++) { + $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent); + } + + // Only one header of this sort + } else { + $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent); + } + } + + if (!empty($input->parts)) { + for ($i = 0; $i < count($input->parts); $i++) { + $output .= $crlf . str_repeat($htab, $indent) . '' . $crlf . + Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) . + str_repeat($htab, $indent) . '' . $crlf; + } + } elseif (isset($input->body)) { + $output .= $crlf . str_repeat($htab, $indent) . 'body . ']]>' . $crlf; + } + + return $output; + } + + /** + * Helper function to _getXML(). Returns xml of a header. + * + * @param string Name of header + * @param string Value of header + * @param integer Number of tabs to indent + * @return string XML version of input + * @access private + */ + function _getXML_helper($hdr_name, $hdr_value, $indent) + { + $htab = "\t"; + $crlf = "\r\n"; + $return = ''; + + $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value); + $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name))); + + // Sort out any parameters + if (!empty($new_hdr_value['other'])) { + foreach ($new_hdr_value['other'] as $paramname => $paramvalue) { + $params[] = str_repeat($htab, $indent) . $htab . '' . $crlf . + str_repeat($htab, $indent) . $htab . $htab . '' . htmlspecialchars($paramname) . '' . $crlf . + str_repeat($htab, $indent) . $htab . $htab . '' . htmlspecialchars($paramvalue) . '' . $crlf . + str_repeat($htab, $indent) . $htab . '' . $crlf; + } + + $params = implode('', $params); + } else { + $params = ''; + } + + $return = str_repeat($htab, $indent) . '
' . $crlf . + str_repeat($htab, $indent) . $htab . '' . htmlspecialchars($new_hdr_name) . '' . $crlf . + str_repeat($htab, $indent) . $htab . '' . htmlspecialchars($new_hdr_value['value']) . '' . $crlf . + $params . + str_repeat($htab, $indent) . '
' . $crlf; + + return $return; + } + +} // End of class +?> diff --git a/program/lib/Mail/mimePart.php b/program/lib/Mail/mimePart.php new file mode 100644 index 000000000..b429b905e --- /dev/null +++ b/program/lib/Mail/mimePart.php @@ -0,0 +1,351 @@ + | +// +-----------------------------------------------------------------------+ + +/** +* +* Raw mime encoding class +* +* What is it? +* This class enables you to manipulate and build +* a mime email from the ground up. +* +* Why use this instead of mime.php? +* mime.php is a userfriendly api to this class for +* people who aren't interested in the internals of +* mime mail. This class however allows full control +* over the email. +* +* Eg. +* +* // Since multipart/mixed has no real body, (the body is +* // the subpart), we set the body argument to blank. +* +* $params['content_type'] = 'multipart/mixed'; +* $email = new Mail_mimePart('', $params); +* +* // Here we add a text part to the multipart we have +* // already. Assume $body contains plain text. +* +* $params['content_type'] = 'text/plain'; +* $params['encoding'] = '7bit'; +* $text = $email->addSubPart($body, $params); +* +* // Now add an attachment. Assume $attach is +* the contents of the attachment +* +* $params['content_type'] = 'application/zip'; +* $params['encoding'] = 'base64'; +* $params['disposition'] = 'attachment'; +* $params['dfilename'] = 'example.zip'; +* $attach =& $email->addSubPart($body, $params); +* +* // Now build the email. Note that the encode +* // function returns an associative array containing two +* // elements, body and headers. You will need to add extra +* // headers, (eg. Mime-Version) before sending. +* +* $email = $message->encode(); +* $email['headers'][] = 'Mime-Version: 1.0'; +* +* +* Further examples are available at http://www.phpguru.org +* +* TODO: +* - Set encode() to return the $obj->encoded if encode() +* has already been run. Unless a flag is passed to specifically +* re-build the message. +* +* @author Richard Heyes +* @version $Revision$ +* @package Mail +*/ + +class Mail_mimePart { + + /** + * The encoding type of this part + * @var string + */ + var $_encoding; + + /** + * An array of subparts + * @var array + */ + var $_subparts; + + /** + * The output of this part after being built + * @var string + */ + var $_encoded; + + /** + * Headers for this part + * @var array + */ + var $_headers; + + /** + * The body of this part (not encoded) + * @var string + */ + var $_body; + + /** + * Constructor. + * + * Sets up the object. + * + * @param $body - The body of the mime part if any. + * @param $params - An associative array of parameters: + * content_type - The content type for this part eg multipart/mixed + * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable + * cid - Content ID to apply + * disposition - Content disposition, inline or attachment + * dfilename - Optional filename parameter for content disposition + * description - Content description + * charset - Character set to use + * @access public + */ + function Mail_mimePart($body = '', $params = array()) + { + if (!defined('MAIL_MIMEPART_CRLF')) { + define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); + } + + foreach ($params as $key => $value) { + switch ($key) { + case 'content_type': + $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); + break; + + case 'encoding': + $this->_encoding = $value; + $headers['Content-Transfer-Encoding'] = $value; + break; + + case 'cid': + $headers['Content-ID'] = '<' . $value . '>'; + break; + + case 'disposition': + $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); + break; + + case 'dfilename': + if (isset($headers['Content-Disposition'])) { + $headers['Content-Disposition'] .= '; filename="' . $value . '"'; + } else { + $dfilename = $value; + } + break; + + case 'description': + $headers['Content-Description'] = $value; + break; + + case 'charset': + if (isset($headers['Content-Type'])) { + $headers['Content-Type'] .= '; charset="' . $value . '"'; + } else { + $charset = $value; + } + break; + } + } + + // Default content-type + if (!isset($headers['Content-Type'])) { + $headers['Content-Type'] = 'text/plain'; + } + + //Default encoding + if (!isset($this->_encoding)) { + $this->_encoding = '7bit'; + } + + // Assign stuff to member variables + $this->_encoded = array(); + $this->_headers = $headers; + $this->_body = $body; + } + + /** + * encode() + * + * Encodes and returns the email. Also stores + * it in the encoded member variable + * + * @return An associative array containing two elements, + * body and headers. The headers element is itself + * an indexed array. + * @access public + */ + function encode() + { + $encoded =& $this->_encoded; + + if (!empty($this->_subparts)) { + srand((double)microtime()*1000000); + $boundary = '=_' . md5(rand() . microtime()); + $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; + + // Add body parts to $subparts + for ($i = 0; $i < count($this->_subparts); $i++) { + $headers = array(); + $tmp = $this->_subparts[$i]->encode(); + foreach ($tmp['headers'] as $key => $value) { + $headers[] = $key . ': ' . $value; + } + $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; + } + + $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . + implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . + '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; + + } else { + $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; + } + + // Add headers to $encoded + $encoded['headers'] =& $this->_headers; + + return $encoded; + } + + /** + * &addSubPart() + * + * Adds a subpart to current mime part and returns + * a reference to it + * + * @param $body The body of the subpart, if any. + * @param $params The parameters for the subpart, same + * as the $params argument for constructor. + * @return A reference to the part you just added. It is + * crucial if using multipart/* in your subparts that + * you use =& in your script when calling this function, + * otherwise you will not be able to add further subparts. + * @access public + */ + function &addSubPart($body, $params) + { + $this->_subparts[] = new Mail_mimePart($body, $params); + return $this->_subparts[count($this->_subparts) - 1]; + } + + /** + * _getEncodedData() + * + * Returns encoded data based upon encoding passed to it + * + * @param $data The data to encode. + * @param $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * @access private + */ + function _getEncodedData($data, $encoding) + { + switch ($encoding) { + case '8bit': + case '7bit': + return $data; + break; + + case 'quoted-printable': + return $this->_quotedPrintableEncode($data); + break; + + case 'base64': + return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); + break; + + default: + return $data; + } + } + + /** + * quoteadPrintableEncode() + * + * Encodes data to quoted-printable standard. + * + * @param $input The data to encode + * @param $line_max Optional max line length. Should + * not be more than 76 chars + * + * @access private + */ + function _quotedPrintableEncode($input , $line_max = 76) + { + $lines = preg_split("/\r?\n/", $input); + $eol = MAIL_MIMEPART_CRLF; + $escape = '='; + $output = ''; + + while(list(, $line) = each($lines)){ + + $linlen = strlen($line); + $newline = ''; + + for ($i = 0; $i < $linlen; $i++) { + $char = substr($line, $i, 1); + $dec = ord($char); + + if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only + $char = '=20'; + + } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only + $char = '=09'; + } elseif($dec == 9) { + ; // Do nothing if a tab. + } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { + $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); + } + + if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted + $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay + $newline = ''; + } + $newline .= $char; + } // end of for + $output .= $newline . $eol; + } + $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf + return $output; + } +} // End of class +?> diff --git a/program/lib/PEAR.php b/program/lib/PEAR.php new file mode 100644 index 000000000..5b76d7540 --- /dev/null +++ b/program/lib/PEAR.php @@ -0,0 +1,927 @@ + | +// | Stig Bakken | +// | Tomas V.V.Cox | +// +----------------------------------------------------------------------+ +// +// $Id$ +// + +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference, ej: $obj =& new PEAR_child; + * + * @since PHP 4.0.2 + * @author Stig Bakken + * @see http://pear.php.net/manual/ + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = get_class($this); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", get_class($this)); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @access public + * @return bool true if parameter is an error + */ + function isError($data) { + return (bool)(is_object($data) && + (get_class($data) == 'pear_error' || + is_subclass_of($data, 'pear_error'))); + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this DB object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE or + * PEAR_ERROR_CALLBACK. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this)) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + if ((is_string($options) && function_exists($options)) || + (is_array($options) && method_exists(@$options[0], @$options[1]))) + { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code AS $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } else { + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE or + * PEAR_ERROR_CALLBACK. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + if ($skipmsg) { + return new $ec($code, $mode, $options, $userinfo); + } else { + return new $ec($message, $code, $mode, $options, $userinfo); + } + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this)) { + return $this->raiseError($message, $code, null, null, $userinfo); + } else { + return PEAR::raiseError($message, $code, null, null, $userinfo); + } + } + + // }}} + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this)) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this)) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this)) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + return true; + } + + // }}} +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} + +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + + // Wait until we have a stack-groping function in PHP. + //var $file = ''; + //var $line = 0; + + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER or + * PEAR_ERROR_CALLBACK + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + $this->level = $options; + $this->callback = null; + } + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + printf($format, $this->getMessage()); + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_string($this->callback) && strlen($this->callback)) { + call_user_func($this->callback, $this); + } elseif (is_array($this->callback) && + sizeof($this->callback) == 2 && + is_object($this->callback[0]) && + is_string($this->callback[1]) && + strlen($this->callback[1])) { + @call_user_func($this->callback, $this); + } + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = get_class($this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + get_class($this), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + get_class($this), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +register_shutdown_function("_PEAR_call_destructors"); + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/program/lib/des.inc b/program/lib/des.inc new file mode 100644 index 000000000..00ecd688f --- /dev/null +++ b/program/lib/des.inc @@ -0,0 +1,218 @@ +> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + $left = (($left << 1) | ($left >> 31 & $masks[31])); + $right = (($right << 1) | ($right >> 31 & $masks[31])); + + //do this either 1 or 3 times for each chunk of the message + for ($j=0; $j<$iterations; $j+=3) { + $endloop = $looping[$j+1]; + $loopinc = $looping[$j+2]; + //now go through and perform the encryption or decryption + for ($i=$looping[$j]; $i!=$endloop; $i+=$loopinc) { //for efficiency + $right1 = $right ^ $keys[$i]; + $right2 = (($right >> 4 & $masks[4]) | ($right << 28)) ^ $keys[$i+1]; + //the result is attained by passing these bytes through the S selection functions + $temp = $left; + $left = $right; + $right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f] + | $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f] + | $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f] + | $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]); + } + $temp = $left; $left = $right; $right = $temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + $left = (($left >> 1 & $masks[1]) | ($left << 31)); + $right = (($right >> 1 & $masks[1]) | ($right << 31)); + + //now perform IP-1, which is IP in the opposite direction + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) {if ($encrypt) {$cbcleft = $left; $cbcright = $right;} else {$left ^= $cbcleft2; $right ^= $cbcright2;}} + $tempresult .= (chr($left>>24 & $masks[24]) . chr(($left>>16 & $masks[16]) & 0xff) . chr(($left>>8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right>>24 & $masks[24]) . chr(($right>>16 & $masks[16]) & 0xff) . chr(($right>>8 & $masks[8]) & 0xff) . chr($right & 0xff)); + + $chunk += 8; + if ($chunk == 512) {$result .= $tempresult; $tempresult = ""; $chunk = 0;} + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + return ($result . $tempresult); +} //end of des + +//des_createKeys +//this takes as input a 64 bit key (even though only 56 bits are used) +//as an array of 2 integers, and returns 16 48 bit keys +function des_createKeys ($key) { + //declaring this locally speeds things up a bit + $pc2bytes0 = array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204); + $pc2bytes1 = array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101); + $pc2bytes2 = array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808); + $pc2bytes3 = array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000); + $pc2bytes4 = array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010); + $pc2bytes5 = array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420); + $pc2bytes6 = array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002); + $pc2bytes7 = array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800); + $pc2bytes8 = array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002); + $pc2bytes9 = array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408); + $pc2bytes10 = array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020); + $pc2bytes11 = array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200); + $pc2bytes12 = array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010); + $pc2bytes13 = array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105); + $masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0); + + //how many iterations (1 for des, 3 for triple des) + $iterations = ((strlen($key) >= 24) ? 3 : 1); + //stores the return keys + $keys = array (); // size = 32 * iterations but you don't specify this in php + //now define the left shifts which need to be done + $shifts = array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + $m=0; + $n=0; + + for ($j=0; $j<$iterations; $j++) { //either 1 or 3 iterations + $left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + $right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333; $right ^= $temp; $left ^= ($temp << 2); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + $temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0); + //left needs to be put upside down + $left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0); + $right = $temp; + + //now go through and perform these shifts on the left and right keys + for ($i=0; $i < count($shifts); $i++) { + //shift the keys either one or two bits to the left + if ($shifts[$i] > 0) { + $left = (($left << 2) | ($left >> 26 & $masks[26])); + $right = (($right << 2) | ($right >> 26 & $masks[26])); + } else { + $left = (($left << 1) | ($left >> 27 & $masks[27])); + $right = (($right << 1) | ($right >> 27 & $masks[27])); + } + $left = $left & -0xf; + $right = $right & -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + $lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf] + | $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf] + | $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf] + | $pc2bytes6[($left >> 4 & $masks[4]) & 0xf]; + $righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf] + | $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf] + | $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf] + | $pc2bytes13[($right >> 4 & $masks[4]) & 0xf]; + $temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff; + $keys[$n++] = $lefttemp ^ $temp; $keys[$n++] = $righttemp ^ ($temp << 16); + } + } //for each iterations + //return the keys we've created + return $keys; +} //end of des_createKeys + +/* +////////////////////////////// TEST ////////////////////////////// +function stringToHex ($s) { + $r = "0x"; + $hexes = array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); + for ($i=0; $i> 4)] . $hexes [(ord($s{$i}) & 0xf)]);} + return $r; +} +echo "
";
+$key = "this is a 24 byte key !!";
+$message = "This is a test message";
+$ciphertext = des ($key, $message, 1, 0, null);
+echo "DES Test Encrypted: " . stringToHex ($ciphertext);
+$recovered_message = des ($key, $ciphertext, 0, 0, null);
+echo "\n";
+echo "DES Test Decrypted: " . $recovered_message;
+*/
+?>
\ No newline at end of file
diff --git a/program/lib/enriched.inc b/program/lib/enriched.inc
new file mode 100644
index 000000000..2435a8233
--- /dev/null
+++ b/program/lib/enriched.inc
@@ -0,0 +1,114 @@
+'=>'',''=>'',''=>'',
+			''=>'',''=>'',''=>'',
+			''=>'',''=>'',
+			''=>'',''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'',
+			''=>'');
+	
+	while(list($find,$replace)=each($a)){
+		$body = eregi_replace($find,$replace,$body);
+	}
+	return $body;
+}
+
+function enriched_font($body){
+	$pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/fontfamily\>(.*)/ims';
+	while(preg_match($pattern,$body,$a)){
+		//print_r($a);
+		if (count($a)!=5) continue;
+		$body=$a[1].''.$a[3].''.$a[4];
+	}
+
+	return $body;
+}
+
+
+function enriched_color($body){
+	$pattern = '/(.*)\\(.*)\<\/param\>(.*)\<\/color\>(.*)/ims';
+	while(preg_match($pattern,$body,$a)){
+		//print_r($a);
+		if (count($a)!=5) continue;
+
+		//extract color (either by name, or ####,####,####)
+		if (strpos($a[2],',')){
+			$rgb = explode(',',$a[2]);
+			$color ='#';
+			for($i=0;$i<3;$i++) $color.=substr($rgb[$i],0,2); //just take first 2 bytes
+		}else{
+			$color = $a[2];
+		}
+		
+		//put it all together
+		$body = $a[1].''.$a[3].''.$a[4];
+	}
+
+	return $body;
+}
+
+function enriched_excerpt($body){
+
+	$pattern = '/(.*)\(.*)\<\/excerpt\>(.*)/i';
+	while(preg_match($pattern,$body,$a)){
+		//print_r($a);
+		if (count($a)!=4) continue;
+		$quoted = '';
+		$lines = explode('
',$a[2]); + foreach($lines as $n=>$line) $quoted.='>'.$line.'
'; + $body=$a[1].''.$quoted.''.$a[3]; + } + + return $body; +} + +function enriched_to_html($body){ + $body = str_replace('<<','<',$body); + $body = enriched_convert_newlines($body); + $body = str_replace("\n", '
', $body); + $body = enriched_convert_formatting($body); + $body = enriched_color($body); + $body = enriched_font($body); + $body = enriched_excerpt($body); + //$body = nl2br($body); + return $body; +} + +?> \ No newline at end of file diff --git a/program/lib/html2text.inc b/program/lib/html2text.inc new file mode 100644 index 000000000..82a254e56 --- /dev/null +++ b/program/lib/html2text.inc @@ -0,0 +1,440 @@ + * +* All rights reserved. * +* * +* This script is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* The GNU General Public License can be found at * +* http://www.gnu.org/copyleft/gpl.html. * +* * +* This script is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* Author(s): Jon Abernathy * +* * +* Last modified: 04/06/05 * +* Modified: 2004/05/19 (tbr) * +* * +*************************************************************************/ + + +/** +* Takes HTML and converts it to formatted, plain text. +* +* Thanks to Alexander Krug (http://www.krugar.de/) to pointing out and +* correcting an error in the regexp search array. Fixed 7/30/03. +* +* Updated set_html() function's file reading mechanism, 9/25/03. +* +* Thanks to Joss Sanglier (http://www.dancingbear.co.uk/) for adding +* several more HTML entity codes to the $search and $replace arrays. +* Updated 11/7/03. +* +* Thanks to Darius Kasperavicius (http://www.dar.dar.lt/) for +* suggesting the addition of $allowed_tags and its supporting function +* (which I slightly modified). Updated 3/12/04. +* +* Thanks to Justin Dearing for pointing out that a replacement for the +* tag was missing, and suggesting an appropriate fix. +* Updated 8/25/04. +* +* Thanks to Mathieu Collas (http://www.myefarm.com/) for finding a +* display/formatting bug in the _build_link_list() function: email +* readers would show the left bracket and number ("[1") as part of the +* rendered email address. +* Updated 12/16/04. +* +* Thanks to Wojciech Bajon (http://histeria.pl/) for submitting code +* to handle relative links, which I hadn't considered. I modified his +* code a bit to handle normal HTTP links and MAILTO links. Also for +* suggesting three additional HTML entity codes to search for. +* Updated 03/02/05. +* +* Thanks to Jacob Chandler for pointing out another link condition +* for the _build_link_list() function: "https". +* Updated 04/06/05. +* +* @author Jon Abernathy +* @version 0.6.1 +* @since PHP 4.0.2 +*/ +class html2text +{ + + /** + * Contains the HTML content to convert. + * + * @var string $html + * @access public + */ + var $html; + + /** + * Contains the converted, formatted text. + * + * @var string $text + * @access public + */ + var $text; + + /** + * Maximum width of the formatted text, in columns. + * + * @var integer $width + * @access public + */ + var $width = 70; + + /** + * List of preg* regular expression patterns to search for, + * used in conjunction with $replace. + * + * @var array $search + * @access public + * @see $replace + */ + var $search = array( + "/\r/", // Non-legal carriage return + "/[\n\t]+/", // Newlines and tabs + '/]*>.*?<\/script>/i', // ', $pos))) + { + $pos2 += 8; + $body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2); + $body_lc = strtolower($body); + } + + + // resolve + $base_reg = '/()/i'; + if (preg_match($base_reg, $body, $regs)) + { + $base_url = $regs[2]; + $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body); + $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body); + $body = preg_replace($base_reg, '', $body); + } + + + // add comments arround html and other tags + $out = preg_replace(array('/(<\/?html[^>]*>)/i', + '/(<\/?head[^>]*>)/i', + '/(]*>.+<\/title>)/ui', + '/(<\/?meta[^>]*>)/i'), + '', + $body); + + $out = preg_replace(array('/(]*>)/i', + '/(<\/body>)/i'), + array('
', + '
'), + $out); + + + return $out; + } + + + +// replace all css definitions with #container [def] +function rcmail_mod_css_styles($source, $container_id) + { + $a_css_values = array(); + $last_pos = 0; + + // cut out all contents between { and } + while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) + { + $key = sizeof($a_css_values); + $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1)); + $source = substr($source, 0, $pos+1) . "<>" . substr($source, $pos2, strlen($source)-$pos2); + $last_pos = $pos+2; + } + + $styles = preg_replace('/(^\s*|,\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im', "\\1#$container_id \\2", $source); + $styles = preg_replace('/<>/e', "\$a_css_values[\\1]", $styles); + + // replace body definition because we also stripped off the tag + $styles = preg_replace("/$container_id\s+body/i", "$container_id div.rcmBody", $styles); + + return $styles; + } + + + +// return first text part of a message +function rcmail_first_text_part($message_parts) + { + if (!is_array($message_parts)) + return FALSE; + + $html_part = NULL; + + // check all message parts + foreach ($message_parts as $pid => $part) + { + $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary); + if ($mimetype=='text/plain') + { + $body = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']); + $body = rcube_imap::charset_decode($body, $part->ctype_parameters); + return $body; + } + else if ($mimetype=='text/html') + { + $html_part = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']); + $html_part = rcube_imap::charset_decode($html_part, $part->ctype_parameters); + } + } + + + // convert HTML to plain text + if ($html_part) + { + // remove special chars encoding + $trans = array_flip(get_html_translation_table(HTML_ENTITIES)); + $html_part = strtr($html_part, $trans); + + // create instance of html2text class + $txt = new html2text($html_part); + return $txt->get_text(); + } + + return FALSE; + } + + +// get source code of a specific message and cache it +function rcmail_message_source($uid) + { + global $IMAP, $DB; + + // 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); + + // get message from server and cache it + if (!$msg_source) + { + $msg_source = $IMAP->get_raw_body($uid); + rcube_write_cache($message_id, $msg_source, TRUE); + } + + return $msg_source; + } + + +// decode address string and re-format it as HTML links +function rcmail_address_string($input, $max=NULL, $addicon=NULL) + { + global $IMAP, $PRINT_MODE, $CONFIG, $OUTPUT, $JS_OBJECT_NAME, $EMAIL_ADDRESS_PATTERN; + + $a_parts = $IMAP->decode_address_list($input); + + if (!sizeof($a_parts)) + return $input; + + $c = count($a_parts); + $j = 0; + $out = ''; + + foreach ($a_parts as $part) + { + $j++; + if ($PRINT_MODE) + $out .= sprintf('%s <%s>', htmlentities($part['name']), $part['mailto']); + else if (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto'])) + { + $out .= sprintf('%s', + $part['mailto'], + $JS_OBJECT_NAME, + $part['mailto'], + $part['mailto'], + htmlentities($part['name'])); + + if ($addicon) + $out .= sprintf(' add', + $JS_OBJECT_NAME, + urlencode($part['string']), + rcube_label('addtoaddressbook'), + $CONFIG['skin_path'], + $addicon); + } + else + { + if ($part['name']) + $out .= htmlentities($part['name']); + if ($part['mailto']) + $out .= (strlen($out) ? ' ' : '') . sprintf('<%s>', $part['mailto']); + } + + if ($c>$j) + $out .= ','.($max ? ' ' : ' '); + + if ($max && $j==$max && $c>$j) + { + $out .= '...'; + break; + } + } + + return $out; + } + + +function rcmail_message_part_controls() + { + global $CONFIG, $IMAP, $MESSAGE; + + if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']]) + return ''; + + $part = $MESSAGE['parts'][$_GET['_part']]; + + $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary')); + $out = '\n"; + + $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name']; + $filesize = strlen($IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding'])); + + if ($filename) + { + $out .= sprintf(''."\n", + rcube_label('filename'), + rep_specialchars_output($filename), + str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), + rcube_label('download')); + } + + if ($filesize) + $out .= sprintf(''."\n", + rcube_label('filesize'), + show_bytes($filesize)); + + $out .= "\n
%s%s[%s]
%s%s
"; + + return $out; + } + + + +function rcmail_message_part_frame($attrib) + { + global $MESSAGE; + + $part = $MESSAGE['parts'][$_GET['_part']]; + $ctype_primary = strtolower($part->ctype_primary); + + $attrib['src'] = './?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']); + + $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height')); + $out = ''."\n", + $GET_URL, + $framename, + $attrib_str, + rcube_label('loading')); + + + $OUTPUT->add_script("$JS_OBJECT_NAME.set_env('contentframe', '$framename');"); + + return $out; + } + + +function rcmail_remote_objects_msg($attrib) + { + global $CONFIG, $OUTPUT, $JS_OBJECT_NAME; + + if (!$attrib['id']) + $attrib['id'] = 'rcmremoteobjmsg'; + + // allow the following attributes to be added to the
tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id')); + $out = '"; + + $out .= rep_specialchars_output(sprintf('%s %s', + rcube_label('blockedimages'), + $JS_OBJECT_NAME, + rcube_label('showimages'), + rcube_label('showimages'))); + + $out .= '
'; + + $OUTPUT->add_script(sprintf("%s.gui_object('remoteobjectsmsg', '%s');", $JS_OBJECT_NAME, $attrib['id'])); + return $out; + } + + +if ($_action=='print') + parse_template('printmessage'); +else + parse_template('message'); +?> \ No newline at end of file diff --git a/program/steps/mail/upload.inc b/program/steps/mail/upload.inc new file mode 100644 index 000000000..4f1eb3dab --- /dev/null +++ b/program/steps/mail/upload.inc @@ -0,0 +1,75 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +if (!$_SESSION['compose']) + { + exit; + } + + +if (strlen($CONFIG['temp_dir'])) + $temp_dir = $CONFIG['temp_dir'].(!eregi('\/$', $CONFIG['temp_dir']) ? '/' : '').$_SESSION['compose']['id']; + +if (!is_array($_SESSION['compose']['attachments'])) + { + $_SESSION['compose']['attachments'] = array(); + + // create temp-dir for uploaded attachments + if ($CONFIG['temp_dir'] && is_writeable($CONFIG['temp_dir'])) + { + mkdir($temp_dir); + $_SESSION['compose']['temp_dir'] = $temp_dir; + } + } + + +$response = ''; + +foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) + { + $tmpfname = tempnam($temp_dir, 'rcmAttmnt'); + if (copy($filepath, $tmpfname)) + { + $_SESSION['compose']['attachments'][] = array('name' => $_FILES['_attachments']['name'][$i], + 'mimetype' => $_FILES['_attachments']['type'][$i], + 'path' => $tmpfname); + + $response .= sprintf("parent.%s.add2attachment_list('%s');\n", $JS_OBJECT_NAME, $_FILES['_attachments']['name'][$i]); + } + } + + +// send html page with JS calls as response +print << + + +EOF; +exit; + +?> \ No newline at end of file diff --git a/program/steps/mail/viewsource.inc b/program/steps/mail/viewsource.inc new file mode 100644 index 000000000..8b8c90cd1 --- /dev/null +++ b/program/steps/mail/viewsource.inc @@ -0,0 +1,39 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +// similar code as in program/steps/mail/get.inc +if ($_GET['_uid']) + { + header('Content-Type: text/plain'); + print rcmail_message_source($_GET['_uid']); + } +else + { + raise_error(array('code' => 500, + 'type' => 'php', + 'message' => 'Message UID '.$_GET['_uid'].' not found'), + TRUE, + TRUE); + } + +exit; +?> \ No newline at end of file diff --git a/program/steps/settings/delete_identity.inc b/program/steps/settings/delete_identity.inc new file mode 100644 index 000000000..dacfc0563 --- /dev/null +++ b/program/steps/settings/delete_identity.inc @@ -0,0 +1,55 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +$REMOTE_REQUEST = $_GET['_remote'] ? TRUE : FALSE; + +if ($_GET['_iid']) + { + $DB->query(sprintf("UPDATE %s + SET del='1' + WHERE user_id=%d + AND identity_id IN (%s)", + get_table_name('identities'), + $_SESSION['user_id'], + $_GET['_iid'])); + + $count = $DB->affected_rows(); + if ($count) + { + $commands = show_message('deletedsuccessfully', 'confirmation'); + } + + // send response + if ($REMOTE_REQUEST) + rcube_remote_response($commands); + } + + +if ($REMOTE_REQUEST) + exit; + + +// go to identities page +$_action = 'identities'; + +// overwrite action variable +$OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action)); +?> \ No newline at end of file diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc new file mode 100644 index 000000000..f4134d329 --- /dev/null +++ b/program/steps/settings/edit_identity.inc @@ -0,0 +1,106 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +if (($_GET['_iid'] || $_POST['_iid']) && $_action=='edit-identity') + { + $id = $_POST['_iid'] ? $_POST['_iid'] : $_GET['_iid']; + $DB->query(sprintf("SELECT * FROM %s + WHERE identity_id=%d + AND user_id=%d + AND del!='1'", + get_table_name('identities'), + $id, + $_SESSION['user_id'])); + + $IDENTITY_RECORD = $DB->fetch_assoc(); + + if (is_array($IDENTITY_RECORD)) + $OUTPUT->add_script(sprintf("%s.set_env('iid', '%s');", $JS_OBJECT_NAME, $IDENTITY_RECORD['identity_id'])); + + $PAGE_TITLE = rcube_label('edititem'); + } +else + $PAGE_TITLE = rcube_label('newitem'); + + + +function rcube_identity_form($attrib) + { + global $IDENTITY_RECORD, $JS_OBJECT_NAME; + + if (!$IDENTITY_RECORD && $GLOBALS['_action']!='add-identity') + return rcube_label('notfound'); + + list($form_start, $form_end) = get_form_tags($attrib, 'save-identity', array('name' => '_iid', 'value' => $IDENTITY_RECORD['identity_id'])); + unset($attrib['form']); + + + // list of available cols + $a_show_cols = array('name' => array('type' => 'text'), + 'email' => array('type' => 'text'), + 'organization' => array('type' => 'text'), + 'reply-to' => array('type' => 'text', 'label' => 'replyto'), + 'bcc' => array('type' => 'text'), + 'default' => array('type' => 'checkbox', 'label' => 'setdefault')); + + + // a specific part is requested + if ($attrib['part']) + { + $colprop = $a_show_cols[$attrib['part']]; + if (is_array($colprop)) + { + $out = $form_start; + $out .= rcmail_get_edit_field($attrib['part'], $IDENTITY_RECORD[$attrib['part']], $attrib, $colprop['type']); + return $out; + } + else + return ''; + } + + + // return the complete edit form as table + $out = "$form_start\n\n"; + + foreach ($a_show_cols as $col => $colprop) + { + $attrib['id'] = 'rcmfd_'.$col; + $label = strlen($colprop['label']) ? $colprop['label'] : $col; + $value = rcmail_get_edit_field($col, $IDENTITY_RECORD[$col], $attrib, $colprop['type']); + + $out .= sprintf("\n", + $attrib['id'], + rcube_label($label), + $value); + } + + $out .= "\n
%s
$form_end"; + + return $out; + } + + + +if ($_action=='add-identity' && template_exists('addidentity')) + parse_template('addidentity'); + +parse_template('editidentity'); +?> \ No newline at end of file diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc new file mode 100644 index 000000000..826717fd9 --- /dev/null +++ b/program/steps/settings/func.inc @@ -0,0 +1,194 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + + +// get user record +$sql_result = $DB->query(sprintf("SELECT username, mail_host FROM %s + WHERE user_id=%d", + get_table_name('users'), + $_SESSION['user_id'])); + +if ($USER_DATA = $DB->fetch_assoc($sql_result)) + $PAGE_TITLE = sprintf('%s %s@%s', rcube_label('settingsfor'), $USER_DATA['username'], $USER_DATA['mail_host']); + + + +function rcmail_user_prefs_form($attrib) + { + global $DB, $CONFIG, $sess_user_lang; + + list($form_start, $form_end) = get_form_tags($attrib, 'save-prefs'); + unset($attrib['form']); + + // allow the following attributes to be added to the tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + + // return the complete edit form as table + $out = "$form_start\n\n"; + + $a_show_cols = array('language' => array('type' => 'text'), + 'pagesize' => array('type' => 'text'), + 'timezone' => array('type' => 'text')); + + // show language selection + $field_id = 'rcmfd_lang'; + $select_lang = new select(array('name' => '_language', 'id' => $field_id)); + $select_lang->add('English', 'en'); + $select_lang->add('Deutsch', 'de'); + + $out .= sprintf("\n", + $field_id, + rcube_label('language'), + $select_lang->show($sess_user_lang)); + + + // show page size selection + $field_id = 'rcmfd_timezone'; + $select_timezone = new select(array('name' => '_timezone', 'id' => $field_id)); + $select_timezone->add('(GMT -11:00) Midway Island, Samoa', '-11'); + $select_timezone->add('(GMT -10:00) Hawaii', '-10'); + $select_timezone->add('(GMT -9:00) Alaska', '-9'); + $select_timezone->add('(GMT -8:00) Pacific Time (US/Canada)', '-8'); + $select_timezone->add('(GMT -7:00) Mountain Time (US/Canada)', '-7'); + $select_timezone->add('(GMT -6:00) Central Time (US/Canada), Mexico City', '-6'); + $select_timezone->add('(GMT -5:00) Eastern Time (US/Canada), Bogota, Lima', '-5'); + $select_timezone->add('(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz', '-4'); + $select_timezone->add('(GMT -3:00) Brazil, Buenos Aires, Georgetown', '-3'); + $select_timezone->add('(GMT -2:00) Mid-Atlantic', '-2'); + $select_timezone->add('(GMT -1:00) Azores, Cape Verde Islands', '-1'); + $select_timezone->add('(GMT) Western Europe, London, Lisbon, Casablanca', '0'); + $select_timezone->add('(GMT +1:00) Central European Time', '1'); + $select_timezone->add('(GMT +2:00) EET: Kaliningrad, South Africa', '2'); + $select_timezone->add('(GMT +3:00) Baghdad, Kuwait, Riyadh, Moscow, Nairobi', '3'); + $select_timezone->add('(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', '4'); + $select_timezone->add('(GMT +5:00) Ekaterinburg, Islamabad, Karachi', '5'); + $select_timezone->add('(GMT +6:00) Almaty, Dhaka, Colombo', '6'); + $select_timezone->add('(GMT +7:00) Bangkok, Hanoi, Jakarta', '7'); + $select_timezone->add('(GMT +8:00) Beijing, Perth, Singapore, Taipei', '8'); + $select_timezone->add('(GMT +9:00) Tokyo, Seoul, Yakutsk', '9'); + $select_timezone->add('(GMT +10:00) EAST/AEST: Guam, Vladivostok', '10'); + $select_timezone->add('(GMT +11:00) Magadan, Solomon Islands', '11'); + $select_timezone->add('(GMT +12:00) Auckland, Wellington, Kamchatka', '12'); + $select_timezone->add('(GMT +13:00) Tonga, Pheonix Islands', '13'); + $select_timezone->add('(GMT +14:00) Kiribati', '14'); + + + $out .= sprintf("\n", + $field_id, + rcube_label('timezone'), + $select_timezone->show($CONFIG['timezone'])); + + + // show page size selection + $field_id = 'rcmfd_pgsize'; + $input_pagesize = new textfield(array('name' => '_pagesize', 'id' => $field_id, 'size' => 5)); + + $out .= sprintf("\n", + $field_id, + rcube_label('pagesize'), + $input_pagesize->show($CONFIG['pagesize'])); + + // show checkbox for HTML/plaintext messages + $field_id = 'rcmfd_htmlmsg'; + $input_pagesize = new checkbox(array('name' => '_prefer_html', 'id' => $field_id, 'value' => 1)); + + $out .= sprintf("\n", + $field_id, + rcube_label('preferhtml'), + $input_pagesize->show($CONFIG['prefer_html']?1:0)); + + + $out .= "\n
%s
%s
%s
%s
$form_end"; + + return $out; + } + + + + +function rcmail_identities_list($attrib) + { + global $DB, $CONFIG, $OUTPUT, $JS_OBJECT_NAME; + + + // get contacts from DB + $sql_result = $DB->query(sprintf("SELECT * FROM %s + WHERE del!='1' + AND user_id=%d + ORDER BY `default` DESC, name ASC", + get_table_name('identities'), + $_SESSION['user_id'])); + + + // add id to message list table if not specified + if (!strlen($attrib['id'])) + $attrib['id'] = 'rcmIdentitiesList'; + + // define list of cols to be displayed + $a_show_cols = array('name', 'email', 'organization', 'reply-to'); + + // create XHTML table + $out = rcube_table_output($attrib, $sql_result, $a_show_cols, 'identity_id'); + + // set client env + $javascript = sprintf("%s.gui_object('identitieslist', '%s');\n", $JS_OBJECT_NAME, $attrib['id']); + $OUTPUT->add_script($javascript); + + return $out; + } + + + +// similar function as in /steps/addressbook/edit.inc +function get_form_tags($attrib, $action, $add_hidden=array()) + { + global $OUTPUT, $JS_OBJECT_NAME, $EDIT_FORM, $SESS_HIDDEN_FIELD; + + $form_start = ''; + if (!strlen($EDIT_FORM)) + { + $hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task'])); + $hiddenfields->add(array('name' => '_action', 'value' => $action)); + + if ($add_hidden) + $hiddenfields->add($add_hidden); + + if ($_GET['_framed'] || $_POST['_framed']) + $hiddenfields->add(array('name' => '_framed', 'value' => 1)); + + $form_start = !strlen($attrib['form']) ? '
' : ''; + $form_start .= "\n$SESS_HIDDEN_FIELD\n"; + $form_start .= $hiddenfields->show(); + } + + $form_end = (!strlen($EDIT_FORM) && !strlen($attrib['form'])) ? '
' : ''; + $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form'; + + if (!strlen($EDIT_FORM)) + $OUTPUT->add_script("$JS_OBJECT_NAME.gui_object('editform', '$form_name');"); + + $EDIT_FORM = $form_name; + + return array($form_start, $form_end); + } + + +?> \ No newline at end of file diff --git a/program/steps/settings/identities.inc b/program/steps/settings/identities.inc new file mode 100644 index 000000000..b760f09bf --- /dev/null +++ b/program/steps/settings/identities.inc @@ -0,0 +1,48 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +if ($USER_DATA = $DB->fetch_assoc($sql_result)) + $PAGE_TITLE = sprintf('%s (%s@%s)', rcube_label('identities'), $USER_DATA['username'], $USER_DATA['mail_host']); + + + +// similar function as /steps/addressbook/func.inc::rcmail_contact_frame() +function rcmail_identity_frame($attrib) + { + global $OUTPUT, $JS_OBJECT_NAME; + + if (!$attrib['id']) + $attrib['id'] = 'rcmIdentityFrame'; + + $attrib['name'] = $attrib['id']; + + $OUTPUT->add_script(sprintf("%s.set_env('contentframe', '%s');", $JS_OBJECT_NAME, $attrib['name'])); + + $attrib_str = create_attrib_string($attrib, array('name', 'id', 'class', 'style', 'src', 'width', 'height', 'frameborder')); + $out = ''; + + return $out; + } + + + +parse_template('identities'); +?> \ No newline at end of file diff --git a/program/steps/settings/manage_folders.inc b/program/steps/settings/manage_folders.inc new file mode 100644 index 000000000..38f9e1a0e --- /dev/null +++ b/program/steps/settings/manage_folders.inc @@ -0,0 +1,176 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +// init IAMP connection +rcmail_imap_init(TRUE); + + +// subscribe to one or more mailboxes +if ($_action=='subscribe') + { + if (strlen($_GET['_mboxes'])) + $IMAP->subscribe(explode(',', $_GET['_mboxes'])); + + if ($_GET['_remote']) + rcube_remote_response('// subscribed'); + } + +// unsubscribe one or more mailboxes +else if ($_action=='unsubscribe') + { + if (strlen($_GET['_mboxes'])) + $IMAP->unsubscribe(explode(',', $_GET['_mboxes'])); + + if ($_GET['_remote']) + rcube_remote_response('// unsubscribed'); + } + +// create a new mailbox +else if ($_action=='create-folder') + { + if (strlen($_GET['_name'])) + $create = $IMAP->create_mailbox(trim($_GET['_name']), TRUE); + + if ($create && $_GET['_remote']) + { + $commands = sprintf("this.add_folder_row('%s')", rep_specialchars_output($_GET['_name'], 'js')); + rcube_remote_response($commands); + } + else if (!$create && $_GET['_remote']) + { + $commands = show_message('errorsaving', 'error'); + rcube_remote_response($commands); + } + else if (!$create) + show_message('errorsaving', 'error'); + } + +// delete an existing IMAP mailbox +else if ($_action=='delete-folder') + { + if (strlen($_GET['_mboxes'])) + $IMAP->delete_mailbox(explode(',', $_GET['_mboxes'])); + + if ($_GET['_remote']) + rcube_remote_response('// deleted'); + } + + + +// build table with all folders listed by server +function rcube_subscription_form($attrib) + { + global $IMAP, $CONFIG, $OUTPUT, $JS_OBJECT_NAME; + + list($form_start, $form_end) = get_form_tags($attrib, 'folders'); + unset($attrib['form']); + + + if (!$attrib['id']) + $attrib['id'] = 'rcmSubscriptionlist'; + + // allow the following attributes to be added to the tag + $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + + $out = "$form_start\n\n"; + + + // add table header + $out .= "\n"; + $out .= sprintf('', rcube_label('foldername'), rcube_label('subscribed')); + $out .= "\n\n\n"; + + + // get folders from server + $a_unsubscribed = $IMAP->list_unsubscribed(); + $a_subscribed = $IMAP->list_mailboxes(); + $a_js_folders = array(); + + $checkbox_subscribe = new checkbox(array('name' => '_subscribed[]', 'onclick' => "$JS_OBJECT_NAME.command(this.checked?'subscribe':'unsubscribe',this.value)")); + + if ($attrib['deleteicon']) + $button = sprintf('%s', $CONFIG['skin_path'], $attrib['deleteicon'], rcube_label('delete')); + else + $button = rcube_label('delete'); + + + // create list of available folders + foreach ($a_unsubscribed as $i => $folder) + { + $zebra_class = $i%2 ? 'even' : 'odd'; + $folder_js = rep_specialchars_output($folder, 'js'); + $a_js_folders['rcmrow'.($i+1)] = $folder_js; + + $out .= sprintf('', + $i+1, + $zebra_class, + rep_specialchars_output($folder, 'html'), + $checkbox_subscribe->show(in_array($folder, $a_subscribed)?$folder:'', array('value' => $folder)), + $JS_OBJECT_NAME, + $folder_js, + rcube_label('deletefolder'), + $button); + + $out .= "\n"; + } + + $out .= "\n
%s%s
%s%s%s
"; + $out .= "\n$form_end"; + + + $javascript = sprintf("%s.gui_object('subscriptionlist', '%s');\n", $JS_OBJECT_NAME, $attrib['id']); + $javascript .= sprintf("%s.set_env('subscriptionrows', %s);", $JS_OBJECT_NAME, array2js($a_js_folders)); + $OUTPUT->add_script($javascript); + + return $out; + } + + +function rcube_create_folder_form($attrib) + { + global $JS_OBJECT_NAME; + + list($form_start, $form_end) = get_form_tags($attrib, 'create-folder'); + unset($attrib['form']); + + + // return the complete edit form as table + $out = "$form_start\n"; + + $input = new textfield(array('name' => '_folder_name')); + $out .= $input->show(); + + if (get_boolean($attrib['button'])) + { + $button = new input_field(array('type' => 'button', + 'value' => rcube_label('create'), + 'onclick' => "$JS_OBJECT_NAME.command('create-folder',this.form)")); + $out .= $button->show(); + } + + $out .= "\n$form_end"; + + return $out; + } + + +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 new file mode 100644 index 000000000..b4b1fec27 --- /dev/null +++ b/program/steps/settings/save_identity.inc @@ -0,0 +1,136 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'default'); + + +// update an existing contact +if ($_POST['_iid']) + { + $a_write_sql = array(); + + foreach ($a_save_cols as $col) + { + $fname = '_'.$col; + if (!isset($_POST[$fname])) + continue; + + $a_write_sql[] = sprintf("`%s`='%s'", $col, addslashes($_POST[$fname])); + } + + if (sizeof($a_write_sql)) + { + $DB->query(sprintf("UPDATE %s + SET %s + WHERE identity_id=%d + AND user_id=%d + AND del!='1'", + get_table_name('identities'), + join(', ', $a_write_sql), + $_POST['_iid'], + $_SESSION['user_id'])); + + $updated = $DB->affected_rows(); + } + + if ($updated) + { + show_message('successfullysaved', 'confirmation'); + + // mark all other identities as 'not-default' + $DB->query(sprintf("UPDATE %s + SET `default`='0' + WHERE identity_id!=%d + AND user_id=%d + AND del!='1'", + get_table_name('identities'), + $_POST['_iid'], + $_SESSION['user_id'])); + + if ($_POST['_framed']) + { + // update the changed col in list + // ... + } + } + else + { + // show error message + + } + } + +// insert a new contact +else + { + $a_insert_cols = $a_insert_values = array(); + + foreach ($a_save_cols as $col) + { + $fname = '_'.$col; + if (!isset($_POST[$fname])) + continue; + + $a_insert_cols[] = "`$col`"; + $a_insert_values[] = sprintf("'%s'", addslashes($_POST[$fname])); + } + + if (sizeof($a_insert_cols)) + { + $DB->query(sprintf("INSERT INTO %s + (user_id, %s) + VALUES (%d, %s)", + get_table_name('identities'), + join(', ', $a_insert_cols), + $_SESSION['user_id'], + join(', ', $a_insert_values))); + + $insert_id = $DB->insert_id(); + } + + if ($insert_id) + { + $_GET['_iid'] = $insert_id; + + if ($_POST['_framed']) + { + // add contact row or jump to the page where it should appear + // .... + } + } + else + { + // show error message + } + } + + +// go to next step +if ($_POST['_framed']) + $_action = 'edit-identitiy'; +else + $_action = 'identities'; + + +// overwrite action variable +$OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action)); + +?> \ No newline at end of file diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc new file mode 100644 index 000000000..1524b9ead --- /dev/null +++ b/program/steps/settings/save_prefs.inc @@ -0,0 +1,59 @@ + | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +$a_user_prefs = $_SESSION['user_prefs']; +if (!is_array($a_user_prefs)) + $a_user_prefs = array(); + + +$a_user_prefs['timezone'] = isset($_POST['_timezone']) ? (int)$_POST['_timezone'] : $CONFIG['timezone']; +$a_user_prefs['pagesize'] = is_numeric($_POST['_pagesize']) ? (int)$_POST['_pagesize'] : $CONFIG['pagesize']; +$a_user_prefs['prefer_html'] = isset($_POST['_prefer_html']) ? TRUE : FALSE; + +if (isset($_POST['_language'])) + $sess_user_lang = $_SESSION['user_lang'] = $_POST['_language']; + + +$DB->query(sprintf("UPDATE %s + SET preferences='%s', + language='%s' + WHERE user_id=%d", + get_table_name('users'), + addslashes(serialize($a_user_prefs)), + $sess_user_lang, + $_SESSION['user_id'])); + +if ($DB->affected_rows()) + { + show_message('successfullysaved', 'confirmation'); + + $_SESSION['user_prefs'] = $a_user_prefs; + $CONFIG = array_merge($CONFIG, $a_user_prefs); + } + + +// go to next step +$_action = 'preferences'; + +// overwrite action variable +$OUTPUT->add_script(sprintf("\n%s.set_env('action', '%s');", $JS_OBJECT_NAME, $_action)); + +?> \ No newline at end of file diff --git a/skins/default/addresses.css b/skins/default/addresses.css new file mode 100644 index 000000000..d660c3c8f --- /dev/null +++ b/skins/default/addresses.css @@ -0,0 +1,119 @@ +/***** RoundCube|Mail address book task styles *****/ + + +#abooktoolbar +{ + position: absolute; + top: 32px; + left: 200px; + height: 35px; +} + +#abooktoolbar a +{ + padding-right: 10px; +} + +#abookcountbar +{ + position: absolute; + top: 50px; + left: 490px; + width: 200px; + height: 20px; + text-align: left; +} + +#abookcountbar span +{ + font-size: 11px; + color: #333333; +} + + +#addresslist +{ + position: absolute; + top: 75px; + left: 20px; + width: 450px; + bottom: 60px; + border: 1px solid #999999; + background-color: #F9F9F9; + overflow: auto; + /* css hack for IE */ + height: expression((parseInt(document.documentElement.clientHeight)-135)+'px'); +} + +#contacts-table +{ + width: 100%; + table-layout: fixed; + /* css hack for IE */ + width: expression(document.getElementById('addresslist').clientWidth); +} + + +#contacts-table tbody td +{ + cursor: pointer; +} + + +#contacts-box +{ + position: absolute; + top: 75px; + left: 490px; + right: 40px; + bottom: 60px; + border: 1px solid #999999; + overflow: hidden; + /* css hack for IE */ + width: expression((parseInt(document.documentElement.clientWidth)-530)+'px'); + height: expression((parseInt(document.documentElement.clientHeight)-135)+'px'); +} + +body.iframe, +#contact-frame +{ + background-color: #F9F9F9; +} + +#contact-frame +{ + border: none; +/* visibility: hidden; */ +} + +#contact-title +{ + height: 12px !important; +/* height: 20px; */ + padding: 4px 20px 3px 20px; + border-bottom: 1px solid #999999; + color: #333333; + font-size: 11px; + font-weight: bold; + background-color: #EBEBEB; + background-image: url(images/listheader_aqua.gif); +} + +#contact-details +{ + padding: 15px 20px 10px 20px; +} + +#contact-details table td.title +{ + color: #666666; + font-weight: bold; + text-align: right; + padding-right: 10px; +} + + + + + + diff --git a/skins/default/common.css b/skins/default/common.css new file mode 100755 index 000000000..2ba97d843 --- /dev/null +++ b/skins/default/common.css @@ -0,0 +1,277 @@ +/***** RoundCube|Mail basic styles *****/ + +body +{ + margin: 8px; + background-color: #F2F2F2; /* #EBEBEB; */ + color: #000000; +} + +body.iframe +{ + margin: 0px; +} + +body.extwin +{ + margin: 10px; +} + +body, td, th, span, div, p, h3 +{ + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + color: #000000; +} + +th +{ + font-weight: normal; +} + +h3 +{ + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 18px; + color: #000000; +} + +a, a:active, a:visited +{ + color: #000000; +} + +a.button, a.button:visited, a.tab, a.tab:visited, a.axislist +{ + color: #000000; + text-decoration: none; +} + +a.tab +{ + width: 80px; + display: block; + text-align: center; +} + +hr +{ + height: 1px; + background-color: #666666; + border-style: none; +} + +input, textarea +{ + font-size: 9pt; + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + padding: 1px; + padding-left: 3px; + padding-right: 3px; + background-color: #ffffff; + border: 1px solid #666666; +} + +input.button +{ + height: 20px; + color: #333333; + font-size: 12px; + padding-left: 8px; + padding-right: 8px; + background: url(images/buttons/bg.gif) repeat-x #f0f0f0; + border: 1px solid #a4a4a4; +} + +input.button:hover +{ + color: black; +} + +img +{ + behavior: url('skins/default/pngbehavior.htc'); +} + +.alttext +{ + font-size: 11px; +} + + +/** common user interface objects */ + +#header +{ +/* margin: 10px auto; */ + width: 170px; + height: 40px; + margin-top: 0px; + margin-left: 10px; +/* border: 1px solid #cccccc; */ +} + +#footer +{ + position: fixed !important; + left: 0px; + right: 0px; + bottom: 0px !important; + height: 40px; + background-color: #f2f2f2; + + /* css hack for IE */ + position: absolute; + bottom: auto; + top: expression((parseInt(document.documentElement.clientHeight)+parseInt(document.documentElement.scrollTop)-42)+'px'); + width: expression(parseInt(document.documentElement.clientWidth)+'px'); +} + +#taskbar +{ + margin: 0px auto; + width: 400px; + height: 34px; + padding: 3px; + text-align: center; + border: 1px solid #cccccc; +} + +#taskbar a +{ + padding-right: 10px; +} + + +#message +{ + position: absolute; + display: none; + top: 0px; + left: 200px; + right: 200px; + z-index: 5000; +} + +#message div +{ + width: 400px; + margin: 0px auto; + height: 22px; + min-height: 22px; + padding: 8px 10px 8px 46px; +} + +#message div.notice, +#remote-objects-message +{ + background: url(images/display/info.png) 6px 3px no-repeat; + background-color: #F7FDCB; + border: 1px solid #C2D071; +} + +#message div.error, +#message div.warning +{ + background: url(images/display/warning.png) 6px 3px no-repeat; + background-color: #EF9398; + border: 1px solid #DC5757; +} + +#message div.confirmation +{ + background: url(images/display/confirm.png) 6px 3px no-repeat; + background-color: #A6EF7B; + border: 1px solid #76C83F; +} + +#message div.loading +{ + background: url(images/display/loading.gif) 6px 3px no-repeat; + background-color: #EFEFEF; + border: 1px solid #CCCCCC; +} + + +/***** common table settings ******/ + +table.records-table thead tr td +{ + height: 20px; + padding: 0px 4px 0px 4px; + vertical-align: middle; + border-bottom: 1px solid #999999; + color: #333333; + background-color: #EBEBEB; + background-image: url(images/listheader_aqua.gif); + font-size: 11px; + font-weight: bold; +} + +table.records-table tbody tr td +{ + height: 16px; + padding: 2px 4px 2px 4px; + font-size: 11px; + white-space: nowrap; + border-bottom: 1px solid #EBEBEB; + overflow: hidden; + text-align: left; +} + +table.records-table tr +{ + background-color: #FFFFFF; +} + +table.records-table tr.selected td +{ + font-weight: bold; + color: #FFFFFF; + background-color: #CC3333; +} + + + +/***** roundcube webmail pre-defined classes *****/ + +a.rcmContactAddress +{ + text-decoration: none; +} + +a.rcmContactAddress:hover +{ + text-decoration: underline; +} + +#rcmKSearchpane +{ + background-color: #F9F9F9; + border: 1px solid #CCCCCC; +} + +#rcmKSearchpane ul +{ + margin: 0px; + padding: 2px; + list-style-image: none; + list-style-type: none; +} + +#rcmKSearchpane ul li +{ + height: 16px; + font-size: 11px; + padding-left: 8px; + padding-top: 2px; + padding-right: 8px; + white-space: nowrap; +} + +#rcmKSearchpane ul li.selected +{ + color: #ffffff; + background-color: #CC3333; +} + diff --git a/skins/default/images/blank.gif b/skins/default/images/blank.gif new file mode 100644 index 0000000000000000000000000000000000000000..ea83374c17e3cf315d0ecaccc57f682fe3012fb7 GIT binary patch literal 56 zcmZ?wbhEHb6k-r!XkcJCaNqy~1B2pE7Dgb&paUX6G7e1qE&VG`zvW*%XUnbb&G+Vr HGgt!vX#5YS literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/add_act.png b/skins/default/images/buttons/add_act.png new file mode 100644 index 0000000000000000000000000000000000000000..0454ff8561c788659a1ca26a067ed659f14fb478 GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6K!2~4jTQ9i)DVB6cUq=RpYd5a=M;HP5k|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5Xc6z!vhE&{2nqyh4#(b1Pp&_Ed zLQ}I-Ncq{>+3W%iK0H?#7#Lk-gBh4Qtd=pb2qXqCI>@kJs)1oqUo=dNTdqIhsb1_Z zkzhjyhDM*CKRzl0!NhA!qK9uf#Qy*PpWTRoiDP;6GXME}i79DmPCEp6BN!bR0@Y)H zMzB6INScxq$|lIdp>Sx~nHh%73s@N#S&UjcJA>*OSp-Ub7&#P#4zcnxa41aBJUvZ! f@dc3v24)7~sq$rPUDGcBJ;C7V>gTe~DWM4fc0pJ9 literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/add_contact_act.png b/skins/default/images/buttons/add_contact_act.png new file mode 100644 index 0000000000000000000000000000000000000000..994242c0a280930c35ee4ff855a3a2654f0283d2 GIT binary patch literal 1626 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 literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/addressbook.png b/skins/default/images/buttons/addressbook.png new file mode 100644 index 0000000000000000000000000000000000000000..359f33e0f3945fe22838cd99c3ef9c55920ca7c6 GIT binary patch literal 1768 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

5MTh&NkcRp Sxxq*P0000osD`|0Fe^{CTVGDYy|}cEI~m*MnJ>$fDYjY#y=?7{{S6x5?L`Y1Rftec{~*f)1Q1CM0LGzpN=gdTg9i^l>`y?zB`+_}0!r<` zxc>?aiTl8y)&i>Gg6RR~GBZCvKZaAMPJyD}A-b6W0mMW?+$*}cxJZkLh%g*Idi1}z zxcIXVA3lhytE)2rea)b)t$pF-$&-cw0Rc8ZOCvx&2V!+MH#bo(E-p}3{0DTvd319D z0*Hl3%b9_Ni>0rxFUWERPEO9}&z?P#w6U>axP19C!>d=XUfSB)eti7+v8BDeJ&4Z& zjBnY$fB$L#%LRtLd-sCMgzLb>`5xVDfB+&k1atxe19^a@8^gng5B~sD{s*Ap{Jgxp zphWiH%F61@v17-Kfx*vo_wHR#uz%p=;}ZZz58KC&9~ri7+x7z(Wv8(j3=lv}MEIVA zpP%0ln2;ENshL4RK>_IbXNu0w&J2eR9by2c`g=g1^UKM}i3Pa^FEkx2UKn=Z_yh7`AWU z{>#kF?EI};w+y|!yco`$Im5up%K8H6AaMf&1IFvuuQQxId-e@5=x^XM93X(02xL1k zRUiOnJ%$4Z4lsy`i9LMu=#jLEi3!8jty>uc1qCl(ym(O^m^itCIgH`jwQGNYiSq@J zEhZx)0}6Uj%0GqA4uAk+B9!fdgM%4?mN4A8bLYjockg&rR8*Kj*$`;iM__sI5Ev?& z#>U3rgr=mV^bjbg?BL+Q08A60^zsns`zQG900;H2Z;mo{&8Sg{sEZ!89-43Dqhc@ zKmWtX$mk9*bfkf4fML&`Js|yOK-DlY4gd%s7CZ@%0Tcqr0OSy0+E@!r1G2!vNE}$i zegr1KC&2i21SVFdD_5>C+`D)0&6+i9ZV_9=0|XFO2LQ9qJ78XB0M>M%tR@i_7RC;1 z(?Naq0E)qNgqD_;B(ROZ0JQi&FyS2`rGf(pAgoaUOmJ_33FU; zfW@#Wun^(_m5S%iodadV6Qs6o00Ibas~A|nI{~9X1ys-g%K&g;18f6;S~d*8G{6Az zIWUUAr6e#B9s;%jZ;h(W={(!O|1E_8Q zm59Kc@)zi!OVg)MKTF6mpk4pa#Q*{b!vRpsK~cjDODDjZP)tfnN(0yg69f939h5tO zx#SnHt^XQWE?fbY`EQ8uET}yBgYF1`0Kyjnj8Kdsg+}A_EEf7dwh#aaAiQaS5!95$ sB1~lT{znUbtQG+T5aU31&jA7q06b6X59F->7ytkO07*qoM6N<$f__K(XaE2J literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/back_act.png b/skins/default/images/buttons/back_act.png new file mode 100644 index 0000000000000000000000000000000000000000..d5352b5b30c9103ac601735fb8368ece2aac9d2d GIT binary patch literal 1321 zcmV+^1=jkBP)!U^jzHLb`DCk6&a@&ghefJh1f zW;P}+y>Q9-7P)d^t^vjjN&+$v2@1**fB+)e0lX5NhIZA;Yc(uH6rJ5H7=Hfw%W&nz zT?Q=)MTYP;h00Icb0h~PS z5_++cD=kyx>|A_}7#P_Z86JOp4o+ksa~T*>{f6NDNAfU`%>?y0R2(Gy``=F>`G)~L zwEzSViUTZ*WKSs@3duVASu(u;@t)!9mmdi0utpVB{6Cfu{||EnLfubbiuv~!)dYY5 zRFY8+fG`X~Y4rYw^^w|fDZnLCE+0g8&p(-cz=HX24x!*01!YZ4*34{*E1kxq2VUc_wmJ# zToX507FktkhEHF=fHnUDTKfIlPllgAe!@cn1Hf|#Qj`Ii%&bfdzkmHhb1VY`KmcLQ z1vhrRC=yZP+x`8+uLZJtZ^bmN#Th<*`UVWXpYXiR$N;H=1f)4pJ^UXng(C4kzx>AV z@5jI2$aVn)5YB?=&Am_CIk?z#-gtdm@$|+=Ck;m-1|DG!hVLJN`a#hE4pv5n-{1c- z9GXpBZ47ew>&sskBZ~n95Z;pT$G2avft0hXnPC0*cfTrSjQQDRb@>>6ffDL(kk|eJ z9q@kKd9U-+lb`#4yZu}B=GIp^O4^kG z0R%2!U>KTVV3-LBGeaEL{fmCO!Q8ORSvfB+&X1X$RZ zSaicB9V~KWlwAFd8I%QOftCZyk^le5b^t&C5$ymz2~H8)Y9&_<3o%}2H*h89)FLHkxkc^wJDFYWTH^Z|JuNi*-{R_4e6#UwvN(|GcY+yh(h7l+U zF_#g}2gekUy1)Cw)vKGHABCv}2q2sxASA~vX;ZG?sADhA_92^8tpM%AKp~=F^AkQz!z{LC?CCdN=5Q+mhdDyx1 zVkMoeQe`Eby^R_dlQq82(^* z79fC79AHr>8=zt&#N*;`#qjR?JBF`ce=sooNAfb5W`uYN76h=!$4E-Z8X=ND8U8Z- z|BISp0Rm7_MkxTpFbI{x?tj*Plrl7-ma@?tKzT_t1)%w(%$cAB(fq=h3&yFJ?TVssXOC4f*IaBRZkb^5V?-8TO|BIe+w!@$eI!SMOVH>d+3 z7J`EO??0d;fBt0n`TaML{=x9~??1GZfyRa;4u;>qegQS31{FX6p*Z0Cm!IE&)CLV# zam!CHercPyN;Ao-$}oKT_66+2pFe&u{P^~Z;n&Zfh=BeNiEo&N5I!_&zzO6Zm}X{S z0y^Ly(DA4a00l^Db4FW(uyef)_M5g?-kq&UGo z{Ew6{k(0oGq;l%>%Wn+-e*Qx#w*dkOXF2ft-lxYLT&%0#d4G3#a^s_vrlSx8k1z+r zkB@&C{sGNkgc|$%`(K7ba~|O<>rhhY%Zp!cBg+B=5ZKfnG1CQ^t;e*XX_us{D9j!k?pi=3huAb^Of3m%_(e->C7J^l6dkMsK{ z-?`PSgurq7=jVThKR^BhLxlXw2q1unt_?rE`2K>0gL#dbi-`00cYkE$O!*mvBshSM z_)AG`%m5HTB((?r`~a254BMm(1q^h}l{GInez^bR(XVg+et_f|i3G@Y z0t66BdjKlQ2z3}EQa)m2z~1aY7W+%2r$H9}`46=iAb?n~7|4ibI1?5z1{~^eISv{8 zgE|)M0Du5u!6FIM{1=PEaD~c$taUAp5crQ2>;M78NNn#IDe4$;H0{XB3IGAbIMCg5 bfB*vkg=@z5^{mw100000NkvXXu0mjf2}D=R literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/bg.gif b/skins/default/images/buttons/bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2191c910c9d776ec65e1c97372183be4899ab2d GIT binary patch literal 211 zcmZ?wbhEHbecI)FJJ!n`Sai3f6t#kfBW{`pWh(x?Ai0bfB*gb`SZn# zm+#)bd;RM5moHyFe*F0D+qWlAp8o&;pMf}__>%>!PzOYU>||gKSfJ9Ek~uG9)w-P5 z^E_qvn{CwH=SjEilkZ9hP!Qk~ov@^6XNkr9fEUSLYr`ZXau!awY9y6lz#t%IE|yWE aFdk3Dtg-?uX`SOWmN(^-fB literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/compose_act.png b/skins/default/images/buttons/compose_act.png new file mode 100644 index 0000000000000000000000000000000000000000..c7e2d61d5af544d6afcdd231e0c5bacbcb3c4066 GIT binary patch literal 1650 zcmV-&295cNP)nWHs~aGI zFdXpWJN5xt4L|^~;L`m5;}-@-Mn(oE zkoy^#A#5flaA<(y?H|a~fB!Rp;s1XO%*@Ov`nfsT;Finq@$J`=krCK?3R2_SU<0fgaz ze^7&f0l@J1@gs&WU%x=C2U`B+%U47c{70ldZZ2*HO)V{kfB*i1+{Ezk;RA*_Q(75H zVl^1{Up~zst6;~l{>&K$f1v8~uU>rsriTMC-2efE;eh`zlYzl5CohlWd#I~0QvQFi zYd{c`M(*9Y$1r|`K7)WFH-oy?4~E*tsSJD~rVPzHc6@mC?VID>yLaJf03d+y zga9MMV_;l=`SJzqdstqC6&xT{pwMA}m83v{=P#Z!9Nx2rp*_zSZ27kj&loa31%xQ1rB*GZXSlaK+BKrS%=l~(zzcP@L3K500D$E3P3hJ zc?1gq28OS|_y)=R`SX|I-`_tBfB*htc=_@r!|{Wg7&@?6UbFN&gQBi8!^Yjc7x0yq z00D$E5rTXU3IRr_Z-4&!$?)sfZ+Mz}@Zdhf=C$*%T3)^68$)B)0)|y<*AXnP0Ro5# zS2p|y^zT1ldiV~kP(FS71guzoLedA&fe-HAV^}o1o1rz^0Mqit-x!K&CNpRO%Z2~{ z2)8u=0tibKKtka6uU`yzfF&8Im<1I;up;2aix&(BcVSO(Aj@+q`WRGH)lkgB2LJ*H zXCnOi^(%vhAF#P`g3tS}s|Nn>K`;YGg9RLtOSaQLCaCU=Lv5e5*KY8*LgS~?R*z&hm zjx$`m{hVRK<{u2D<+Tg~0s`RZ0XZI2b#roXFtD(&GO)0+5_AAS0AY=S|NkM`5mX<5 z90GF0zI}Tbq=lIoR^GeHaQNy=1|AVPpykyJA|j#;zkt4G1zN_&#s;*Qg@K2gi$PFO z5Gck*&;bAegtaLC|NlP}LxLVu=^Q_Hl)=Ezh=JeOm?16C2<$sHHlQzAK$bFtEd~WW z$k8B&fLciZiO2;20fZ$DKrH?btz;nV{|pNkFJ)k7X9vddAFxFr3z?ZA7Q%{VmNs$o~v~A)dh7EC&c679`6-Y|bCwe}LP%{gM#225aSF1fB<4db`&%;&@lrR w3mNfr%>Edmz$jE5d zxpU{gB@u3Kad0d!{b0!Rt|2) zr%xXlgt@tW>jDGW||wmi&w66)6~>ld;R)#a7X|I5N-#64O0MH3WJc~U|^7w zlS6U<13VOv!JRvI81CJ^&EOXn#Wm#<$S)&nj7^5rWc3jQNfA2$~_gQk`i!@qxjL2hDr`0xS4oGGmg zC9xU|`!AnnkX5i_SbydWgFjI9`B$%g0n@`Xm~Mao!f?QUn90Ckmy?%A@;%g57%Bfh z*fk&sN+b8~++&zMt(BoAOP@hNk()tX>jy(^<5UJd5mScd9Xo!#`u1(}-Me?;X#gOA z@Pq&(!((7vfBEtS?0Z;VgcTehRiMyefR&^`f#)xtGaTNthM_&r7;O2s56>7roIk-} zr^&$3x$Y>2($%-Z_u z*UOhbF)RlGfB?c01<()x!beXY14H05n8$=xAW2J019Qn!up{o=z0GiF=W48$7tVb3 z>&7GOmV*F50AV@+mYShijtOQfDg_RCE^Z!%yFkm2?pcS`^3u5<81PvR0ssMoGYUX9 zJ$VER0S1Pz!1xBq{Q2{j;osjs41fRrV|e-UCByN9n;1HIcA zmH+{SGZBJ(4hjKAsBeG%`pNL?*Kc^5d+^{s!{)W~uv%WdV=q?8oYVu9G&)5J!0O3r8 zAR1)(|Np=Y$p{hKx^)XfMMf}#x{(IM+O-=PtOQSh6A0MyvR(!i6&0|r|NQ>V@Z-l1 zhMzxv5_AAS0O8Jtpo#`)IRoQ=u#Z5Fd35h4gGs&@!NJ;n1z9dn~OnE zP!K4_M$iEO0fe0Ha4IySwNODgDnOH zJ;>1@hk#m0|B1*200D$04L~gZ53OV%?Eef47cXUCXJ-e-@gJ~7APbq9Ar``lX5~1T&nIlMBuU#Vx9X8Q>Pd9Q_aK31Z3tfB?d9z+X@l03ip^x9AlR z*5>(tq!u}p!3uWdf3R7E06+k-AT>fk#WHhhdKTCqaWPTK+T{O1{emALb3v~8`yWTC z1Q0;TApmMubKSmmlOZc7hbsMocW=QJAr}yTgSB7K0YCsT!r~7W0#M8dt*DS`WQ-mm z|FK|@g?~XcIKB`72p~rEl*-7+$cQ7x8Ho>kD*yx#<3M-M0RjvFl7!{0t((nu P00000NkvXXu0mjfYcJIL literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/contacts_act.png b/skins/default/images/buttons/contacts_act.png new file mode 100644 index 0000000000000000000000000000000000000000..9876128175a7a9a72b444ea723fec92494462953 GIT binary patch literal 1742 zcmV;<1~K`GP)PiMKZZ3*^cyiWyhFf>C&;P3CR2&C-T zm>C)N?B2;>sISAo$jHbL7#K*F19%l4GpMslGUy0!JYDnfs581eKmcJ2fs*y>*JnL= z@BorXn3x#Wt>4J-;nP=e=>BJf2J3$a0pf$$U<#O}8KHcTv>-nhNCn*B+n=6sqFV+K zK-e6x0q9%7fBzXGxwtqPSeTg@JiYuFV8z9kPoEerT)4nsXk^5|&CLz66=EsaBCsn^ zQwV`_1|Wbi9I$cY#@#?_x0R!Nq?N4$gTJ>s!@G}Pp_VW(Oq({DVaN9E3?80d4CNJ- z42O>#Vc554H^Ybb@8L;MPF9wosH68wQ5YOoBSB zY=Z3Q_5cJB&RoFC$jor})=h?W>(()R{r-!=+sBvT=&_>=ZOx5fb!DZ63{^Gt3|3aw zC?&yvw7B2-`wPR%Ki?SEKYH@?+J~=#==K2w5K*~c?YfQNRNh!$%kby-Z?O2cZ{Haj z>uMPmE?LU(`sFKND7;}15)olw1jdCJFzO^EBq8c}Z!ny_bc`WTeEP2^?=NGdNPqys znG60iFhz2(voWx;G6NHwFT;Oew%D2RLjg)dQVatF7Y`2u z6AK#yGcy~|<&6K(EdvN3oVmck!!J@tPm3WYGL+%nhtFUe85tQ-N?t|=R6a2EG5r1i z514lTGr+2O9v)r>PEJsEX8Xm&$n*!@K7atinFzUoE*B6IW{{DQVPIl@&2Z=TT|^9n z6X<_11_lk#(!byk`VT9Cpy1yh1%_{5zJN7+XJyr4X5+(1ga84A(*cZ3%nbkk{9)kZ z<74;@%nZW7`2G9$FVIq;g@67aQa$5;XnJF0Kq?}^p(7A-av~P!CCV^1B3=6q+%Hy3jh9qQZj?A zlK=Y;@2+9gYybg7R4!P$Y$e>lFJC@`^S++G0Rs=PDE<$t6L6HipipCC#NF%w2q3(< zfQ^-fft{TdSopZW%lJ97XEE#r7QN0ct_=AFMGPlT9A`Lq@BqVy4Lw0sP zk^^uTg#ZDBCl~lfYRStm_jlgB6el@vmOJ%<%5*ThvAo z5ZKzfQ#0faLbFtKnjym|c+oC{vPe#hYI?!nO2 z-pcSBS`>f({+*$-qm5zO^jQpVU%zH}`~EG1FtFSJxj|S<ElV3=#r=|AJj4ZlnGF z>w}jVxd0%5h{^?vmn;MOZq3>aDD^um$BT)JL31Y~JPUwA3>*Ug|Dl$kXaFF9FdP63 zx{Uz=0YZ$-ED_AWI+>G$ogpM7ltEcRmaH}*sNe$SLQqM`#KQ6k=orTTNZm1j0AfV$ zngQiN4g$5?*qnWW-$;uJ0fX=#IF5ydMWHnfl1~|ti>CjGt_E5of)4Cg*xxyd2S zcj@kueaWC01lkKuU;qKcf@C>J3kMK`>QOc>ZeE7>-~WOeCX7HYd;_Kf25^Iv5kiA& zK1ewT^2GoD|G-)B|G$4wv47yoi3ywq85y2#KNAAA3S|B>pmpDX`u+g~5Y7;QIu3@J zp)?be%>+#f*dq5I6#s?Nf1vCiQ1&n65C8}uM)ck>G$hb50~QN$rL6yG?Egp(`wvNG k2ulG1h;g91=Kui)0Ep#ybxPu^*#H0l07*qoM6N<$f?pmMEC2ui literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/contacts_pas.png b/skins/default/images/buttons/contacts_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..25dfd8c32d9c2cece0da2c0f115223390003b319 GIT binary patch literal 1721 zcmV;q21fabP)~jDXZKD9Lwy|vMn*=4z`#JV9Kfsam_eOYl0ip+g8$jQ3{QJ+K%f-dXz{1SL;OXVZ04pxOeEP(2;lc$5Ln9*wZf7I}(2-0ab^jURnE_nV;&A~$0O5216HwE?e}AE- zFaiw+ne(5)-ocS!^{SN&_V$h-VTQ|>E-}1)^BTpUAiEu%oFP&6`ai>$Hw+A)nFPgH z*#t4{0|+3Txqy|Cnc?oOn+)sLtz-E5{TG9`k1xZ~V@DazS^yKrk4_`UZ?E?rPqH@97bsNE{ys^HP;m_~iVDWF?zB4q| z)iNwxvXtTV%U8fqc*7thBErB3j0-Vf)JaH4Le%lzU^si}7(<}=^uJHuU&gQuAb@b@ zg8vLmx*Y6m46Llozy#;Z@E@2hcI@2Cz=%}ffzmsODgc)RHWEhy3Uo+gfeHRhK-~{>~ zjDbM|wDd1Hg#N=yASn3vM}gtnmoH!q-&tA3nA!L+>;niOoDN`QVrKaN=MMuPA0NYS zVBiS@l}@b1GW1~)ekq)Y}5Z=l7D;H>$d0YZZjQn3sUg@1oQDVaf5$^ZL@ zch@kAVt@c5Di_Kw3tcAv-%C$pN^F zLVy6mlMDQHwd7?OaxzjG9zT8oO5ot2RZd^!0Rt`SrEc;2O`|%mSJM z7*Vn*EY1A=`wv`xT>o41`7P6Jj9dT^Ksa*&6AK5!o7XSFx!~37cMPuX9t>UWtqi}R zMe+CV-x)eP+8CxypT+R@^=pQ=@82>A1IrDN8-ztf8N?;TAR+MgFW5!mHrn66K6r_d z3jhL$s9dmk$uh9-)~wxtQoqA;yqLHcGvj8Z>z#;JeA8HAT1^@yG!vVmcyAco& zz{$wWqQeZVlQ}uq8A3ur8I%=d$!ZgV3NBDC1eKIbEG$2Pj$!`_Eo6ocnm?4Tmt_%ezbV zZ2}7Y2HFd*7XSi?1<7(oC?Ax+n7O!l8Qy>Y3vQTz-1QBZ4j8}Scxj+B@G2D3knBmF$_rLi$Ij?eZ za~H%OI&_d2a{&T~paZ5G81OJKGH(0&>zB2knHiIuh6V#D*cd;5W&ni%2!l-c&(F{B z7iiYQn>QIYpFH`Go1Og_D>t`S(xF42@tF@0KzJRnz{*PZ{ijcR3}j`+EF2sdnBKo< zV0iY7;m4OR4DWyb1Y69=$Ov|X5IZ{q2QM$fe+dbO|3X3x#}6D}xbXP#DV7`Tg?As3?E_)go@hfX;GW@@Oo#EYw4-7Yf_zM%$F98*mr)<2uKS64L zfBC}k;r4AQ9tH+BO<+g}3JNkX07L5DjT;Qx&Yt}!A}p*Mf8@wxZ1w;I5Y9yS<;#~t zP8u5g$|@=hf6ts@xc2TH!%Jr7FN$etN1YN9K=Jzkh`&OWa|5yRt(h~OFV36i-~db; z|IeOfP}0+5aQga{|LEPjM}YG3*z5raAgm!U-`u>9=g*%)e_vmQe-|z=oPYkD;j66d zbK3t{U<`~FCIbV8jhi&yVxW?n=!RTRNs+vJ z{rUw@K|wJFnB_qHXm0-aG0=?vw{9`00dvU9H*eg~%>W1>%nl z9Q(vWL+?Gif1lwgFdh8@X3y_`{-~jw0}wzM4*2oo2Nx?a$QZwVW%vq=Lva(6w?N@5 z$ZGCXRY~7FcI=V|7ncw`*nyVs{`&R3ioLzAYIpZjpt1`bY-~%eegDqz7KqvT_!xfw z|1W@UA3y+MWW!&7{xCDLu>s51KMcQshH~=qf)dR;nEbukTA4e0_MCV7{afhIw{LKL zTfcvQDW|Qir_$E;3M%x8OHS_WFD52%=&*2bFaRTo9o;^F0K#wpJ3IT||9}629l-|7 z&)>g%;R2;zpw#+%wD^^xH z29U3S_&*Tu`}5}k$a1@zH{YWf#eIM4Ruev;Cs=`I{RJjQPF7ZQH4Fd&gy8@lUf##A z9zA0C2TEAL3g_&SC9+=+9#p*a@#8srPEG{|P$>tseE;v?4|D|tjIdY^0wQm3-*y!N zg(R>n`1tlM0~Z_HZFEHd0fgZIW=_t{7tftzcqJ^%zzdAG@9*B(tcZ=>?8L>TzznpU z35pN@`t{IIM#dP2<@`5#d(A$-eQP5NG=m-JfXjF9GH|i8Z$?)L5I`6XxOMbs^~nz( zK79seL2h|@1`}>>W-B%}DMp}=VfgTm9}o4UrH!o4oOy@Ea-Og6-sv2lGNnU-ot+tE z#!sMG_db34^!3%NUUbC(0fgaz+V9_g3-a(x-go>s1DCco12?b$0r?z;kNy4o#Kh3h z6pQ5`vt-`gxM98C+IlYE-@kIoz-k#}2FNTCUf#(dv(fDX2q2u*ahtUC9ZN+;WeuPK z-+>1F|NWccI4~h8n3ycES-*ZZP{~K63W*IA><7ccWA2|m9WMIspO6MH-*Z`7GF-cS znc?Kahj*)$A0U8;ZWT}0*0%ck z^=m({Rje<=%ge4NDGByDxCRB9aR(SWk3N0+$;ZKQk(-;lF!SowW5k#X5I|TR0BmT2 z%4~LM;$lU@9H1gLLR#8Yh?&_EShh1mlmFj$fBzm|@$~6#P%9mZK`H(_lm;c%pFq2Q zqT2-!K)4*h4Q=Of0Wl}kVwi*2pmhi{Qgr|_BkQtX#oKyEm>Ix7G`F!+@F8{7;Zd%%<$y>`+xkLobNfg zxsSyjI`o_va{&T~paZ5G7_c%hGJ1af^-J8(%#2Y^LxTYnY>b~jGk`(>gh3|!=jUhm z3pDHD&6^CHPoDhG&CdRkm79Be(xF4Y@tF@0KzJRnz{*PK{ijdf2C}l877h*!Oz+<_ zFg$z4@Z-xDhW9^zf-PobWCS}xh@G8*gO``#zk~$Ce<2};;|C5fTzLHWyO4mu*0{rm z-{GV7`R~&)W|lLOhL(*pxLj8UA0t&hYNT2ZozK{Dq0>pMZ+WS2kYWzaX{0 zzkFf-aQikl4+8^}CNLxf1qB%xfFX77#tnvTXV3l;5f)w(f8@v)Z1w;I5Y9yS<;xde zCk+iYWfc{Mzh}-cTzmJ9;UzQkZ^g8&YLIY08AVI z&z@ya($iyb`udga=-s=1K>20Z>;VWMtRXPp+}x7q&mUcXUtflQ7cMZIfBu}|tE}ud z+XV~mu=DVM64zrO{)epRerqew^}~mQ+*nvRKxTq5Fj|-l3>Y?U-pufwlk-aK;lsz! z?E(lOjB;SPpC9x4w{JB)?CcmA@84&*|LPUPCjo(<_RE&t1X_LrsN^BK<=0bExUO#7 z7U&MN9Oxqk82$xJD-1w0JZxaS;HaNWOlEyPPefRhoJ9bx#u-@m_(zI_We17wyeCnw9_ z&z}v@^#cSDh6Dcn{3)leq{P4k^!X#84@503zX-|7z6DCXMOS+xH<#47{m&nMbaMa#2*UwCe*9oz1qK--FzCPj`NJS?V)6qhjFOM!|34eLeE}V7K4D+5dd|2G_Us`}gm1+S+SW z+Sn1KZt zx_tlvgb@W?+}wZv0E3Kyhlc@J7BD=VH0c*e{E)gj`>88e0n|`daz3AL4f1!?b|XUppcZ7X7~uql3Z+T zAJG*71Q3P;m^nEgUOab>;gzs311~V%zQ21Xu_89s!-3dqihX|jRzenN20PFJm+#(X;9_Tgh^`PIfH2a)t)oXz|Ka7;RQ>UTjay!x!Q{~+ zMs`LdYBzma~3+_fF{elqqHk?CgvnGkyZI^Sw`>ezAY~atU2A zKmcKcK<)SM{{(q>uI@X2oPkSQn}M4b6za@yeC+SvuO^0u>#$f3N|W60Zrl)GZ*6VI z_xCT4GO$_(nE^6OgqQa!$ZT}`00IbWo3P;Cz0+@h{`_M=N z@b|?FhTjh!Fns;=iQzpki~fV^Wdi1PK^7JUZeVH0s-VEY3@mm}9z4i!;ra9L;sOF& z(yv{6kIN2#03z5XoTjhO`t8#v_n*IhNqXq%G0Li|gNxq3z-+|;(+hL}GcebHvgTu8 zn{daaOaIx~*q(Fo@$JmIcoA=#5FmhvZWT}0))xQz^(&}VEG)yz%d93T3HCX-1_hdN z2N*h!K7IPj$HDQIo16Q1=GCh&i7^)-fUr6M*w6%(+04*Hij2Wx5z^AqLd?wK|DdHY zP~!i)zkgq@c>44yw6XFZO8A%dqiKRrHHcm8OZ=A zDNT^f+;*5ROpZzBC;j{Az2q+d0DQHL%Zbey7a$lG*ahPyfIvXw0aTdq4v+v2=^#KH zlK2BmNq?3^v0;OFpxC$IL|h)vq1&a8VQ%KUoSVGcHZytmyT8lJ%c00f@-20SRmtw? z=!Wdf%tQE$kSb}Xd!#$0DJfq#9c#9umJz;I795zKnNc%cT#Dm#m%}P(r`B$*u@UiF z6k9LbjfkB|yA=d@%X4ukNnzL;WRHdo=mA`JiAL^ycpN)>)=ri-)ggrv4f^+vW20gW zwP@kgf6zS-lO1TwV#Vi*WSrllN@tdS6++(&VxaRj6a1kwY>p+XlFo!|i*zl`%`|=% zo=A-#BL-d3%!67VC_!0p{DjmU#8nb_r?iWUDLHMX&x@}A;y}=|Q%E7(l4bge4wfOu zz?)}H*fQ^~_Bp~m4U(C5V4guMok2|>c_6bGAYX22oapFR7|+RP(Aqc9h15vs{B^m| zcU?MuQ$?yDw0-+_cAjy;vIhs?h}rPS+!d@UDUSXyUOA}M2XfgZq?tgb_mCzKL)pj@ zr9MrWtJb1ZHnLY(fJceRq)wlI;wC%!RR9Y?=PPCg9i#hkPw>x}4&~C+(B45v9+2U| zh^$7lu?vwYm3Kc4QHkx(iC>&XH5V8R?v<|_JFB5P2QNYLB?E22shjqh(-zd_548n2+?HnoyWY`HU@8rctop3=M}XV~ixgLKG0GjUBZzxM z?akgFLyoeD_FUAP*#QxGZKHd9Qa3goXX1k zg}3U;NrzREoM!9U`R(~c#rIGQaE#Bq?Hyr_Vs&L(s5PO74~DeAb<#9F+sRu$8uQzt z5yJ;eKANW&5l^)johjO*{%?OXXXErJ!MZeyx1qRuILj#p&TL-w9fg?$B1Ytm%X#YK zPAs}u<-VzIjixDc(D`=8=T5sw*3OFht4g}B^hOf|1`DiL$4_>TpI47&uJqUeGjz7$ zSaOoUfG&XzTBG%sAQesrkwhMXoq*21W5*x2w<~Ee5wj0K;ijY z7`?hf`B6tn^>fwbf#V3FL`m>MfmvbWl!xeSn(+4Bn$r60!7U_jlD*6nnC;ob`Yq@i zrnpl|hepq#i6v1J_qFKT{jvnO3vR`8F}!is$73C0M9)Y|t1Z{!0o*ZHEyl{nka?f3 zor*NhxdPA+U!vr!QLkfav^G^`4iQF0|Vd(u;T!$=jX zCs5;*iEmh_J2|s7KL}MgwhMFe^lPX}evarByQ@~XS-MVzSfp%(fpt%OBNGB}2f%qR zvbf0EmHN?b=x;2COPj>_!ti@zolU~oOxd&1m!5_uBU{tfD&dDsu}Rs=7b@gokE(MM z**y;PKoAs+u~(IeqBj|rLAX%ooPQCiaQL&zKc5#n2GR?HE(2!)u?g$bTF}H(Qdu5m zvPlKla%z|Iy^_BE`BS!gnoej)@IJ#oFuI0hGqn=Zly^c`zX*cEfbF}YO*oMuuwk#_ zMz==QuYKj?u_~RdKD0vu1le&h+LYMzfx@tOFPTK4GNo7{SULLv<2h74kc5z3_ljVGQyP36tz*|e-;N~qR`!3Ev? z&vHmF<>)PFB22M&ITtZfHr8-@JY4tV^82mJtry>8G^8+_kl&+H^=>3Nn@~lgPvsTp>t-k(Z9aqv8eQZmcjetXs@T0z*R$|kSfJN6KAk;ZD$Kn6`No4IyIx~Cp?^Uh_olT8L<*at|F_hv{g_}E6 zX`vJc4};yqVr@eqS1rE%g113j^w)i?k)LNiONHKbd)EGOXJO_|u^#S{{9;%&}`{Q@VRe$w#8V^=5xx{x#B`7u&yX5HLi=kL>zbW`e0rOk3Cgz){!Vvb*M1pGH z{AleVQlosbm11YKqQd1vz3cnEF2EYnNqbs~Y&bI7+m`U3`5|2MM4&55xq`vZ0wuIq zdOkRA0-3-M-=^XL2#=$V2(bsLseizS0voB}R-9Pw)u^@Vvg)^*c&MHtq#t)*&SGDU z`?V@31f(a-Nxd2lw)&$}`F@jKn+7WY0ps;MKUjhTcCpC0hZ%0Y=Dz^g781q19>gpB EA0x!!y#N3J literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/download_pas.png b/skins/default/images/buttons/download_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..fb39db5ddd9cb6228a4f61f0c09f9c3889c55eb7 GIT binary patch literal 2107 zcmW+%dsLDM7XNq%h$xt@fjJ{)X;Z0yjj5=BnrUllWv-PKpkQ0MqL^c*@}UIzn9(!k zWNs?$j;?je%pO{);6OfOw9RInYJ5~a)3j1SUfb(rMn#72w;=h8VNez?%*|c405X-emjwX7jSR;o(kwA4Ygb~{fpmV>cbrTfz)DHy z^2kwXoK)U^9w+5&MjtN-0MMGKa8`WIORf=u7%C<=7N7y-5J(5e zU~e`kcXvNBAoKStJ($OKR(tliSdv*&^P?TFbfX>Ty35MSaM972)~-zKg@m{`|F=_9 z*>=5?Y!vn`Zx7g*F^!J-&GIY_^t1byo%D)cg`sXe;dRLtN;UmL+ z{d18ADnX85?x?`;|5O}rnSkJ)89+&UdGFq(OODd?u}&%&Ix(gYv5!M0!}_PF^Zh;L zuB7aRmrn$<&q$~=`ey0$?OJMNNfb3HL?C0u{)*hJX7WKwG_HHFzrWh*t^*m23mvyq z;nGLjIXeBywj^9i00wjcgp$_QovK$0v81fMFNke*RNpOow)(bhK{#MDLO$xwU9^*-#mS9mw>{{oihhq zxyxFGBMGlz(4j>0<=uMU%uE5HGN&DzN}IV+Ov{^kn>=)xkX&(zojmjRsAL^hgJrPx zVYB9A<;exGub>SV4uKDjcAASg+Oj805;OrUZaD-apkU48jiZp&WB%m=yJVrTVZ$!8 zeYnY}8pAg8y!|ycI@^b`Z}m}i;lf+Nq#ERlIO=PD@(8~0%z?;*V%zy2d0=T7@m{RG z&x6py_Tk;YjXpA(NkkT&dL~$c7Kg*4BDdX&J5|=&QE^52$$IJ^g?S8-~rN7zq@!-!E=L8OjZ6R^o|u`&{N>w3q?5x|W;J~n-vL6XRw%(6fvKVx>D zEv-4{*H!t~Z;ELG3e1*g(kQKeKF{+ft`ic@Un{=vQ*?WJE4v!>f8$wU9_UpsnLgv= zCRWf5c4TnePS>L}PA`;?ou)C5uvi+<(a0>P?(l5lv}GPHWrfVp!}6Kb*Bi6>38-vT zf^^MPS)p#Pubb$mIib?ElQ@RhuP7fvU&;~J>Ywy3+0FobzDFAZfMbr0np0Esh7UbH z&69HV=dVtD#*@u_ONOzD_Xvh>~%i}K)m?W(RL1F2jfUZ%J|{9mWvb1?LN4RvA=Sccv^G=f=>xvS>7&9_6?!sAe;C(rVn`4 ze-=;U2J1xp9OHPf>h0r2P-m<9H@%KD8g$MY2b&tBoPxnI*Sk4-ll4qs)oqq;!w!~s zT&;N$&9Cm?df)s20PUGKJE0o+$DQa#~IaF;pqBWYMa3eJ@uV8$|;-0zOI)| zOluhxEkMH0MVZgi*%%6~YnvAcg!W6L6(L4l-;#r~l^m&i4>6=ZN}a)O$2-HKh>fUP zlMv1MkcL2Nt>v68WvHN*E4cTMK2UOWO>8#bkT^F&hg^=bbciF7eVWFeC*Xfi`GGxPq?7;!ZA`{niP|KjhI|1i{iE1A6XU#U%MI z(;IM;b0a*w|2$|LqKZfoXH_C)V0w%&Iwm}<(B*VMqZ$!Fm>O3= zdfz;qfXJ)7WhhG#+VFy0?$kRc$kDu3X3M_#1=mwDq ze#dRIbECvya@d4Qb2o~IA;Cab2!!v(#Ti)NU#(+=(1H}giJiSM6+|XL4SjX;=9`uq zdF?HzE|;J}xsG}A0BaeNHS|M6$~7(I8v4QYUn_{~VeFqmh3mFgi>J)+->Ma(NkQsWs@2JX z^(Zo5@@=%(E2Vp|j#2bG^A03Wpf-QhyAFd^es7_ocOVzKee`kn(z`x~q@xQ^<3hZo j9)PL+hyDsK9{eh@mG2u<2?85&80JPBd literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/edit_contact_act.png b/skins/default/images/buttons/edit_contact_act.png new file mode 100644 index 0000000000000000000000000000000000000000..57b278278983b6eecf017c205e9aee9a8efe562f GIT binary patch literal 2157 zcmXX|dsLDM7XJhUluyxoL8;)_q^+q4JE>`c_{d&rk7;ys15vP=3SX6J2}+`trm4Lh z(Pn#0S)sM%woanp8?~k^HI2|I(jK6cKqBALoc-gz&bjAz@A;j3?!Be)vFmKCms$e= zV6#3Za;w=AzX=*?)>*l^pUno57QQ(g0G^LLi%TGzV|;d0LiRQ;C;M=6CL0J(<+9ks z_4||4*jw4jsYfz;*`WY{g4RcdZ_gQH86k)&rNQ_Bi-ltXb~N}W!0dbcC^*KVh6D!2 zJyR$YZg>-vhQyG`CU%-CR5PnRcLk+#F)i;5HK#6LZIiUi96cNPQl6mf>i(%!sEDKmkJ-jtb^^lhbWv`}SPBzw+ z{vbHr;4YfjhN$8^){98>^eODNXlCtd=>wzx0-hhks<$7yq~xi*gWLTuu?3T1Ao0I;e1i zZeyQ|*F`?s|FY(DZqgwDVHbUjFFWPoHt30wV3_9zj~Xh{yhv$1W|e?->Q6_e(aw^=V9~EK04Ta0E$TH zEt%Ns=w&PpwxsX8347Y5)`2gbbtcEE;VrM8x#%1dvF5s|Qng5NtLBNA>Ei5^Jd&&Q zhkIf?;hD+pC0;;d%>^92j2NA7niVx9_j85SI*5`pjiL1HPH1X7lFto}@3T!@Mgtlg zBf~6D{;TcxynV^)nZERyS3DsE@o%H((b3+VLRR!9dGDaCa<8U(sZ^cH&3JigsDCtfAGO$b{lcD=kHrZXY ziWJZh7+Xp*$L_5VG4O8}2!EdeVV`5G@(dSFE3pnPf|ABH{UQeSQsp&jk}h4#V=cC%QYyvmgD+KPg9#yP7UD+02)P@iUIfSX=uTwL%UQF`6EOVXV9 zjWphtEwdVp(bZHF5Xf!1*`9B=5jhAkXwk98i3xS>&LB#b$S7nfMMLqFe(F z#rdU%SisQ37CeZQrAen4kwQ0$_@X`HZ@x`wsZ7Bd*3>Wr=5bB1w>1i;Aee9EKXd_p zo7Yh%0(pF^iXyzD6Vz^tjI#3fGZ`(N<6RqR-9~oweFq{x{xZMx%onwatH6zndbAr2 zSWoHcVi4Rw2f-7x+P#AkqGS&1-Hpg5Iz+Stgox`4a2a#$3}JPJDL^bPbd~f-tZUL> z$;{n+`f;~+BWh|vgS2DL@Za-uGN;rKm5NK?8+0$?m@I_T3YtI-WOdDDogdb;ZiDz%OLng$4TuX@ zA(G?ovx^*)>Oc7O*ksEf2FTbouJ3Q}eR`^q@C{IW*>h%PTS-SR1$CHGl0~A;g*nIq z8)>;1arS@p;Fcq9Eej&$;7(*ZNk9rh)X#)}rP%^k;89yv2zRFG$QtWj_ffKk3E%t+ zU~&A3_Zy`>n0Lr9f@Nw?gzrLZcPACzb!zFc{0B+ASj>cjPD|+WeU
fwyQZoc!eCHL!P2A)d!s!B{aQImHj! z06Sla=kJ-GoF9dPM@O!4>uT!C2i(n#y<7pVy0~*;dZIellEUL0IS3b4NSM$ZhGp+S zk$LbM&KAmOSH35ZbQ;*xp{YwQxKE;S{W(VD)r<&6CdDrVfR!+B2DP%9hORw`yGju^ z_xDVXl4E@KP)He>0Y(%2){=rT2nYzdKC<|wTsb{)6RhwfaG1tLt<@cI_S>1k7GJ#_ zg(f!IGE-AiQExWHk0NCClfvPZ&1C#_^0cnvPSuA{x;)8vS@MnvLqR;|e(lGnK0*RR z0kKn5xwei;Vjf#{G~UDNMr!yEYwaM!SkaR`7HDFU?Q7(jjWqDae}W3m!`~8Z{dW2J zVz`H659F^!c0sEuR}-g11O|22!$Yk1g9JqwPmqX~QR`0urN=DCzBoCD3a0rf8U1poj5 literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/edit_contact_pas.png b/skins/default/images/buttons/edit_contact_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..b999294c89aa8467cdcaed29f10de3f5dc93feac GIT binary patch literal 2135 zcmV-d2&ngoP)my z8z=7k`}^lFDdqtL5F@c^Kwj5DOIp=X@BhC)JiG$pOoAd3K-VxrB>(+qc>m@F!{-mL z{xLE!e|dWQ{H2GN4_qV0Tz~)~=m1f99T^oPH#=^A5gt7gYX&1jJ%)eGTnsNi{$uzH z)yfQXhd4hI1JmDc4Cl^YVz_kXD8tu}Z@%0okQ{lAwFuARSqYV%oK zb^rtrP6ue)Mc7EFm}mw>B{TkJ;LZz8sJmfKY~pyKmcLQ1#&ue8ltjVnxP5ljIX|NG3>blwEPbP10yibA(#mZhRA`^B}gqu z4@hrlVmhOUtfr={wyg#>y8r?R!vUPULfkTHX4bA@X^d~avNN200Q5B@GtgXSIL*k& zgatFBr~~0MK)oO{+``itWz|isL1v@d2M|CQ*-*zZ)>%&5hFMrtgkkH2zYL5lj10)G zWP}rF0O(FDWhRCYBZ!fofBa`?*z%j<wjC?UYf zBgDdJ8H9x!+R1Ey>SBwxaU8%qdqvNJKH+OROFh%$ol382M)|1vTB1)6ah z$hLKHW?*Gw6=Ub(a$Hq1n}9VZ5CcO46e8?E$A16$6U0X;#{mKe)iunle?Po`&%nhBNq8X1 z{SO!zj^2k9!Q5<&3^ktYV4sT%Ff&A&vVz5d$$(+nq2EA@nIIVG2qut2m>>=XIe>?q znc?I6cOYN>LADbhfY3_9|KDFceZ(Nl4~%<|1Ayj#`ShEiZ_h7=7oQ-GP#0%nNU&gK zNU>yP;Dp%Eu=>IuhIc<0Ar^xy1jZl8AOhu%{=@L=*MEkezzFZz_Xn7&A?kwkm>KL3|Ie`X+JA_JprB_3 zIfN1Ha~2j@NH8*p@iQ~LeR_l8%iAZ9k?jNsAQT7OJh}Po`$yOQ{r~fWfd!a;SGeQe4d0|F|Z=XIe zyt{Mw@6|)g_MzJc5I`6X0ENP{Tc?g)-81_i7xOO$DSlW`GJp;K`j?Sm#;N}d%P#@b z#viE9p_YN6EnnOP{Z`!Ux*l}wB!Tk9#Dn* z_~r$MdneZae{uWV*&8P|pTlJbKmZYJ6-%iY%Bh*U*>DPq^T_GhGDs_FGca*-G5r1m ztrCIS{{S&NsM!7Wjp6Cts|=4WA7=RR{^gh3XLcQVcIW&feC7iL5LO2;g4rEih01|Ni{`rJMIJAHD_D z2Xf{=DE{Qvmo z>Dy=bE+6HF0Ro5xUGnSKuQauso0}Vj4-i0b2fzv> zMn*=4=g*%ryn6MD;mw;j3|d-RV78c;7+jO2q$E+6#ZG*{z|1ZLGL+%}&$kQ<^Au3* z0s(*kf;-^fzkhHCNJ&Y7F$^HHNdbSD#TYpF`52ghvHj&8GuUioyFdUSfUr6M76Pwd zzXpqmii(11P$*#YJ;+CY|NcdxLHNPbmkfe`{s0}o$nf#?JBBY`{xfiLa-ui@Ab{Ww z0BJ-HVtm02Qj3g{4MYa4f8R3v`ozY-1PlV!e{X?~62`C#Ab_ws0Gkj00Dbc7*Do-Q zHMoJ|pfm$g^ZWO2u%1a#EDY@IpBN-0Bp6s&RN--tY!^TPu^=0O&Cs7ee}WA}&aO9a z-eh?9?j3`wsw%_Vw{L-#urq+l5Mg0qhA-d$FswcCj^WC^_Y99-d;sf_li+7CQWs~) z3e;v0N3#ncfH2Yk$dw=qL4^gjP!Sgw2V)rc@Zkeo?YVnj8D?y~&G3UunSo6}jX_ja zi~*GFK7V<|u=CavhJ*Dx89H*^P@)VVfH0!q^XJbvgZavpE8qkPN}M2{gVcTb@`Zt) zpP%8>z26L5ud^}mt9UZ-aquxP01J6g>IXTXAXtH6+5t(1U*FUivL+m6u$4x503d)c z9Dp3$=s;Ur8=f0L0OSaeZ{B_W#jt(DIR+sE9|jgy4zR`GiiQzf1TaLHurWySGc$DW zW@g~xa%VVvas@*`^>(=pt)7nn0tmwaxKcDSc=_@rmDN_h#@P3jWQF1q6nnEvr}be5aQ-wXy3ui@KIWq;r)l_lYzqi00D$G4G;pb5MX9z z2J5^2s@{Cw52Z8eselnCUf5Y(Q+h2z7-+u~#!~g;a#Q}MF zc_bCJ-@ktchZrNHAp;xJe+CvdMh0zY`E~f_cZTVEJ}_K=`itRwn>@pwE8iGuR=;8R z`5RbD{`&*c2Tmyf0R(rzq)C$)$*tk^V&}g4_3eY`uircjUp|9El8<5Gp-*7TL14x4 z&kUWL-@(=Y`}Gx=7&+d9*Z=`Ul@^g8AMf#}cW*GfeEyc<#O?23F_2GT0NHYIPW$o_ ztOvvf2q5Y>fS;%6$IBakKtX%r&JS?V$Jp=!>i{gpI#A7@cX$7Q^nmyP0mMkHj){Bm zhMIdXzBhA8889%haxqw`aWcpWvoP$u^bHsq{}{gg`p@w1_cw-b&o413iL=-4>rHLCTJDRn4X?aQD}e+RFUGz{Qczc=O3?cG90@23>^3Gzy4+T^zj`7NDL&WBEgvl zQVUG*VEX_92pj^9jg3t2-@j+Jx3>pX{QsdClqflYm={W;CsGif8C2^+X^@^j&p!O) z-+1}TAc_T87cjE0uz)KXAdPGRyov_NBlRm7k>vg($^C;m z3Qhy%|3XXKe?YtbOrAXXKR^I64s`DrAb(^b07*qoM6N<$ Ef+6HF0Ro5xUGnSKuQauso0}Vj4-i0b2fzv> zMn*=4=g*%ryn6MD;mw;j3|d-RV78c;7+jO2q$E+6#ZG*{z|1ZLGL+%}&$kQ<^Au3* z0s(*kf;-^fzkhHCNJ&Y7F$^HHNdbSD#TYpF`52fO85q92V+NazY!?Us1Q1pSz(U~l z>(^j0QBhGa4GINpz6bf}@87>DGzdR<`jSEL&mW)z7#Tjke#h|T%YOz=PEHgD00a=+ z0U(XYL5we$L28jPvVq8e_3vATU!T|*n1DgR`tL2!QNkE@0R#|M2VnEzAD~Zu{rUx_ zu?9C#9F%52YJUIz4c0R$iiLrl{S$+PgaiW%iz+#DCqqZB8%mS`1Q13PeE$3yXE0y6as`|qL5UOObC9|(U%oK# z^Yb&Dy7!x5>vc8;eics!J`O$x24Eo%O8p=Q6a*_UOgkXS@avlzL)L`D47Sn;4*&!Z zh69j;8y#qCYr}H`2!I>`^3A)?zZkY}IL9Dl;KRVe$^o_*T+uLsivWfQ6E+4ZerAU5 z-OLPJT<#2qPp)7HsNT-Aq1E#XKmcJl09T4e1}|T}1k<2&0E)8JC%-bViEA@(aB_hy zWo2ey2r*=3uu*1WP!xgGcXq1G3_{!-4DCCZ89qwuGQ9ur+!`pn6Ci-FrU60#76Q!7 z%wT=jpS)n;lQm;t2igpBK)EXmgQFT|MXMvl#8BkQ%24@6k>SPVTi|#A2p|jx$jQkO zUDAP4K1koIw)v~M3okiARq6`r+05KynOza;l%ClU@?$SVF1~3a8CR3608Tr z1_&VPIDnt$_>Y%2{(*w_#GN1DppUWP1=ayrigloxKkx4T1L*-=1G$P!eZ9v$Hqg97rEP z0Kwguo}SJ~i330esz~u1`TgYZ?;o#kG90@23>^3Gzy4+T^zj`7NDL&WBEfkKq!yUq z!S(?J5I6)H8ygwlzkknYZ*R|mrP0a?%JK}5QWYIALOlV(prHK!?885{jb}gWy?Xma z@ZF~`>>wqA{JcLz1o__BYxA7YmHht$r18+9LqGca`~Lw15ZnR4s+5I^iHRN5AVF%L zfh=Z+I)o9q*#>08EN4V=+<&0lf2cZ8cK8d$|A69PHeB-Gzwf{j^)EmG!3_nrh#5fu zSQjv|u&{tD8X%2q3A~C1$s>gT0}i?WPz+}S<^MxVTd+fcS^qyk05J}9?-(F}2E1nk a5MTi1VtMP8s!IC+0000= literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/inbox_act.png b/skins/default/images/buttons/inbox_act.png new file mode 100644 index 0000000000000000000000000000000000000000..30c1e7635d2c30bd39c4a18a1d8e4b36d7b986e7 GIT binary patch literal 1827 zcmV+;2i*9HP)}hKFu94dFnJc8z6vKuqpWby zalpU-|G+dOQ1SEU&lz65ddcwS%^LYp|Gzs3@2Qg#yU;=;a59|L@;FF#Y%MUoZ{AtbgA!{QAVkzyu5e)_-ro zYQF;$Aq)Tn5LyWQMG0bj!TkE&O9pmsR)+6CzcVm1F*AJm@SQ=JUj#$lmRfBjo*=}d zzz~4}fB?c80{!9_*n5VDAMP{A z3n&8lHyN0}a54xB3p42G=;C((l9>Pjgw+9`KYs%I92?Nq)`4cP9}Eg=VhrEjzh+Pn z6k|BL|008(ojp9dh;;x!05PFTK*|A7aKlnDF8tv6ZH6EJJ}|uh{}fDv_=NPp90s!o z1ONgEH5dH*gHj;j1Mk1SVc_Qe&%pHWJD3LXiP48_4+sDR5Q+nS|AqvOyewv+Q#v=E zVdwrGh=eF7#K6G@bO6V9FwG^#$lzOP2$y$v^kC>tUWnBJFnd4%Ab`+9;4ec?UI7kw z3o`us%FLi0&&p6AP|N^Ntt>wnSegDYOlr#ni!^QNXSh7~2gCP^f_ThA0Du5u#Fk)E zQq#|>sHhlud3iD%ICz9XQBi?`UqAp@g8yeIoEpJkn8e9Y>5|8=^XFECkJ-H$x(-ZX zI5X=D!^GTG42=Jo8Q#DDz;OTmT?Pkx8-^V_b~4<&dGq|-IkSwA?E(lOj0Q`^g1`!ji9tj}6xdey2&~zd847&6878)rGW;)_$*`g8HbcH| zI|DDX2(YIA&%n#a3oPw`MK`EY0vhuC#dB~)B@Z;niOj1c(p`LmI} zo*u(XVC(2LuqOQc`3q3f6Ci%f@cYki1|dOV1}0`E1|Bwkh8&+JhD}`$fpjy25QhW< zGYd0=Ah0C-{p&Bo)29$UAAyD1yZ7&awd)H8eO+C!`N;MG1Q13DaB*?*J2*Npu(Pu> zwCgk@Wu4y)yLRsdhQJpFZZ0l{4<9};a5IW9RQOK?6@9?^;uixSFCW8~PoIHB_;-e| z&>#j@R#tGrg(7fhu3EL4AK5;D0K(cNd+^{1wA}(NxquA_E-nrR6BA>GO!Y`w{O5YJl)+GZrr-V@c!KgaNz_B{=cBM!avL$2M|Ck*s5J*%VGSl zU%xSk3JEf#B*w#JfIw{HxrY-~TF zO(PzVod5yE0`obL;sCY8fbqL<)ym}wz(mK&z<|)q!0;c#5g;4>!5x7RgIEl6I6^Nl zQT~#Zm1_st1H`|8_!&R|!HZ&O2!OgpY|yBIVP+`J1Z6Wp8}^Jy4Se*7Mh=?4Q2Gy) z{R7GdIp8}$0HM?cjIbn)X#pcjZvvH#3;f68AZQH+4J04{2q4CR?w$h#7y$WeMwRRK R%<%vK002ovPDHLkV1hp!GrRx* literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/inbox_pas.png b/skins/default/images/buttons/inbox_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..67f4da08dcd0b6d0e208a70c3cda28ce0bfe1fc9 GIT binary patch literal 1804 zcmV+n2lM!eP)}hKFu94dFnJc8z6vKuqpWby zalpU-|G+dOQ1SEU&lz65ddcwS%^LYp|Gzs3@2Qg#yU;=;a59|L@;FF#Y%MUoZ{AtbgA!{QAVkzyu5e)_-ro zYQF;$Aq)Tn5LyWQMG0bj!TkE&O9pmsR)+6CzcVm1F*AJm@SQ=JUj#$lmRfBjo*=}d zzz~4}fB?c80{!9_*n5VDAMP{A z3n&8lHyN0}a54xB3p42G=;C((l9>Pjgw+9`KYs%I92?Nq)`4cP9}Eg=VhrEjzh+Pn z6k|BL|008(ojp9dh;;x!05PFTK*|A7aKlnDF8tv6ZH6EJJ}|uh{}fDv_=NPp90s!o z1ONgEH5dH*gHj;j1Mk1SVc_Qe&%pHWJD3LXiP48_4+sDR5Q+nS|AqvOyewv+Q#v=E zVdwrGh=eF7#K6G@bO6V9FwG^#$lzOP2$y$v^kC>tUWnBJFnd4%Ab`+9;4ec?UI7kw z3o`us%FLi0&&p6AP|N^Ntt>wnSegDYOlr#ni!^QNXSh7~2gCP^f_ThA0Du5u#Fk)E zQqzM}R8&N~ygV5W96Z9HsHnieFCYLc!T&Q9PK{tNOyXpybjf4b`Ex76$L!t=T?eKx zoSF57VPfto2FCx)4Da86V7Pz(E`x);4a1HdI~i`?y!mGCoLTFT?E(lOj0Q z+}zwu($bPZ7vBI{{*&R|ySKnb#7~9~A3rdB{_vF{(WZi7Z~tS4+1KVW_^|pj%)7aO zVQ24ShIqSDhOZyK0oA={_yH`u-n@ASE;+AVzs8`VqRha`^g1`!ji9tj}6xdey2&~zd847&6878)rGW;)_$*`g8HbcH| zI|DDX2(YIA&%n#a3oPw`MK`EY0vhuC#dB~)B@Z;niOj1c(p`Ll?= zo*u(XVC(2LuqOQc`3q3f6Ci%f@cYki1|dOV1}0`E1|Bwkh8&+JhD}`$fpjy25QhW< zGYd0=Ah0C-{p&Bo)29$UAAyD1yZ7&awd)H8eO+C!`N;MG1Q13DaB*?5IXF5nu(Pu> zwCgk@Wu4y)yLRsdhQJpFZZ0l{4<9};a5IW9RQOK?6@9?^;uixSFCW8~PoIHB_;-e| z&>#j@R#tGrg(7fhu3EL44cR_`0K(cNd+^{1wA}(NxquA_E-nrR6BA>GO!Y`w{O5YJl)+GZrr-V@c!KgaNz_B{=cBM!avL$2M|Ck*s5J*%VGSl zU%xSk3JEf#B*w#JfI|Sa6w6L(e(C=(Z>9wtXjHF#~g|#b1K~Q1;|NsAH z0RR90A^8LW002J#EC2ui02Tld000K#z@KnP?1(OoUe9q6b)LlNPqfiluhxx9`ojr7 zx_}A+L+~gq-Zr}Pe09A}#bDt9a=ZoG<^F+t5(5(iJQ{dk5QT?{3Nj-Y zn3*0a1d)b$LW(FOF*v5DI6Dw0k~{%FI}tN42M07M3M&ycE~>1budpvZJ~tW1$Qiz^ z!LS9yJJHfRDG)5oL_5zrLpcrx1ZEVU1Z)M|LU7IS2^;zwJQG}A w=^B_2K+uK_0Xzn98Nwk%2nGyFlmJ071c!w}I2bT6;K2h45*m;o!666$J5}xEr2qf` literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/logout.png b/skins/default/images/buttons/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe632ab3b212e84bf2dc7986579622d723cc3f1 GIT binary patch literal 2036 zcmVrmw$Zm1M0nh=KueH_|yXg5DPJu>v8gKvNkl;l8BFI zVE9kKcA)%=MGLhU&!67JAR$N45dZi>VO{}%{50w91`@LJBnv)M}5L{l;_kb&XUaZJnqV+nzuKfr21daVBb*J8MI zW;4(czPKC#5I~IR=>%lCr-ZDM9tZD6TLWOQ2ly~BTsY0Z@cS2%rJ%I<57YN>aVBs` zFc=y!yx6dX;qZmi*Dn3|?7#iR<9q0i002n5TaUlKsJJ{hMGpzpu6Ys^-8yO^I{egC%I07Jm;2{9YYJVhTm36?D8*0h;0xiFE z4r)0Q!=HbD7=HZu!vIpx&cedL#>|Z3hF^dGGyMGXiveg10|!u^g^39o5v}8OzfvyKy{^J+eGk<^CFH#8)OH_ zE||Rl0R(pdsE`3F*N_bcCb%o-fk6mNaE$-K_{ZPh4247_@}41A^e46hk} z0pTAo2C@0e3&C=t{yq$hk-iv%}2WTe9 z?7wI^2OxmZvLR3w=<@&n|3Xs;#C_~6Obo9lPGMjKTFRrP33mijT@_FX69cEbJlupY zSFbU=Z)#@{2I~F!^&7*#pTEGFgpmoDHl94k$h!am#DZo$!~fqv*Zu>tfEpM;=>(Xl zSb=Pj|BMW8`uZ3cii^OOg8-MJB8p+3E?i=GQBcJo1dRJXpo9xd>>#iF1DXR$bF4QW zViX+!0mOvv0APxOSPTqyhX0IU!T&%9urf0OeZ|7?s-v6X+x`0(h1Zvxw;3K6R4@nv zwXraY$mj zl;D&VF&x0HqRb%I*T(P;=%ruasAB?0EU;QznB44{De547+f z&>F86M`8Fg(aDVfcLYI+7!_86-Ly7=Hfy z3$Ym-08C&u$W!PJ008Y{>BC z+%=$s{{nr(%m8v7IB_um4Fgs%tU!wyp#>F4^!Hy-Wd*7`7#Y|==?|#(-#c#%*>1|kL1Q0+d?Ez4A>?S6y0&;|&l(e#jlsv<)Pal95{Rf5+ zGmvHm#tswMVo;)HWJ1IsDBVDE4Y2S56~q4_iJ6U8nBmI3+YDFUJO^98>($dc$kj1G z0AX#AfE=O3&b3WfR8m<-NrmC}$4}tsWCB{w#00@00Y*eafB~Gt|3Q2W_Bk*ln0W;l zuH3)LaOvgKyZ3&6!>}9#00M{+Tgw^d2t{_T?Rp|oO1diQ4FA5o2PYXOW`rX^^AfQ}HARMJ=1V)*y@ z128HWfu09O2RJGqp#btdIG+Q9{vR;97`gcwF5I}raPigCd-r~P^W5_qyX7DN5I|TP zrHr7+22wX(KYbh_Bo+X4;wB(h!AMsh9Pf<4BA1DU8B)3-m2m(5{AFMSHdfAGxyW$- z<&%fIKfjOM^6~8}VAA9OHMoFkexch15I|T%0H~N3mQC4!$=;7&SjB-ya5c~-Ibu2{ zz({z$;N7c|3*Wyy2epZSLLWdG1!&hDboBrMgv$Xe&@uvqnK^+K91k-y2T&y|q>Tg? zX9QNWOt8+-e|V<|oGt%+|Mw5n82iJ3gn@Q_L$?bcfEWk5cMK3f1Kv9Z2rvNCq<-0) Sxw!oR0000}hKFu94dFnJc8z6vKuqpWby zalpU-|G+dOQ1SEU&lz65ddcwS%^LYp|Gzs3@2Qg#yU;=;a59|L@;FF#Y%MUoZ{AtbgA!{QAVkzyu5e)_-ro zYQF;$Aq)Tn5LyWQMG0bj!TkE&O9pmsR)+6CzcVm1F*AJm@SQ=JUj#$lmRfBjo*=}d zzz~4}fB?c80{!9_*n5VDAMP{A z3n&8lHyN0}a54xB3p42G=;C((l9>Pjgw+9`KYs%I92?Nq)`4cP9}Eg=VhrEjzh+Pn z6k|BL|008(ojp9dh;;x!05PFTK*|A7aKlnDF8tv6ZH6EJJ}|uh{}fDv_=NPp90s!o z1ONgEH5dH*gHj;j1Mk1SVc_Qe&%pHWJD3LXiP48_4+sDR5Q+nS|AqvOyewv+Q#v=E zVdwrGh=eF7#K6G@bO6V9FwG^#$lzOP2$y$v^kC>tUWnBJFnd4%Ab`+9;4ec?UI7kw z3o`us%FLi0&&p6AP|N^Ntt>wnSegDYOlr#ni!^QNXSh7~2gCP^f_ThA0Du5u#Fk)E zQq#|>sHhlud3iD%ICz9XQBi?`UqAp@g8yeIoEpJkn8e9Y>5|8=^XFECkJ-H$x(-ZX zI5X=D!^GTG42=Jo8Q#DDz;OTmT?Pkx8-^V_b~4<&dGq|-IkSwA?E(lOj0Q`^g1`!ji9tj}6xdey2&~zd847&6878)rGW;)_$*`g8HbcH| zI|DDX2(YIA&%n#a3oPw`MK`EY0vhuC#dB~)B@Z;niOj1c(p`LmI} zo*u(XVC(2LuqOQc`3q3f6Ci%f@cYki1|dOV1}0`E1|Bwkh8&+JhD}`$fpjy25QhW< zGYd0=Ah0C-{p&Bo)29$UAAyD1yZ7&awd)H8eO+C!`N;MG1Q13DaB*?*J2*Npu(Pu> zwCgk@Wu4y)yLRsdhQJpFZZ0l{4<9};a5IW9RQOK?6@9?^;uixSFCW8~PoIHB_;-e| z&>#j@R#tGrg(7fhu3EL4AK5;D0K(cNd+^{1wA}(NxquA_E-nrR6BA>GO!Y`w{O5YJl)+GZrr-V@c!KgaNz_B{=cBM!avL$2M|Ck*s5J*%VGSl zU%xSk3JEf#B*w#JfIw{HxrY-~TF zO(PzVod5yE0`obL;sCY8fbqL<)ym}wz(mK&z<|)q!0;c#5g;4>!5x7RgIEl6I6^Nl zQT~#Zm1_st1H`|8_!&R|!HZ&O2!OgpY|yBIVP+`J1Z6Wp8}^Jy4Se*7Mh=?4Q2Gy) z{R7GdIp8}$0HM?cjIbn)X#pcjZvvH#3;f68AZQH+4J04{2q4CR?w$h#7y$WeMwRRK R%<%vK002ovPDHLkV1hp!GrRx* literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/next_act.png b/skins/default/images/buttons/next_act.png new file mode 100644 index 0000000000000000000000000000000000000000..fed82945ce04fbd483f4955a37f8464e6e750c99 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEa{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i>J^>lFzskoK&=l_3u=8X&r4HAi6 zhYugV-58=RP=9b)!P8Syc^DXvv>aK_@JQNW4(E|GH%u5<1casHr8<@~ew0)wa|-7X zaPYC1lg@CYy0L;=VD$kOMy8I=hWUFMDZl2)i=5@O&`5R>83 zXDC#f(#G7tkaQ?Q&gTe~ HDWM4fhB;FP literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/next_pas.png b/skins/default/images/buttons/next_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..df80ad344a4715f77428ddd7aedb9d015c01c2e2 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEa{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i?Fv BTC4y7 literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/previous_act.png b/skins/default/images/buttons/previous_act.png new file mode 100644 index 0000000000000000000000000000000000000000..457d873c55134bf80785fc65c5a99ec2d97a4e79 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEa{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i>J@N{tuskoK&=l_3u=8X&r4G|75 z6%`hGm2wK};&v9Ls&+67IQUqI7%~^C3EXFR#5F^~fnj4p;0u-`dmVBb^cV#kPIQGf zR4@rtKQ0n>U^pmpn&G37g4xmMjtvY=JAZNt+-4{g7WjW?sf0qq1Y3@v5dI_29BLS6 zCp9n}5|a{NAZ3ul$e|G9*nU;4fgwprAk!fF0E5B-hP&BfpAPMby#RD0gQu&X%Q~lo FCIAteRUQBU literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/previous_pas.png b/skins/default/images/buttons/previous_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..db7186d56612087517611184289fa9c6ced09b61 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEa{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5iFVdQ&MBb@04t$fO#lD@ literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/print_act.png b/skins/default/images/buttons/print_act.png new file mode 100644 index 0000000000000000000000000000000000000000..19e1f3341cd8a10a22dd54b1503d32a23480c891 GIT binary patch literal 1468 zcmV;t1w;CYP)mYytA{YWspFd|vO-dxo0kh}LC#VJ>fCxI^@85r5`oqU> z42+D742%rGWWx;f6tcg7q4@tV5QE@9kox}&f&x4YfB*a==m3BKBA5vO{Qd)tEGWT@ zrujcaoROIktb~z?k>NihBwGLc{X@_J00BhM0l)wJhT6{vHXQ5-MyTa5he1PwkqM%X zi4o$;-@ktmbO1mA5sZRgzaWM%GBd&KMg#~0BsM_l_#e=Aa1=3tqTxSOFX0dX2q1zE z_ziUc6C)#nW`x8$2>b)mfByVs`1|iKIR5_t(+ntQ@$ql~_5LL20Du4@=z!0kzc76K z_>tlJkKbT>{{SrlS@`?+Uxt6cIQ|Pwbda?8AL_1u3|#EY44=MyA?N^r03zssPoF^aq>{$l44<8tQeg4F- zT1IZu^XE^Ufl~WmY5)QVIU90HO3G|BpG?9WZNYATRuNWjGB!F4@C&M407|3jHZoZw!o&g9Tlr(VT#&w|2 zU4WKDe5|OT#PHz31BMG1FG6wyECVnwGTR^BXLURDna-hXOe*9wK=HY_peKeaH@OU4q04Ue|`0)d1HZz76fB-^u0MLa@z!LB8 z|9=c$K7WM=3nLVRqkxeKtuzFN6ce!U`G>IcKd>AC7lz<+;Xi~1LXg>z;v4}00thVx zn1I2=4D~tGLMBE?Jpj$~Fh`&U1~bEdW+XrV2ZrQ-h|m8+EeE*>1d;WE06+ktH~?fZ zGc&YIhxr~_3BfF9fXXo-p+@nQxhXxaf6U}yyaKmegc0VKOIFzng02Ur@iFo=nZGxT(KQ565;Kr;>;IKbfG z-~jg|G5`o5aBT<_WITBIi14u^hhKvPLDg?lQxnxXA9Zzgz+zbx&VTmo8SA7;lfca- zfB*uAKtn?V)4DaQxeSerdcS`C3ammO+ZGfSVHBJ2W&pGzBt{-aE32p+hN*k`@})3{ z0yak?Ad+5zyQ|1EQf&@Be-ByEl3<1as=gJ^sSpWL2QtMU%+|+o)-ZE z2p$E6g@r6YiW^vmGXvwF@z0+>|3NfHGaV{UNFJLw)RDh|_I!gy0YCsT4s`b%Aiw~k W74nDy;zuI@0000i;E#9B77Dp<^co{BcU{~ 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 KMNUMnLSTaGs}N%V literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/send_pas.png b/skins/default/images/buttons/send_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..db227c9027bfc3934ab7cdc810a453d9e7925a2a GIT binary patch literal 1836 zcmV+{2h;e8P)I$umq#!4?7; zz%+C1`Zb38_wF&gfB&9AP*9LTNlA%8Q&STt%>-124p)KLZ0m05PF*7{LZGGXpV*W@2VwVPaxng5o=OZZjAe8#BzFHH$%6 zSsAPcL{FPGl|f%$A1u$r%m`P{%)|tB5X4bTOqh-U2q4rDV1oFT0q$}b8)CrsA3qrQ z`S}@c-@eV@;pqwX6^OnAV6l6dVNDwlk1SJzN;i;;sFkHNNks&oLjp4?P8w`;V;S4vfUuVe5%4WEH z`7+QUD&S~iVq$^oXMtjnCqR6301!ZEA;1WV1+YSd@1em5ghqzO4BNJEW4HpeEHNpG zL0nv%;pNL$K>j6$pFe+sC>lxS@11`kf0EQqM{;$hK44?uU|ib>Et`Z??1m8{{Mp%1iyd(M$YFL z4gd%sj5GjAtxOO%Gr`=>2rd*r3GDy>zYJQyLI;%kfBpK+@b}Lja6o<%>|1I2?>D{Sa3)%FhTtV`yLcBe}IXLot>TG6)+d@^6`Sz{sb0OLPCNJ zYu2t|xP9vu!@GCy7#1yB$WTyN2o5wRM$9w-5I`sn02RNVK79noRcve=!_1j87__u? zz-%K!BZfafi$THr9hl&rJb3~xfKD7c%Aluj05^l3osEH;hlgSL^5qPN4;^HPi;II4 z$)F^RCF%eI2umVl1ZyZQt6(TEuVh%Zd?|yitqrgg*RP*}RjUlcvuDr1C8Ihp zM~F*EAUpvqMQvB5&fU`6_TVrW~0t65fdLo3l z6cP;&?mu9#wzh^OJ|F-##lea4?VGpYc;?{XVBqBB#4z;x_n+WsyM6l(*c?b20OexL zL;PaiGDF)43|P_tKmeiY{ts(5L5klePaZP}3h*<0`tk#%6k`YaoSmJ6K|lb} zH~9=KAdA-{e7HGZkl`^<3S6KGLmIeR;Ft7omjR{=0Ffrui<)LT<2q19Rtg*3?3E0Hu ze*UzqzrX(rObtK)!PCHB zU_$%y`Qrhgs7wH5OMC!WO#l1;_sWj(@u9WkU!WboCrz3JcQrr&4S4Su aAiw|_lPnK}`?>l60000Z{NN#WM^hD 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 DCfcOF literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/source_pas.png b/skins/default/images/buttons/source_pas.png new file mode 100644 index 0000000000000000000000000000000000000000..aec440a5ec91df8f575d816b2c07512ff9ba02ad GIT binary patch literal 1632 zcmW-idr(tX9>>qk&5Mv15S1w4jjJUT&_DozRk=w+DX2BF0i#k(*hChThXGk|u_X7x z2Bc`V!}74Q1Vzh82avWawHgu#ay1oSYXx^HPlrC7A%=DoYr|gq$2q_GotZP=`TXYl zJ*Q6jehP=RmIVOdq`s#}CoA%1G3n%9a^l3#WTEEDcFO?xcKknk)X`)wEKOFI{;BA2 z>0h-5J&@^&a`Z@Qfi_p4uGi`+j@{C41Ayj9RmfE3PjX(btRxMi6eGyV3Df{S8Zk~4 z3WXD!vj(OKm&?Tq`1Qr&`k<8+-uV^j>)(EDo_XARh<#}AL;cI=bEEB}XVy>c+P(XR zugbfW^beUYA03bz&ongbwzRc1wAR$r2N-SYv>1!YY&Opfn|bW1!Kz&FWCYo;fpV#%!)bRqsW&StE7^lpD~HQpx+6Fgsuq)H!Fb!|$MP|Pp{L+oi=)c>8d^6tQsd@}2^rYPsN>cyBe6(aXlUr4<#O!j z?tQ)99`%)3f8~$9I~ah<_uY}IabqW6EidKv=_M)91=GxbuNG-yt$gSrR9IL@*Qg|Y zpMNg>OI}{o;oMx;sZ*yg`Rq33#J(&M#7E?5viZEc^~o_JjJM?be)@CSYRA*(?j028sJXu`DVY60%9UCn1l-KGIZq@?(QDm zi7LfeH%_cN2cvmUw@NM#R8$D#jjKs3)Xhw-3~ENFDI~*IswIjLA-=LE6Bbn69C?tw zxl@&q;Sfnr-emus@nR7_$?g}ZlO=uqeM1kKab!fwU648p16?6t`N#VgQZ%o|+WyGC zS~!`*K%F@DJ zsrukSyrllprMJ}E#RbL)x>m`>T5%3Jfoz5ZiuIbWg*5(x?)MX1N7_m2uzlBTrkYjd5#nM{?^YA};Wo2b-7K_E6 zoSbAo?)d<2{?IBm(voZnCLi5Z{RBq#7(GdZCq=&_#BmVDXtryvc@UO9*}|N z=jUtcwa?F-t1o`@M2H&U@2*#HxIUU2V|~Ye$}ElBh880X}F)`6CXF3`G#vBQh`9NhI^8uVzjU*@&!4Kw(>#|5_b!}cE z?uiq#(2;NgRo-EEf{9O&oiZ8kW5yMk$KT(7x=BDBvwm-1!+MjmEzr=~HfttVEW#w8 z`LR5)hD|Uj4pb#WXOAE$zdP|EWX~Q;(zvA#Hbe^(cQ_8DAv?r^dywJlfJ_W+{!ykei0xw`F%x?T!Z}|Lw}WF literal 0 HcmV?d00001 diff --git a/skins/default/images/buttons/spacer.gif b/skins/default/images/buttons/spacer.gif new file mode 100644 index 0000000000000000000000000000000000000000..5bfd67a2d6f72ac3a55cbfcea5866e841d22f5d9 GIT binary patch literal 43 mcmZ?wbhEHbWMp7uXkdT>#h)yUAf^t80Ld^gF}W}@SOWlZ0R#L1 literal 0 HcmV?d00001 diff --git a/skins/default/images/display/confirm.png b/skins/default/images/display/confirm.png new file mode 100644 index 0000000000000000000000000000000000000000..27265f8a62d62d916abe1c4934e4ec9009033e34 GIT binary patch literal 2135 zcmV-d2&ngoP)+a;RozIqW#;Z zrcWbeCO`n;wb(m%uKTz5PiHf;u*m9}STh(I>M{Id=3;pH@gKuqs5WMx{o?#g3`~E& zF`PSpiQ&?jqYQul{CUjAFP*Y;YVs~zW&;EePK&*AW;A?x^QhX$&X2{?!ieF@owc(;prY`L=CS((AFQ2M8dn7JFt+oA&$H zj|~6FM8@BYoD7F={AKw0o47>C&dSJOtHI2``u{t_#%1&Wv$Au{+&(=k6I~rZ0AX0{ zl{+W(`-c}Z!c+5^o_=6sID7vOG!4PEV6hHj2C`AciYyG$0>2nm&Yt*>Q$Rd@+vL~f4^tgwz&7F zkgSgKroOnRF!cZdgp!@Ue}1=8M#F+#SX6{z>xI7zj4X@{OvtXp<6$dhCWa6rh;g5P z{AXy`@|)r0{r?PJ`oat{8dmIYp5I#zl(K_q0SF+txjqGpq`$p;Y+>)}%5du5e}@16 zfUX5XMn))Rf?`HY%*oEgkZQxipd!i$#wUOl{{73u@E2&tX&~Fy#hKyzhi8_)`SV0! z_5lPC+~U8#ztxGzX)yn0@N+>oHS_ToRo z_Ur$_`ayCpKQl7?Vd7#CkyU5;^Xq35%szksf(P}lZy%kMv}_rkyk`WL4U90%gos~Q znSmVI;(QDY{<=)CvV@^~`&WinZ+?Rl+V9_g!45uoorQr{Ooie8r6W!-eEFkF513mC-z8UFnH z2X;A#{p|f;1|bn?hM(U*OTz2}2q3tR|NZ{KDIh4w@D1o=kS{^LWoAJnD6nrCLF)c7 zeEIU5;oJ9L3>LsFW1$2w;`Qf$4D*lu1Uixl>?lTH(e@vt9%%m$U>U$GAk6Up&rdFx zeE1hTp(2Vg?rfff1DK%loH^h@ zK4H&KhCjdr#lj2<^8a9mf`T3t=70VI3l7s;LxY9oFU&rG0D@c0!p8aI!~6FPT&$1;1(MkRfPvxYeMphO z&Bn-3DyB=7%bV3>C3H_$>R2nJft1abfq#DO4-dDxj5KE8hkbTr2| zn0){N1h<%tgXiUor;iwf`GIi@vKVOYmruVL`u6-{c<~8hxw<$LLxKe>Ly9FU11H2@ zhSeATFueQ02(b`k5ip)W4q%4*9uz_Xz^wM>VWF5c%b`v3w6ZZS8H(B5ZvuQ7=6 z0DTOy^z$EvU%&n{`~*g5&%QsvR0>fSq{qx)uL9Bb@cn;=t=IlTECK~FE64$iV4t$E zz8q1`cikcr^(SKyZtJt%$}CPj3AE|K|q-3o!rv`Uy;Aph5s>;2mH} zUw#g=I-GavA26W-Ed!r zMMusf*H7GP;~@fo5*IdJzs!=1Mb;NS#du#chYLHa-z zgW_3Hl!@Wi*}V+BLb6A;Oo)F5(+?0pOemE(k6_rd%g25In=uUXBB1=t2+khhq7i8D z%#;5aKK@`}`1*^1VbxVgh%mE33Ku43NNxbBXM`3w^1_S^-#&d{_;CODPcA;;C}g_; z0tll%4k((R{Neq}nWh2x%wPYpGraueE=yb3bnAF#mq z3ycjA2IX53ZeY4${K;@`)5O1gf@0~L`jh4&+XE0lSX&^z1v94t^IfK~cPisQCSaxU zl>uC6fC>d>SQ!rV+5f)~OF`|ge_+cYj*$Q+PzGRHxww7ye@-^`>6<5|XQSHz5I{KF zT!BS%Yd^hvQmmMLy z2NjRMzA-$#dzInQ<--h&zkfdA6_(Ci-5Iw9m)QUTgkdowBO^N~cY(?jAO;l^tWJ@Y z$v{;}zkhs{WaklL=HeFx20IftnEwN7fp4E)G5q-Y{x2Il*K?rYg8eHy=YtA0P^AZ| zae??J&>ob=K0p9rvzQxHo&YhZCgB8P4wyqYxOlm=EWF)0x%u@N82__C+E|Q#eti9S z>Dq~{JAZup{0(Li5dVN$4iftcwC5|bJpcj3I8c2jfB<4*7$5);U;tYw!yWp>&+`BP N002ovPDHLkV1m;}_^$u} literal 0 HcmV?d00001 diff --git a/skins/default/images/display/info.png b/skins/default/images/display/info.png new file mode 100644 index 0000000000000000000000000000000000000000..85462e4b93b466fdb911863f38bf5b4b3c790a95 GIT binary patch literal 2162 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 literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/abcard.png b/skins/default/images/icons/abcard.png new file mode 100644 index 0000000000000000000000000000000000000000..d0d850044b5e96f14310fdc20fc8b75064019167 GIT binary patch literal 441 zcmV;q0Y?6bP)Js`gNOH=Z_fKHMggGw73JR~`_=&t)5l#yJt;|S@1U0vJy)_7Pw-{K z`9kfrj$FQgxB5H3{|1fdxsuq%rj$e?YcPUAo(-poeBm66OD4kM2}v{>1_Hww;7!+3ZK! zGHFE5mCP-ee3?ugAru-%ATY)=nM&ia`XqQpMVu?_Oe1>j62k~`fd}17z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;2T4RhRCwBA`2YVu10@(BfEXw>03d*fQq+%*YhQbL`z?}_S1@vM zb6?=<=J9}mfq@OA79fByG*?#D@=l#T<7#bf{oaVkDC^a0*1Y!f51a|qpasOzK+NLo z;`W=Hht~k49w2~FG#3_?a88*r?dsZf>yLSQdArp&G`&ntNuQyoZy4(0>Rtp=Gi&yo z3TGF0kP8femI{!mpa7f1F z$y3Wcy?owVS=;ylHEV$M0R#}-fZDo-y?uQXj~W;nIRIVqDm5(=tT`|!_+3a?c)p#z zLye=e+ea&F+W??uJs{=+=>rHLu;!4k2#tcmqHnTt^12?L-b(`lLpFgl`}q353kVF( zv$eCYwRdp(Xklp`h^!fe0Rjk21O|opM@Ge51xW$}EX^`ons=O?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hT@dAc};RNPAX^Z&m+^G*hZ1_{lJJOU0PnQR;iT_(&d0t}PZ*gvmZ!~dlQ@vZ;J{#L7{I^)RFw`=&&Y;VI~&8s`=-yY?fmKkw3Wfr L)z4*}Q$iB}gTFvX literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/flagged.png b/skins/default/images/icons/flagged.png new file mode 100644 index 0000000000000000000000000000000000000000..58e3e1c2ddffd559ad69f4638d1acd3b70a47463 GIT binary patch literal 514 zcmeAS@N?(olHy`uVBq!ia0vp^{2?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx-l>?R(QHNhE&{2`tkq2J@ZZpg$4iR4}^8@ooQ zF_wqt-(*RNSI>Nlzy05}^WgvFEU*8kB_;lu zGkf(28_w{(@W`UzQ#OdQU|d3A!`E-7c)uWa%0PWdRu#Pe)1|D82u>CDBTfom85msxk1=oPe39GjlBgHDB7D?E0$IWF(w<` zyC};p?C!lYcjnHSW5KcpgB2(FlPS*p=l_y(jH+^zYF<9Jx3`~8CX;vnHniLAwe|J& zz5hC>DyquP&d!fK&-JoG2zqpMq??oH&*RtWP*mY*Z!z1~zgwiIi2s z`9y2J#qVwpF#VZq4}SZ}`f zj>mkx7wHWuLVYpKxrFyZ2tpl%D2bM4L~k*s(F4egF{aSGFDCj* z@Kbh)3MNBhz>o8RF~&53?9zj-MUSz3Xb>R ww1Lb32ABg{Q>4aJ=DO1XWGV+#=BDTT2Z?gAQO_H^IRF3v07*qoM6N<$g7q~eUH||9 literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/folder-inbox.png b/skins/default/images/icons/folder-inbox.png new file mode 100644 index 0000000000000000000000000000000000000000..995ca81284889daf448d37e64ac36229c91b9bf9 GIT binary patch literal 586 zcmV-Q0=4~#P)eP^2h*(AM@AX)B1)XrrLelp<(- zk)kp9jtdAb(M5sVe9m0M;#xE$vN)M!=FB%a=a;bow*QfB-vF*|&v8dnGkcNr)&V*? zyDuwVADdfS|CHj@5Z=BzKLQjt( zy>)D5{2{`0#jC+&x}gZjT%rT`sq5pZ1O}v9EmE-_NvH9XWdJfY6~6Cr=%;UvM1$ Y1;Xdy_rq*_qyPW_07*qoM6N<$f<{9 literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/folder-junk.png b/skins/default/images/icons/folder-junk.png new file mode 100644 index 0000000000000000000000000000000000000000..06fbd49d5793fa7a3ec812243533ac67d6e55aec GIT binary patch literal 800 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 FV1l4SUR?kH literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/forwarded.png b/skins/default/images/icons/forwarded.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea246f8ed5c77c799e20757dde8615474525d27 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^{2?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hU0^mK6yskoK&4H6m`c?29pGTAs3_Ds6G%=h(Cb$$Vd7L)(%kFGkL z>GYLTXt*G{nXyn)K%V*0`GB(uH4GiC7fhL11a>`J>LGREqgcsV2F8{(7p41;9lntR zG$!TjTLbBa8#5&Afr>Ug(_4{Lt+Mgt4<-?Xh6$#-olIv7N}mVnkV`0a*u&H@vlC?h yjYrp*JBk}3L^>)zfSl4bN!@`VaEYYC0S4Z4O|zcQd@2caJcFmJpUXO@geCxe-Dj-; literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/plus.gif b/skins/default/images/icons/plus.gif new file mode 100755 index 0000000000000000000000000000000000000000..854b5eb340f954c11ce107d9dfdd5f6d6a17dbea GIT binary patch literal 93 zcmZ?wbhEHb?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hU0_H=O!skoK&4H6m`c?29pGTAs3)-+vS=KEUJ&DeoqVfG`IM^_#G z%$GRJz}T`TkfVdY!Nlofx`G|sk);l2+I)d(6tnL&EfJK}Ke|j(q2WTVUC(ib{1TAz z>*pPANt|?j`(hR&6GwQ4zgyC6XVdb9tC=|zniRRNq_ACm)1}8Q;Lu`X#Qc#tyxDGm+| z0s`HWQW*jk^9sbXK2mqE=~ZEFkSb~Xp(60V{n2>`9rrFqQIA=P7BfYdV>U_%cyuw& zarh(V`B`3JnwqJ=;t4z}l-0$qOynt0H5FrO{9!hUaeW7u%L1h|g}6plhQuEX8Z{pz zCv>_S^Y|Y~KMJ3tIUkYdZb=3VtABRI@VTYE13Hnx)78&qol`;+ E0M{i{%>V!Z literal 0 HcmV?d00001 diff --git a/skins/default/images/icons/unread.png b/skins/default/images/icons/unread.png new file mode 100644 index 0000000000000000000000000000000000000000..31f640632c586be9638988e26f8063d20b4fa45d GIT binary patch literal 460 zcmeAS@N?(olHy`uVBq!ia0vp^{2?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx-l>?I(fP{hE&{2`t$$4J@ZZmg@zdySb0{<87XgM-q?AV!GXar(a?Z*MS#ev9ek?- znLJV#X|r%B;UI$%q#-RMK;X5AK8MW7uFp~+pHdN*=`2V znTo$7nO>#WY>RLBCHcgat%1Rb?`?zv8|OWiN74>|WIHS;Iz=-}&2VzqBav}Hzkwmi z#ebed^P+|jL4oVcAH@{P*dB2z*qxYvB8!oUBUu#?FE literal 0 HcmV?d00001 diff --git a/skins/default/images/listheader_aqua.gif b/skins/default/images/listheader_aqua.gif new file mode 100644 index 0000000000000000000000000000000000000000..59f44ea98b950b44cdf2f4a7b1e81ac43de7e203 GIT binary patch literal 270 zcmZ?wbhEHblw%NKIKsei_Uzer@7}$7_3Fio7jNDI;hS^k&YwGX?(N$*pFe-PaN+!o z8#jOgpFe-TaN)xB8#i9Pdj0<0yB9BCo;!Q?*|TRKK76=!>(-YqU(TF4!+;Ga{$v3Q z>wrj*oeZqq4^;b7GUsKiT9@;BpQq0GlH~gpac^th|346$;-Mp@+_%{V4Lxhgz?DH8X6VB#s*Zi=f#&7*$-5-1E&cA;w-_Y39%-!17-oe$? z-P6n0KVjk|wkcDmv9Zr&=b1Bi-hAPOixw{tW>~&r=g-faG2_XTCzB^ln$X{W`0%0Lo}SycZ|~i^=jzp~ z+qP|=H*fB#lcyd$c(8Qw;#DhGO`SY>!-fqE!~q?UGLT&itaB9<`cg9IX;`kwdA+aT zj#WwS{fc$BJ>LI6u%O^autfifB}FG)*ydeWQR21MP5Q=~veR#?wzh4k@X?!n{&7py z*}UEN3%(`!t-t;LM@{UZ_rL!)G&a=6d(PaM zObZq+TD)ZGvPFU`SFK*NcHR2bteZA(*}84}jxFrF_w3!b|G>dRhmRaRcKpQ2QwJ0o FtO2Tsh;sk{ literal 0 HcmV?d00001 diff --git a/skins/default/images/listheader_light.gif b/skins/default/images/listheader_light.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d9e6cac0888596ddbb06c87ce0e4103c4442805 GIT binary patch literal 261 zcmZ?wbhEHblw%NKIKsg2<;$0kA3r{P`0(Dnd(WOdfBN+4?OV6rym@oy&YhPpU%r0* z>ixTSj~_q&@ZrOQ2M<1f{(ST1O$Jhc;!hT^avcx}vXg&R z?wEVOV%>G$_x}$p*sxtgs{h22O%)kd^DnH}vT{Y#`WtJu&3aL_|G|bG-Ws#dzu2-X zCS&*g4?FgpU2*&Uk3IYJUi|*w(AZSV*V@+J(b?6?+}qbbVdA7-j;Yh8&zL!DD%;$7 b^A{{!G*@8hvgIpQu3Eij?Yi~r6&b7nD|~;u literal 0 HcmV?d00001 diff --git a/skins/default/images/mailbox_list.gif b/skins/default/images/mailbox_list.gif new file mode 100644 index 0000000000000000000000000000000000000000..d53de17f1d6736d0c7374e327c01406210bedfce GIT binary patch literal 207 zcmV;=05JbYNk%w1VH5xo0J8u9@9*#V`T6?#`tI)T>+9?F_4WPz{qXSc?d|Qw!^8IW z_WS$$^78WY^YiiX@&Et-A^8LV00000EC2ui02BZc000Dh@X1MQT{!E#mH%KEHe|yv zWqGEg;}p*My08q-$I%?Fp6|V#kH6}C@2beJN};M^8*3`0fT{nf`o#F28)c1j*btD6Oxh=lm-@=nhBhp Jo}Zr)06QA8ZHoW^ literal 0 HcmV?d00001 diff --git a/skins/default/images/mailbox_selected.gif b/skins/default/images/mailbox_selected.gif new file mode 100644 index 0000000000000000000000000000000000000000..bbc2265e0299e6d454b02ac34179a95e9e1928b2 GIT binary patch literal 158 zcmV;P0Ac?}Nk%w1VH5xo0J8u9s;a7_q@=O2vA({(p`oE?XJ@XiuDH0ksHmv5wY8$6 zqP)DkrlzK|v$L(Ot-ZayEC2ui02BZc000D2aLGw)9XRW~pZ{PO9%N~rXsVh?>%K7D z%yezrLay&TZ~VZZa7Zi$9mu3|xdb?$&}bAvty-^FhIY&Cb_3wBcsy2^&**fTz;3(W M?}B_zuh%00J1EFb+-xjo{#6_mF?^>2R?u8 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 E4}<%oK>z>% literal 0 HcmV?d00001 diff --git a/skins/default/images/roundcube_logo.gif b/skins/default/images/roundcube_logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..b77fd3d0b99efde94eeddaf871d44ad32b42462e GIT binary patch literal 2284 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 Ce7d6m literal 0 HcmV?d00001 diff --git a/skins/default/images/roundcube_logo_print.gif b/skins/default/images/roundcube_logo_print.gif new file mode 100644 index 0000000000000000000000000000000000000000..8fbf6a8eb1ecbf928377d4b6105ab541d8a86212 GIT binary patch literal 2400 zcmV-m37_^yNk%w1VYUD=0OkMyc6N3uDk`R?rkRgu$#v|C$S z@bK{9;NbfD`cqR=+}zwUGBQm~P1xAj%F4>n(9o%=slvj-g@uL2#>U>>-o(VjzP`TN z+S=6A)WE>N=;-M@JUqw{xdW*G&D2W+1b<6 z(r^*EBOTH!m+Q<>lq)=jZqL_TS&%r>CdL$j8ge%c!WR`T6;;udmF@%lG&9G&3~J z%gn2*tG~a$o1C2c`}>=loAUAU@$vD;$j8*w)8pgg$;rvr*w?eOv)$g^*x1+G+uPaN z+Q-MoxVN~qwYBr}^Tox*;o;%o;^N}s;kUQ9(b3T;C@3>CGynhpA^8LV00000EC2ui z0JZ=!000O7fPaF6goTEOh>41ejE#NPkC6(=w!hYHYTU2#x5kwUg z6fuSjc*ygmmo(}y10OvYF~b5}EKZY0fJ0m zFt^bf@-Vmx2$C(h=MvJv1wT~U>=k+nQpOjiBJwT>JGx-R0;Xbs#sU#k>c9~J^zlK# zg&a_T9~=B(L9PfCg2vGlH2mzx%$`f}vKeAV2~MDm|h@19ntk#}|i`!9@!n5Fl{SKP0Wl*nd3jN5~2I0RSQtY>TzS9p^eh zz!ZeV!3~1&2UDPc0wREb zIar_r^|1mMJg^}UFklP_7{CQKK!E^s&jB@z;}3vGKOG)0SNZ!xxrEg#La+gOxzeHp z34wsfH8GGV$YbY5CM>G~l3LT-l>^6x0?ajX5CsT%?+;}^|-7b!>oFk`7g*^k6TESxjSwO&jeZL^cbt%`eq~na$i451>iT4Q{WRHFRSH6k!1kY|{dvJAejg zqk($XQxNuKLpO`{zi$5F0Q|(KwK6bI^>jg#;S^^%q4_>^!p{NgOhf|`zyLu^^aO*r z=K%)5fCG3`5Cb^D0T2MhKV)D4Yx}2(w26fQD3YTpRitTbV9SK+3Jg0~C!eH zQ(YxNr>pGgLkqwNESzAX?R;wj&b3hl*b}4!$m;~Mseuz9z*$@M>mW{=R4h~!q!sYwFk`pf#;(oq`!=#|RCe6rV8ltZYGBQPKL!2t_^M0Gx$}l?K(L9-Y9aU>j5Q zkRSwPb!=qI>4(Y2k^(Py!~r(t*^;U>uX)AmRNs0)@>(^U6g_E569-eTqIUqt(EsUW*_nF;w=noWtgGjtq5C^VAH~pDR2JDxU{k3hqP66!Q8lqrc$t;b7r-0r5;t~QA z=3sz}DFruV_&9bD007wNLH;Im2QaRpABtJH5uCU|9$3Q(1aN^5NP)u~PAFtW9LoZ< z?8Xk#K?U$|0yC^J2H54Wi*?0=5JO+9?7?d|#b`TYF+=;-L_>FMn3?DX{X{r&y=`ughX z>hA9D@9*#S_V)h%{_ybd^YioZ@$vHV^8f$;nVFgY|Nj6000000000000000000000 z000000000000000A^8LW000#LEC2ui0Av6c000I5U`35&X`X1Ru59a~;v~;>ZQppV z?|grcj-YTzEE)Zo3x(U z*Uru051)(42P44i?CtIm@BRMu*8KGYNbrHcb^H!0ltA#)FMz-x zHk7bV-iQSlGiuz(k>kCO_b>(+NwQ>sj3YaQW&{aRqsfvZ6v&)Ov!+d(0CMWwsk3H* zpFo2asL8Xa(VaGh1|6ZasZ*sllLjR~wW?JDK%;8Csr0JV5eCAF9ZR-s*#KtKhCQlN z?8}#G)v_JIvaVeQDplTXhLLaHza8x+RCuu9HHC%~2kbYP@IPv#2+xE3X&Pm7vo4#; JT#7;n06US=89x93 literal 0 HcmV?d00001 diff --git a/skins/default/images/tab_pas.gif b/skins/default/images/tab_pas.gif new file mode 100644 index 0000000000000000000000000000000000000000..26adabf0022789e572f6cd54e4f2777971a755b0 GIT binary patch literal 511 zcmVFw?9_xJbg?CkjX`1bbp@9*#G>gxXf z{`&g*>+9?N{r&Lp@b2#J_4W1h^YiiX@$&NWnVFgY|Nj6000000000000000000000 z000000000000000A^8LW000#LEC2ui0Av6c000I5U?q-ZX`X1Ru59bRa4gR&W#4$N z?|kq7z~HVzX&8^lq;kn@I-k(!(x#|duh^`1%k6rr(&JZQTbR%2w0g~MyWi%3d`_>+ z;R_pN&+q&HfPsR8gnI{vh>41ag%CCqkdcy;l$Dm3n3<3foSmMZoSGAlqNS#%m!PVi zm=dm}sIjt|o&dJDx2%^Ays)#7yurf4rNhR&lAXBAy2lO(&^E5q)YaD2&d%4=+0Lik z&Zt=?zap*rRB9`ztdwkc9SaJ=va`0xMlg#O zty;Bv^fYQjV3A$AcJt~@M3;aK1Aqey9!$8fox_CRoundCube Webmail + + \ No newline at end of file diff --git a/skins/default/includes/settingscripts.html b/skins/default/includes/settingscripts.html new file mode 100644 index 000000000..b7699708d --- /dev/null +++ b/skins/default/includes/settingscripts.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/skins/default/includes/settingstabs.html b/skins/default/includes/settingstabs.html new file mode 100644 index 000000000..ef561d9f4 --- /dev/null +++ b/skins/default/includes/settingstabs.html @@ -0,0 +1,3 @@ +

diff --git a/skins/default/includes/taskbar.html b/skins/default/includes/taskbar.html new file mode 100644 index 000000000..b0ebc552c --- /dev/null +++ b/skins/default/includes/taskbar.html @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/skins/default/mail.css b/skins/default/mail.css new file mode 100644 index 000000000..239024c73 --- /dev/null +++ b/skins/default/mail.css @@ -0,0 +1,647 @@ +/***** RoundCube|Mail mail task styles *****/ + + +#messagetoolbar +{ + position: absolute; + top: 20px; + left: 200px; + right: 250px; + height: 35px; +/* border: 1px solid #cccccc; */ +} + +#messagetoolbar a +{ + padding-right: 10px; +} + +#messagetoolbar select +{ + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; + color: #333333; +} + +#messagetoolbar select.mboxlist +{ + position: absolute; + left: 300px; + top: 10px; +} + +#messagetoolbar select.mboxlist option +{ + padding-left: 15px; +} + +#messagetoolbar select.mboxlist option[value="0"] +{ + padding-left: 2px; +} + +#listcontrols +{ + position: absolute; + left: 200px; + bottom: 60px; + height: 16px; + width: 400px; +} + +#listcontrols a, +#listcontrols a:active, +#listcontrols a:visited +{ + color: #999999; + font-size: 11px; + text-decoration: none; +} + +#listcontrols a.active, +#listcontrols a.active:active, +#listcontrols a.active:visited +{ + color: #CC0000; +} + +#listcontrols a.active:hover +{ + text-decoration: underline; +} + +#messagecountbar +{ + position: absolute; + top: 35px; + right: 60px; + width: 250px; + height: 20px; + text-align: right; +} + +#messagecountbar span +{ + font-size: 11px; + color: #333333; +} + +#messagepartcontainer +{ + position: absolute; + top: 80px; + left: 20px; + right: 20px; + bottom: 20px; +} + +#mailcontframe +{ + position: absolute; + top: 60px; + left: 200px; + right: 40px; + bottom: 80px; + border: 1px solid #999999; + background-color: #F9F9F9; + overflow: auto; + /* css hack for IE */ + width: expression((parseInt(document.documentElement.clientWidth)-240)+'px'); + height: expression((parseInt(document.documentElement.clientHeight)-140)+'px'); +} + + +#messagepartframe +{ + border: 1px solid #999999; + background-color: #F9F9F9; +} + + +#partheader +{ + position: absolute; + top: 10px; + left: 220px; + height: 40px; +} + +#partheader table td +{ + padding-left: 2px; + padding-right: 4px; + vertical-align: middle; + font-size: 11px; +} + +#partheader table td.title +{ + color: #666666; + font-weight: bold; +} + +#rcmdraglayer +{ + width: 300px; + border: 1px solid #999999; + background-color: #F9F9F9; + padding-left: 8px; + padding-right: 8px; + padding-top: 3px; + padding-bottom: 3px; + font-size: 11px; + opacity: 0.6; + -moz-opacity: 0.6; +} + + +/** mailbox list styles */ + +#mailboxlist-header +{ + position: absolute; + top: 80px; + left: 20px; + width: 140px !important; +/* width: 162px; */ + height: 13px; + padding: 3px 10px 2px 10px; + background-color: #EBEBEB; + background-image: url(images/listheader_aqua.gif); + border: 1px solid #CCCCCC; + color: #333333; + font-size: 11px; + font-weight: bold; +} + +#mailboxlist +{ + position: absolute; + top: 100px; + left: 20px; + width: 160px; + height: auto; + margin: 0px; + padding: 0px; + border: 1px solid #CCCCCC; + background-color: #F9F9F9; + list-style-image: none; + list-style-type: none; +} + +#mailboxlist li +{ + height: 18px; + font-size: 11px; + background: url(images/icons/folder-closed.png) no-repeat; + background-position: 10px 1px; + border-bottom: 1px solid #EBEBEB; +/* IE 5.5 margin-left: -16px; */ +} + +#mailboxlist li.inbox +{ + background-image: url(images/icons/folder-inbox.png); +} + +#mailboxlist li.sent +{ + background-image: url(images/icons/folder-sent.png); +} + +#mailboxlist li.junk +{ + background-image: url(images/icons/folder-junk.png); +} + +#mailboxlist li.trash +{ + background-image: url(images/icons/folder-trash.png); +} + +#mailboxlist li a +{ + display: block; + padding-left: 32px; + padding-top: 2px; + padding-bottom: 2px; + text-decoration: none; +} + +#mailboxlist li, #mailboxlist li.unread +{ + /* background-image: url(images/mailbox_list.gif); */ +} + +#mailboxlist li.unread +{ + font-weight: bold; +} + +#mailboxlist li.selected +{ + background-color: #929292; + border-bottom: 1px solid #898989; +} + +#mailboxlist li.selected a +{ + color: #FFF; + font-weight: bold; +} + + +/** message list styles */ + +body.messagelist +{ + margin: 0px; + background-color: #F9F9F9; +} + +#messagelist +{ + width: 100%; + table-layout: fixed; + /* css hack for IE */ + width: expression(document.getElementById('mailcontframe').clientWidth); +} + +#messagelist thead tr td +{ + height: 20px; + padding-top: 0px; + padding-bottom: 0px; + padding-left: 2px; + padding-right: 4px; + vertical-align: middle; + border-bottom: 1px solid #999999; + color: #333333; + background-color: #EBEBEB; + background-image: url(images/listheader_aqua.gif); + font-size: 11px; + font-weight: bold; +} + +#messagelist tbody tr td +{ + height: 16px !important; + height: 20px; + padding: 2px; + padding-right: 4px; + font-size: 11px; + white-space: nowrap; + border-bottom: 1px solid #EBEBEB; + cursor: pointer; +} + +#messagelist tr td.icon +{ + width: 16px; +} + +#messagelist tr td.subject +{ + overflow: hidden; + text-align: left; +} + +#messagelist tr td.size +{ + width: 60px; + text-align: right; +} + +#messagelist tr td.from, +#messagelist tr td.to +{ + width: 180px; + overflow: hidden; +} + +#messagelist tr td.date +{ + width: 110px; +} + +#messagelist tr.message +{ + background-color: #FFFFFF; +} + +/* +#messagelist tr.odd +{ + background-color: #F9F9F9; +} +*/ + +#messagelist tr.unread +{ + font-weight: bold; + background-color: #FFFFFF; +} + +#messagelist tr.selected td +{ + font-weight: bold; + color: #FFFFFF; + background-color: #CC3333; +} + +#messagelist tr.selected td a.rcmContactAddress +{ + color: #FFFFFF; +} + + +/** message view styles */ + + +#messageframe +{ + position: absolute; + top: 70px; + left: 200px; + right: 40px; + /* css hack for IE */ + margin-bottom: 50px; + width: expression(document.body.clientWidth-240); +} + +table.headers-table +{ + width: 100%; + background-color: #EBEBEB; + table-layout: fixed; + +} + +table.headers-table tr td +{ + font-size: 11px; + border-bottom:1px solid #FFFFFF; +} + +table.headers-table td.header-title +{ + width: 70px; + color: #666666; + font-weight: bold; + text-align: right; + padding-right: 4px; +} + +table.headers-table tr td.subject +{ + width: 95%; + font-weight: bold; +} + +#attachment-list +{ + margin: 0px; + padding: 0px 0px 0px 68px; + height: 18px; + list-style-image: none; + list-style-type: none; + background-color: #DFDFDF; + background: url(images/icons/attachment.png) no-repeat #DFDFDF; + background-position: 52px 1px; + border-bottom: 1px solid #FFFFFF; +} + +#attachment-list li +{ +/* display: block; */ + float: left; + height: 18px; + font-size: 11px; + padding: 2px 10px 0px 10px; +} + +#attachment-list li a +{ + text-decoration: none; +} + +#attachment-list li a:hover +{ + text-decoration: underline; +} + +#messagebody +{ + min-height: 300px; + margin-top: 10px; + margin-bottom: 50px; + background-color: #FFFFFF; + border: 1px solid #cccccc; + border-top: none; +} + +div.message-part +{ + padding: 8px; + padding-top: 10px; + border-top: 1px solid #cccccc; + overflow: hidden; +} + +div.message-part a +{ + color: #0000CC; +} + +div.message-part pre +{ + margin: 0px; + padding: 0px; +} + + +#remote-objects-message +{ + display: none; + height: 20px; + min-height: 20px; + padding: 10px 10px 6px 46px; + margin-top: 8px; +} + +#remote-objects-message a +{ + color: #666666; + padding-left: 10px; +} + +#remote-objects-message a:hover +{ + color: #333333; +} + + +/** message compose styles */ + +#priority-selector +{ + position: absolute; + left: 200px; + top: 10px; +} + +#compose-container +{ + position: absolute; + top: 70px; + left: 200px; + right: 40px; + bottom: 60px; + padding: 0px; + margin: 0px; + /* css hack for IE */ + width: expression(document.documentElement.clientWidth-240); + /* height: expression((parseInt(document.documentElement.clientHeight)-130)+'px'); */ +} + +/* +#compose-headers +{ + position: absolute; + top: 70px; + left: 200px; + height: 84px; + border-top: 1px solid #cccccc; + overflow: auto; +} + +#compose-headers td +{ + padding-top: 1px; + padding-bottom: 1px; + border-right: 1px solid #cccccc; + border-bottom: 1px solid #cccccc; +} +*/ + +#compose-headers +{ + width: 100%; +} + +/* +#compose-headers td +{ + width: 100%; +} +*/ + +#compose-headers td.top +{ + vertical-align: top; +} + +#compose-headers td.title, +#compose-subject td.title +{ + width: 80px !important; + color: #666666; + font-size: 11px; + font-weight: bold; + padding-right: 10px; + white-space: nowrap; +} + +#compose-headers td.add-button +{ + width: 40px !important; + text-align: right; + vertical-align: bottom; +} + +#compose-headers td.add-button a +{ + color: #666666; + font-size: 11px; + text-decoration: none; +} + +#compose-headers td textarea +{ + width: 100%; + height: 40px; +} + +#compose-headers td input +{ + width: 100%; +} + +#compose-cc, +#compose-bcc, +#compose-replyto +{ + display: none; +} + +#compose-body +{ + margin-top: 10px; + width: 100% !important; + width: 95%; + height: 95%; + min-height: 400px; + font-size: 9pt; + font-family: "Courier New", Courier, monospace; +} + +#compose-attachments +{ + position: absolute; + top: 100px; + left: 20px; + width: 160px; +} + +#compose-attachments ul +{ + margin: 0px; + padding: 0px; + border: 1px solid #CCCCCC; + background-color: #F9F9F9; + list-style-image: none; + list-style-type: none; +} + +#compose-attachments ul li +{ + height: 18px; + font-size: 11px; + padding-left: 26px; + padding-top: 2px; + padding-right: 4px; + background: url(images/icons/attachment.png) no-repeat; + background-position: 4px 1px; + border-bottom: 1px solid #EBEBEB; + white-space: nowrap; + overflow: hidden; +} + +#attachment-form +{ + position: absolute; + top: 150px; + left: 20px; + z-index: 200; + padding: 8px; + visibility: hidden; + border: 1px solid #CCCCCC; + background-color: #F9F9F9; +} + +#attachment-form input.button +{ + margin-top: 8px; +} + + diff --git a/skins/default/pngbehavior.htc b/skins/default/pngbehavior.htc new file mode 100644 index 000000000..553699a2f --- /dev/null +++ b/skins/default/pngbehavior.htc @@ -0,0 +1,52 @@ + + + + \ No newline at end of file diff --git a/skins/default/print.css b/skins/default/print.css new file mode 100644 index 000000000..ac184db9d --- /dev/null +++ b/skins/default/print.css @@ -0,0 +1,111 @@ +/***** RoundCube|Mail message print styles *****/ + +body +{ + background-color: #ffffff; + color: #000000; + margin: 2mm; +} + +body, td, th, span, div, p, h3 +{ + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 9pt; + color: #000000; +} + +h3 +{ + font-size: 18px; + color: #000000; +} + +a, a:active, a:visited +{ + color: #000000; +} + +#header +{ + margin-left: 5mm; + margin-bottom: 3mm; +} + +#messageframe +{ + position: relative; +} + +table.headers-table +{ + table-layout: fixed; +} + +table.headers-table tr td +{ + font-size: 9pt; +} + +table.headers-table td.header-title +{ + color: #666666; + font-weight: bold; + text-align: right; + vertical-align: top; + padding-right: 4mm; + white-space: nowrap; +} + +table.headers-table tr td.subject +{ + width: 90%; + font-weight: bold; +} + +#attachment-list +{ + margin-top: 3mm; + padding-top: 3mm; + border-top: 1pt solid #cccccc; +} + +#attachment-list li +{ + font-size: 9pt; +} + +#attachment-list li a +{ + text-decoration: none; +} + +#attachment-list li a:hover +{ + text-decoration: underline; +} + +#messagebody +{ + margin-top: 5mm; + border-top: none; +} + +div.message-part +{ + padding: 2mm; + margin-top: 5mm; + margin-bottom: 5mm; + border-top: 1pt solid #cccccc; +} + +div.message-part a +{ + color: #0000CC; +} + +div.message-part pre +{ + margin: 0; + padding: 0; + font-size: 9pt; +} diff --git a/skins/default/settings.css b/skins/default/settings.css new file mode 100644 index 000000000..7b4b88beb --- /dev/null +++ b/skins/default/settings.css @@ -0,0 +1,150 @@ +/***** RoundCube|Mail settings task styles *****/ + + +#tabsbar +{ + position: absolute; + top: 42px; + left: 220px; + right: 60px; + height: 22px; + border-bottom: 1px solid #999999; + white-space: nowrap; + /* css hack for IE */ + width: expression((parseInt(document.documentElement.clientWidth)-280)+'px'); +} + +span.tablink, +span.tablink-selected +{ + float: left; + width: 80px; + height: 17px !important; + height: 15px; + padding: 5px 10px 2px 10px; + background: url('images/tab_pas.gif') top left no-repeat; +} + +span.tablink-selected +{ + background: url('images/tab_act.gif') top left no-repeat; +} + +span.tablink a +{ + color: #555555; +} + +span.tablink a, +span.tablink-selected a +{ + text-decoration: none; +} + +#userprefs-box +{ + position: absolute; + top: 90px; + left: 20px; + width: 550px; + border: 1px solid #999999; +} + +#userprefs-box table td.title +{ + color: #666666; + padding-right: 10px; +} + +#identities-list, +#folder-manager +{ + position: absolute; + top: 90px; + left: 20px; +} + +#identities-table +{ + width: 500px; + border: 1px solid #999999; + background-color: #F9F9F9; +} + +#identities-table tbody td +{ + cursor: pointer; +} + +#identity-frame +{ + position: relative; + margin-top: 20px; + border: 1px solid #999999; +} + +#identity-details +{ + margin-top: 30px; + width: 500px; + border: 1px solid #999999; +} + +#identity-details table td.title +{ + color: #666666; + font-weight: bold; + text-align: right; + padding-right: 10px; +} + +#userprefs-title, +#identity-title, +div.boxtitle, +#subscription-table thead td +{ + height: 12px !important; + padding: 4px 20px 3px 6px; + border-bottom: 1px solid #999999; + color: #333333; + font-size: 11px; + font-weight: bold; + background-color: #EBEBEB; + background-image: url(images/listheader_aqua.gif); +} + +div.settingsbox +{ + width: 500px; + margin-top: 20px; + border: 1px solid #999999; +} + +div.settingspart +{ + display: block; + padding: 10px; +} + +#subscription-table +{ + width: 500px; + border: 1px solid #999999; +} + +#subscription-table tbody td +{ + padding-left: 6px; + padding-right: 20px; + white-space: nowrap; + border-bottom: 1px solid #EBEBEB; + background-color: #F9F9F9; +} + +/* +#subscription-table tbody td select +{ + width: 150px; +} +*/ + diff --git a/skins/default/templates/addcontact.html b/skins/default/templates/addcontact.html new file mode 100644 index 000000000..773e6085f --- /dev/null +++ b/skins/default/templates/addcontact.html @@ -0,0 +1,24 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + +
+ +
+ + +


+" class="button" onclick="history.back()" />  + +

+ +
+ + + + diff --git a/skins/default/templates/addidentity.html b/skins/default/templates/addidentity.html new file mode 100644 index 000000000..0875a99a8 --- /dev/null +++ b/skins/default/templates/addidentity.html @@ -0,0 +1,35 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + + +
+ + +

+ +
+
+ +
+ + +


+ +

+
+
+
+ + + + + diff --git a/skins/default/templates/addressbook.html b/skins/default/templates/addressbook.html new file mode 100644 index 000000000..99c2c8efb --- /dev/null +++ b/skins/default/templates/addressbook.html @@ -0,0 +1,37 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + +
+ + + + + +
+ +
+  + +
+ +
+ +
+ +
+ +
+ + + + + diff --git a/skins/default/templates/compose.html b/skins/default/templates/compose.html new file mode 100644 index 000000000..7ff5f3006 --- /dev/null +++ b/skins/default/templates/compose.html @@ -0,0 +1,118 @@ + + + +RoundCube|Mail :: <roundcube:label name="compose" /> + + + + + + + + +
+ +
+ + + + + +
+ +
+ +
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[Cc]
+[Bcc]
+ +
+ +
+ +
+ +
+
Attachments
+ +

+

+ +
+ + + + + + + + + diff --git a/skins/default/templates/editcontact.html b/skins/default/templates/editcontact.html new file mode 100644 index 000000000..b71836d5b --- /dev/null +++ b/skins/default/templates/editcontact.html @@ -0,0 +1,24 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + +
+ +
+ + +


+  + +

+ +
+ + + + diff --git a/skins/default/templates/editidentity.html b/skins/default/templates/editidentity.html new file mode 100644 index 000000000..07283f5be --- /dev/null +++ b/skins/default/templates/editidentity.html @@ -0,0 +1,37 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + + +
+ + +

+ +
+
+ +
+ + +


+  + +

+
+
+
+ + + + + + diff --git a/skins/default/templates/error.html b/skins/default/templates/error.html new file mode 100644 index 000000000..0b2d9b8b9 --- /dev/null +++ b/skins/default/templates/error.html @@ -0,0 +1,16 @@ + + + +RoundCube|Mail :: ERROR + + + + + + +
+$__page_content +
+ + + diff --git a/skins/default/templates/identities.html b/skins/default/templates/identities.html new file mode 100644 index 000000000..7ae2bf007 --- /dev/null +++ b/skins/default/templates/identities.html @@ -0,0 +1,23 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + +
+ + +

+
+ + + + + + diff --git a/skins/default/templates/login.html b/skins/default/templates/login.html new file mode 100644 index 000000000..7f44f5790 --- /dev/null +++ b/skins/default/templates/login.html @@ -0,0 +1,30 @@ + + + +Welcome to RoundCube|Mail + + + + + + + +
+
+ + +

"> + +

+
+ + + diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html new file mode 100644 index 000000000..2c47cb67f --- /dev/null +++ b/skins/default/templates/mail.html @@ -0,0 +1,50 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + +
+ + + + + +
+ +
+  + +
+ +
+ + +
+ +
+ +
+:  +  +  + +
+ + + + + diff --git a/skins/default/templates/managefolders.html b/skins/default/templates/managefolders.html new file mode 100644 index 000000000..99afd5c81 --- /dev/null +++ b/skins/default/templates/managefolders.html @@ -0,0 +1,38 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + +
+ +
+ + + +
+
+ +
+:  + + +
+
+
+ +
+ + + + + + diff --git a/skins/default/templates/message.html b/skins/default/templates/message.html new file mode 100644 index 000000000..aba6412db --- /dev/null +++ b/skins/default/templates/message.html @@ -0,0 +1,41 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + +
+ + + + + + + +
+ +
+  + +
+ +
+ + +
+ + + + +
+ + + + + diff --git a/skins/default/templates/messagepart.html b/skins/default/templates/messagepart.html new file mode 100644 index 000000000..924342f3f --- /dev/null +++ b/skins/default/templates/messagepart.html @@ -0,0 +1,22 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + +
+ +
+ + +
+ +
+ + + diff --git a/skins/default/templates/printmessage.html b/skins/default/templates/printmessage.html new file mode 100644 index 000000000..223c98b4d --- /dev/null +++ b/skins/default/templates/printmessage.html @@ -0,0 +1,18 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + +
+ + + +
+ + + diff --git a/skins/default/templates/settings.html b/skins/default/templates/settings.html new file mode 100644 index 000000000..b29734d5e --- /dev/null +++ b/skins/default/templates/settings.html @@ -0,0 +1,28 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + +
+
+ +
+ + +


+
+
+ + + + + + + diff --git a/skins/default/templates/showcontact.html b/skins/default/templates/showcontact.html new file mode 100644 index 000000000..1e24688dc --- /dev/null +++ b/skins/default/templates/showcontact.html @@ -0,0 +1,19 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + +
+ +
+ + +


+
+ + + diff --git a/skins/default/watermark.html b/skins/default/watermark.html new file mode 100644 index 000000000..85e53652a --- /dev/null +++ b/skins/default/watermark.html @@ -0,0 +1,12 @@ + + + + + + +
+ +
+ + + \ No newline at end of file diff --git a/temp/.htaccess b/temp/.htaccess new file mode 100644 index 000000000..8e6a345dc --- /dev/null +++ b/temp/.htaccess @@ -0,0 +1,2 @@ +Order allow,deny +Deny from all \ No newline at end of file