Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merged branch devel-api (from r2208 to r2387) back into trunk (omitti…

…ng some sample plugins)
  • Loading branch information...
commit cc97ea0559af1a92a54dbcdf738ee4d95e67d3ff 1 parent fb253ee
@thomascube thomascube authored
Showing with 3,466 additions and 1,270 deletions.
  1. +7 −1 config/main.inc.php.dist
  2. +37 −11 index.php
  3. +42 −0 plugins/additional_message_headers/additional_message_headers.php
  4. +44 −0 plugins/autologon/autologon.php
  5. +152 −0 plugins/database_attachments/database_attachments.php
  6. +146 −0 plugins/debug_logger/debug_logger.php
  7. +227 −0 plugins/debug_logger/runlog/runlog.php
  8. +39 −0 plugins/emoticons/emoticons.php
  9. +42 −0 plugins/example_addressbook/example_addressbook.php
  10. +72 −0 plugins/example_addressbook/example_addressbook_backend.php
  11. +144 −0 plugins/filesystem_attachments/filesystem_attachments.php
  12. +41 −0 plugins/http_authentication/http_authentication.php
  13. BIN  plugins/markasjunk/junk_act.png
  14. BIN  plugins/markasjunk/junk_pas.png
  15. +7 −0 plugins/markasjunk/localization/en_US.inc
  16. +28 −0 plugins/markasjunk/markasjunk.js
  17. +47 −0 plugins/markasjunk/markasjunk.php
  18. +49 −0 plugins/new_user_identity/new_user_identity.php
  19. +15 −0 plugins/password/localization/en_US.inc
  20. +15 −0 plugins/password/localization/pl_PL.inc
  21. +44 −0 plugins/password/password.js
  22. +160 −0 plugins/password/password.php
  23. +49 −0 plugins/show_additional_headers/show_additional_headers.php
  24. +6 −0 plugins/subscriptions_option/localization/en_US.inc
  25. +84 −0 plugins/subscriptions_option/subscriptions_option.php
  26. +9 −0 plugins/userinfo/localization/de_CH.inc
  27. +9 −0 plugins/userinfo/localization/en_US.inc
  28. +16 −0 plugins/userinfo/userinfo.js
  29. +53 −0 plugins/userinfo/userinfo.php
  30. +115 −0 plugins/vcard_attachments/vcard_attachments.php
  31. +10 −0 plugins/vcard_attachments/vcardattach.js
  32. +29 −1 program/include/html.php
  33. +1 −1  program/include/iniset.php
  34. +14 −11 program/include/main.inc
  35. +33 −11 program/include/rcmail.php
  36. +169 −0 program/include/rcube_addressbook.php
  37. +1 −0  program/include/rcube_config.php
  38. +2 −33 program/include/rcube_contacts.php
  39. +7 −4 program/include/rcube_html_page.php
  40. +20 −11 program/include/rcube_imap.php
  41. +13 −13 program/include/rcube_json_output.php
  42. +1 −1  program/include/rcube_ldap.php
  43. +3 −0  program/include/rcube_message.php
  44. +196 −0 program/include/rcube_plugin.php
  45. +312 −0 program/include/rcube_plugin_api.php
  46. +55 −57 program/include/rcube_template.php
  47. +17 −9 program/include/rcube_user.php
  48. +2 −2 program/include/rcube_vcard.php
  49. +396 −601 program/js/app.js
  50. +102 −128 program/js/common.js
  51. +2 −2 program/js/editor.js
  52. +57 −115 program/js/list.js
  53. +13 −5 program/lib/imap.inc
  54. +18 −18 program/steps/addressbook/func.inc
  55. +39 −35 program/steps/mail/attachments.inc
  56. +20 −30 program/steps/mail/compose.inc
  57. +92 −84 program/steps/mail/func.inc
  58. +48 −39 program/steps/mail/sendmail.inc
  59. +3 −1 program/steps/mail/show.inc
  60. +12 −0 program/steps/settings/func.inc
  61. +1 −0  program/steps/settings/manage_folders.inc
  62. +3 −0  program/steps/settings/save_prefs.inc
  63. +7 −0 skins/default/common.css
  64. +11 −19 skins/default/functions.js
  65. +2 −0  skins/default/includes/settingstabs.html
  66. +1 −0  skins/default/includes/taskbar.html
  67. +1 −1  skins/default/mail.css
  68. +20 −20 skins/default/splitter.js
  69. +2 −2 skins/default/templates/addressbook.html
  70. +1 −1  skins/default/templates/identities.html
  71. +1 −0  skins/default/templates/mail.html
  72. +1 −1  skins/default/templates/managefolders.html
  73. +1 −0  skins/default/templates/message.html
  74. +24 −0 skins/default/templates/plugin.html
  75. +4 −2 skins/default/templates/settings.html
View
8 config/main.inc.php.dist
@@ -35,6 +35,12 @@ $rcmail_config['log_dir'] = 'logs/';
// use this folder to store temp files (must be writeable for apache user)
$rcmail_config['temp_dir'] = 'temp/';
+// use this folder to search for plugin sources
+$rcmail_config['plugins_dir'] = 'plugins/';
+
+// List of active plugins. Add the name of a directory found in 'plugins_dir'
+$rcmail_config['plugins'] = array();
+
// enable caching of messages and mailbox data in the local database.
// this is recommended if the IMAP server does not run on the same machine
$rcmail_config['enable_caching'] = TRUE;
@@ -152,7 +158,7 @@ $rcmail_config['date_long'] = 'd.m.Y H:i';
$rcmail_config['date_today'] = 'H:i';
// add this user-agent to message headers when sending
-$rcmail_config['useragent'] = 'RoundCube Webmail/0.2-beta';
+$rcmail_config['useragent'] = 'RoundCube Webmail/0.3-beta';
// use this name to compose page titles
$rcmail_config['product_name'] = 'RoundCube Webmail';
View
48 index.php
@@ -2,7 +2,7 @@
/*
+-------------------------------------------------------------------------+
| RoundCube Webmail IMAP Client |
- | Version 0.2-20080829 |
+ | Version 0.3-20090419 |
| |
| Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| |
@@ -36,6 +36,9 @@
// init output class
$OUTPUT = !empty($_REQUEST['_remote']) ? $RCMAIL->init_json() : $RCMAIL->load_gui(!empty($_REQUEST['_framed']));
+// init plugin API
+$RCMAIL->plugins->init();
+
// set output buffering
if ($RCMAIL->action != 'get' && $RCMAIL->action != 'viewsource') {
// use gzip compression if supported
@@ -70,21 +73,29 @@
raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE);
}
+
+// trigger startup plugin hook
+$startup = $RCMAIL->plugins->exec_hook('startup', array('task' => $RCMAIL->task, 'action' => $RCMAIL->action));
+$RCMAIL->set_task($startup['task']);
+$RCMAIL->action = $startup['action'];
+
+
// try to log in
if ($RCMAIL->action=='login' && $RCMAIL->task=='mail') {
// purge the session in case of new login when a session already exists
- $RCMAIL->kill_session();
-
- // set IMAP host
- $host = $RCMAIL->autoselect_host();
+ $RCMAIL->kill_session();
+ $auth = $RCMAIL->plugins->exec_hook('authenticate', array(
+ 'host' => $RCMAIL->autoselect_host(),
+ 'user' => trim(get_input_value('_user', RCUBE_INPUT_POST)),
+ )) + array('pass' => get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'));
+
// check if client supports cookies
if (empty($_COOKIE)) {
$OUTPUT->show_message("cookiesdisabled", 'warning');
}
- else if ($_SESSION['temp'] && !empty($_POST['_user']) && !empty($_POST['_pass']) &&
- $RCMAIL->login(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '),
- get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host)) {
+ else if ($_SESSION['temp'] && !empty($auth['user']) && !empty($auth['host']) && isset($auth['pass']) &&
+ $RCMAIL->login($auth['user'], $auth['pass'], $auth['host'])) {
// create new session ID
unset($_SESSION['temp']);
rcube_sess_regenerate_id();
@@ -99,12 +110,22 @@
$RCMAIL->user->ID,
$_SERVER['REMOTE_ADDR']));
}
+
+ // restore original request parameters
+ $query = array();
+ if ($url = get_input_value('_url', RCUBE_INPUT_POST))
+ parse_str($url, $query);
+
+ // allow plugins to control the redirect url after login success
+ $redir = $RCMAIL->plugins->exec_hook('login_after', $query + array('task' => $RCMAIL->task));
+ unset($redir['abort']);
// send redirect
- $OUTPUT->redirect();
+ $OUTPUT->redirect($redir);
}
else {
$OUTPUT->show_message($IMAP->error_code < -1 ? 'imaperror' : 'loginfailed', 'warning');
+ $RCMAIL->plugins->exec_hook('login_failed', array('code' => $IMAP->error_code, 'host' => $auth['host'], 'user' => $auth['user']));
$RCMAIL->kill_session();
}
}
@@ -208,9 +229,14 @@
while ($redirects < 5) {
$stepfile = !empty($action_map[$RCMAIL->task][$RCMAIL->action]) ?
$action_map[$RCMAIL->task][$RCMAIL->action] : strtr($RCMAIL->action, '-', '_') . '.inc';
-
+
+ // execute a plugin action
+ if (eregi('^plugin.', $RCMAIL->action)) {
+ $RCMAIL->plugins->exec_action($RCMAIL->action);
+ break;
+ }
// try to include the step file
- if (is_file(($incfile = 'program/steps/'.$RCMAIL->task.'/'.$stepfile))) {
+ else if (is_file(($incfile = 'program/steps/'.$RCMAIL->task.'/'.$stepfile))) {
include($incfile);
$redirects++;
}
View
42 plugins/additional_message_headers/additional_message_headers.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Additional Message Headers
+ *
+ * Very simple plugin which will read additional headers for outgoing messages from the config file.
+ *
+ * Enable the plugin in config/main.inc.php and add your desired headers.
+ *
+ * @version 1.0
+ * @author Ziba Scott
+ * @website http://roundcube.net
+ *
+ * Example:
+ *
+ * $rcmail_config['additional_message_headers']['X-Remote-Browser'] = $_SERVER['HTTP_USER_AGENT'];
+ * $rcmail_config['additional_message_headers']['X-Originating-IP'] = $_SERVER['REMOTE_ADDR'];
+ * $rcmail_config['additional_message_headers']['X-RoundCube-Server'] = $_SERVER['SERVER_ADDR'];
+ * if( isset( $_SERVER['MACHINE_NAME'] )) {
+ * $rcmail_config['additional_message_headers']['X-RoundCube-Server'] .= ' (' . $_SERVER['MACHINE_NAME'] . ')';
+ * }
+ */
+class additional_message_headers extends rcube_plugin
+{
+ public $task = 'mail';
+
+ function init()
+ {
+ $this->add_hook('outgoing_message_headers', array($this, 'message_headers'));
+ }
+
+ function message_headers($args){
+
+ // additional email headers
+ $additional_headers = rcmail::get_instance()->config->get('additional_message_headers',array());
+ foreach($additional_headers as $header=>$value){
+ $args['headers'][$header] = $value;
+ }
+
+ return $args;
+ }
+}
View
44 plugins/autologon/autologon.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Sample plugin to try out some hooks.
+ * This performs an automatic login if accessed from localhost
+ */
+class autologon extends rcube_plugin
+{
+
+ function init()
+ {
+ $this->add_hook('startup', array($this, 'startup'));
+ $this->add_hook('authenticate', array($this, 'authenticate'));
+ }
+
+ function startup($args)
+ {
+ $rcmail = rcmail::get_instance();
+
+ // change action to login
+ if ($args['task'] == 'mail' && empty($args['action']) && empty($_SESSION['user_id']) && !empty($_GET['_autologin']) && $this->is_localhost())
+ $args['action'] = 'login';
+
+ return $args;
+ }
+
+ function authenticate($args)
+ {
+ if (!empty($_GET['_autologin']) && $this->is_localhost()) {
+ $args['user'] = 'me';
+ $args['pass'] = '******';
+ $args['host'] = 'localhost';
+ }
+
+ return $args;
+ }
+
+ function is_localhost()
+ {
+ return $_SERVER['REMOTE_ADDR'] == '::1' || $_SERVER['REMOTE_ADDR'] == '127.0.0.1';
+ }
+
+}
+
View
152 plugins/database_attachments/database_attachments.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Filesystem Attachments
+ *
+ * This plugin which provides database backed storage for temporary
+ * attachment file handling. The primary advantage of this plugin
+ * is its compatibility with round-robin dns multi-server roundcube
+ * installations.
+ *
+ * This plugin relies on the core filesystem_attachments plugin
+ *
+ * @author Ziba Scott <ziba@umich.edu>
+ *
+ */
+require_once('plugins/filesystem_attachments/filesystem_attachments.php');
+class database_attachments extends filesystem_attachments
+{
+
+ // A prefix for the cache key used in the session and in the key field of the cache table
+ private $cache_prefix = "db_attach";
+
+ /**
+ * Helper method to generate a unique key for the given attachment file
+ */
+ private function _key($filepath)
+ {
+ return $this->cache_prefix.md5(mktime().$filepath.$_SESSION['user_id']);
+ }
+
+ /**
+ * Save a newly uploaded attachment
+ */
+ function upload($args)
+ {
+ $args['status'] = false;
+ $rcmail = rcmail::get_instance();
+ $key = $this->_key($args['path']);
+ $data = base64_encode(file_get_contents($args['path']));
+
+ $status = $rcmail->db->query(
+ "INSERT INTO ".get_table_name('cache')."
+ (created, user_id, cache_key, data)
+ VALUES (".$rcmail->db->now().", ?, ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $data);
+
+ if ($status) {
+ $args['id'] = $key;
+ $args['status'] = true;
+ unset($args['path']);
+ }
+
+ return $args;
+ }
+
+ /**
+ * Save an attachment from a non-upload source (draft or forward)
+ */
+ function save($args)
+ {
+ $args['status'] = false;
+ $rcmail = rcmail::get_instance();
+
+ $key = $this->_key($args['name']);
+ $data = base64_encode($args['data']);
+
+ $status = $rcmail->db->query(
+ "INSERT INTO ".get_table_name('cache')."
+ (created, user_id, cache_key, data)
+ VALUES (".$rcmail->db->now().", ?, ?, ?)",
+ $_SESSION['user_id'],
+ $key,
+ $data);
+
+ if ($status) {
+ $args['id'] = $key;
+ $args['status'] = true;
+ }
+
+ return $args;
+ }
+
+ /**
+ * Remove an attachment from storage
+ * This is triggered by the remove attachment button on the compose screen
+ */
+ function remove($args)
+ {
+ $args['status'] = false;
+ $rcmail = rcmail::get_instance();
+ $status = $rcmail->db->query(
+ "DELETE FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $args['id']);
+
+ if ($status) {
+ $args['status'] = true;
+ }
+
+ return $args;
+ }
+
+ /**
+ * When composing an html message, image attachments may be shown
+ * For this plugin, $this->get_attachment will check the file and
+ * return it's contents
+ */
+ function display($args)
+ {
+ return $this->get_attachment($args);
+ }
+
+ /**
+ * When displaying or sending the attachment the file contents are fetched
+ * using this method. This is also called by the display_attachment hook.
+ */
+ function get_attachment($args)
+ {
+ $rcmail = rcmail::get_instance();
+
+ $sql_result = $rcmail->db->query(
+ "SELECT cache_id, data
+ FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key=?",
+ $_SESSION['user_id'],
+ $args['id']);
+
+ if ($sql_arr = $rcmail->db->fetch_assoc($sql_result)) {
+ $args['data'] = base64_decode($sql_arr['data']);
+ $args['status'] = true;
+ }
+
+ return $args;
+ }
+
+ /**
+ * Delete all temp files associated with this user
+ */
+ function cleanup($args)
+ {
+ $rcmail = rcmail::get_instance();
+ $rcmail->db->query(
+ "DELETE FROM ".get_table_name('cache')."
+ WHERE user_id=?
+ AND cache_key like '{$this->cache_prefix}%'",
+ $_SESSION['user_id']);
+ }
+}
View
146 plugins/debug_logger/debug_logger.php
@@ -0,0 +1,146 @@
+<?php
+
+/**
+ * Debug Logger
+ *
+ * Enhanced logging for debugging purposes. It is not recommened
+ * to be enabled on production systems without testing because of
+ * the somewhat increased memory, cpu and disk i/o overhead.
+ *
+ * Debug Logger listens for existing console("message") calls and
+ * introduces start and end tags as well as free form tagging
+ * which can redirect messages to files. The resulting log files
+ * provide timing and tag quantity results.
+ *
+ * Enable the plugin in config/main.inc.php and add your desired
+ * log types and files.
+ *
+ * @version 1.0
+ * @author Ziba Scott
+ * @website http://roundcube.net
+ *
+ * Example:
+ *
+ * config/main.inc.php:
+ *
+ * // $rcmail_config['debug_logger'][type of logging] = name of file in log_dir
+ * // The 'master' log includes timing information
+ * $rcmail_config['debug_logger']['master'] = 'master';
+ * // If you want sql messages to also go into a separate file
+ * $rcmail_config['debug_logger']['sql'] = 'sql';
+ *
+ * index.php (just after $RCMAIL->plugins->init()):
+ *
+ * console("my test","start");
+ * console("my message");
+ * console("my sql calls","start");
+ * console("cp -r * /dev/null","shell exec");
+ * console("select * from example","sql");
+ * console("select * from example","sql");
+ * console("select * from example","sql");
+ * console("end");
+ * console("end");
+ *
+ *
+ * logs/master (after reloading the main page):
+ *
+ * [17-Feb-2009 16:51:37 -0500] start: Task: mail.
+ * [17-Feb-2009 16:51:37 -0500] start: my test
+ * [17-Feb-2009 16:51:37 -0500] my message
+ * [17-Feb-2009 16:51:37 -0500] shell exec: cp -r * /dev/null
+ * [17-Feb-2009 16:51:37 -0500] start: my sql calls
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ * [17-Feb-2009 16:51:37 -0500] end: my sql calls - 0.0018 seconds shell exec: 1, sql: 3,
+ * [17-Feb-2009 16:51:37 -0500] end: my test - 0.0055 seconds shell exec: 1, sql: 3,
+ * [17-Feb-2009 16:51:38 -0500] end: Task: mail. - 0.8854 seconds shell exec: 1, sql: 3,
+ *
+ * logs/sql (after reloading the main page):
+ *
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ * [17-Feb-2009 16:51:37 -0500] sql: select * from example
+ */
+class debug_logger extends rcube_plugin
+{
+ function init()
+ {
+ require_once(dirname(__FILE__).'/runlog/runlog.php');
+ $this->runlog = new runlog();
+
+ if(!rcmail::get_instance()->config->get('log_dir')){
+ rcmail::get_instance()->config->set('log_dir',INSTALL_PATH.'logs');
+ }
+
+ $log_config = rcmail::get_instance()->config->get('debug_logger',array());
+
+ foreach($log_config as $type=>$file){
+ $this->runlog->set_file(rcmail::get_instance()->config->get('log_dir').'/'.$file, $type);
+ }
+
+ $start_string = "";
+ $action = rcmail::get_instance()->action;
+ $task = rcmail::get_instance()->task;
+ if($action){
+ $start_string .= "Action: ".$action.". ";
+ }
+ if($task){
+ $start_string .= "Task: ".$task.". ";
+ }
+ $this->runlog->start($start_string);
+
+ $this->add_hook('console', array($this, 'console'));
+ $this->add_hook('authenticate', array($this, 'authenticate'));
+ }
+
+ function authenticate($args){
+ $this->runlog->note('Authenticating '.$args['user'].'@'.$args['host']);
+ return $args;
+ }
+
+ function console($args){
+ $note = $args[0];
+ $type = $args[1];
+
+
+ if(!isset($args[1])){
+ // This could be extended to detect types based on the
+ // file which called console. For now only rcube_imap.inc is supported
+ $bt = debug_backtrace(true);
+ $file = $bt[3]['file'];
+ switch(basename($file)){
+ case 'rcube_imap.php':
+ $type = 'imap';
+ break;
+ default:
+ $type = FALSE;
+ break;
+ }
+ }
+ switch($note){
+ case 'end':
+ $type = 'end';
+ break;
+ }
+
+
+ switch($type){
+ case 'start':
+ $this->runlog->start($note);
+ break;
+ case 'end':
+ $this->runlog->end();
+ break;
+ default:
+ $this->runlog->note($note, $type);
+ break;
+ }
+ return $args;
+ }
+
+ function __destruct(){
+ $this->runlog->end();
+ }
+}
+?>
View
227 plugins/debug_logger/runlog/runlog.php
@@ -0,0 +1,227 @@
+<?php
+
+/**
+ * runlog
+ *
+ * @author Ziba Scott <ziba@umich.edu>
+ */
+class runlog {
+
+ private $start_time = FALSE;
+
+ private $parent_stack = array();
+
+ public $print_to_console = FALSE;
+
+ private $file_handles = array();
+
+ private $indent = 0;
+
+ public $threshold = 0;
+
+ public $tag_count = array();
+
+ public $timestamp = "d-M-Y H:i:s O";
+
+ public $max_line_size = 150;
+
+ private $run_log = array();
+
+ function runlog()
+ {
+ $this->start_time = microtime( TRUE );
+ }
+
+ public function start( $name, $tag = FALSE )
+ {
+ $this->run_log[] = array( 'type' => 'start',
+ 'tag' => $tag,
+ 'index' => count($this->run_log),
+ 'value' => $name,
+ 'time' => microtime( TRUE ),
+ 'parents' => $this->parent_stack,
+ 'ended' => false,
+ );
+ $this->parent_stack[] = $name;
+
+ $this->print_to_console("start: ".$name, $tag, 'start');
+ $this->print_to_file("start: ".$name, $tag, 'start');
+ $this->indent++;
+ }
+
+ public function end()
+ {
+ $name = array_pop( $this->parent_stack );
+ foreach ( $this->run_log as $k => $entry ) {
+ if ( $entry['value'] == $name && $entry['type'] == 'start' && $entry['ended'] == false) {
+ $lastk = $k;
+ }
+ }
+ $start = $this->run_log[$lastk]['time'];
+ $this->run_log[$lastk]['duration'] = microtime( TRUE ) - $start;
+ $this->run_log[$lastk]['ended'] = true;
+
+ $this->run_log[] = array( 'type' => 'end',
+ 'tag' => $this->run_log[$lastk]['tag'],
+ 'index' => $lastk,
+ 'value' => $name,
+ 'time' => microtime( TRUE ),
+ 'duration' => microtime( TRUE ) - $start,
+ 'parents' => $this->parent_stack,
+ );
+ $this->indent--;
+ if($this->run_log[$lastk]['duration'] >= $this->threshold){
+ $tag_report = "";
+ foreach($this->tag_count as $tag=>$count){
+ $tag_report .= "$tag: $count, ";
+ }
+ if(!empty($tag_report)){
+// $tag_report = "\n$tag_report\n";
+ }
+ $end_txt = sprintf("end: $name - %0.4f seconds $tag_report", $this->run_log[$lastk]['duration'] );
+ $this->print_to_console($end_txt, $this->run_log[$lastk]['tag'] , 'end');
+ $this->print_to_file($end_txt, $this->run_log[$lastk]['tag'], 'end');
+ }
+ }
+
+ public function increase_tag_count($tag){
+ if(!isset($this->tag_count[$tag])){
+ $this->tag_count[$tag] = 0;
+ }
+ $this->tag_count[$tag]++;
+ }
+
+ public function get_text(){
+ $text = "";
+ foreach($this->run_log as $entry){
+ $text .= str_repeat(" ",count($entry['parents']));
+ if($entry['tag'] != 'text'){
+ $text .= $entry['tag'].': ';
+ }
+ $text .= $entry['value'];
+
+ if($entry['tag'] == 'end'){
+ $text .= sprintf(" - %0.4f seconds", $entry['duration'] );
+ }
+
+ $text .= "\n";
+ }
+ return $text;
+ }
+
+ public function set_file($filename, $tag = 'master'){
+ if(!isset($this->file_handle[$tag])){
+ $this->file_handles[$tag] = fopen($filename, 'a');
+ if(!$this->file_handles[$tag]){
+ trigger_error('Could not open file for writing: '.$filename);
+ }
+ }
+ }
+
+ public function note( $msg, $tag = FALSE )
+ {
+ if($tag){
+ $this->increase_tag_count($tag);
+ }
+ if ( is_array( $msg )) {
+ $msg = '<pre>' . print_r( $msg, TRUE ) . '</pre>';
+ }
+ $this->debug_messages[] = $msg;
+ $this->run_log[] = array( 'type' => 'note',
+ 'tag' => $tag ? $tag:"text",
+ 'value' => htmlentities($msg),
+ 'time' => microtime( TRUE ),
+ 'parents' => $this->parent_stack,
+ );
+
+ $this->print_to_file($msg, $tag);
+ $this->print_to_console($msg, $tag);
+
+ }
+
+ public function print_to_file($msg, $tag = FALSE, $type = FALSE){
+ if(!$tag){
+ $file_handle_tag = 'master';
+ }
+ else{
+ $file_handle_tag = $tag;
+ }
+ if($file_handle_tag != 'master' && isset($this->file_handles[$file_handle_tag])){
+ $buffer = $this->get_indent();
+ $buffer .= "$msg\n";
+ if(!empty($this->timestamp)){
+ $buffer = sprintf("[%s] %s",date($this->timestamp, mktime()), $buffer);
+ }
+ fwrite($this->file_handles[$file_handle_tag], wordwrap($buffer, $this->max_line_size, "\n "));
+ }
+ if(isset($this->file_handles['master']) && $this->file_handles['master']){
+ $buffer = $this->get_indent();
+ if($tag){
+ $buffer .= "$tag: ";
+ }
+ $msg = str_replace("\n","",$msg);
+ $buffer .= "$msg";
+ if(!empty($this->timestamp)){
+ $buffer = sprintf("[%s] %s",date($this->timestamp, mktime()), $buffer);
+ }
+ if(strlen($buffer) > $this->max_line_size){
+ $buffer = substr($buffer,0,$this->max_line_size - 3)."...";
+ }
+ fwrite($this->file_handles['master'], $buffer."\n");
+ }
+ }
+
+ public function print_to_console($msg, $tag=FALSE){
+ if($this->print_to_console){
+ if(is_array($this->print_to_console)){
+ if(in_array($tag, $this->print_to_console)){
+ echo $this->get_indent();
+ if($tag){
+ echo "$tag: ";
+ }
+ echo "$msg\n";
+ }
+ }
+ else{
+ echo $this->get_indent();
+ if($tag){
+ echo "$tag: ";
+ }
+ echo "$msg\n";
+ }
+ }
+ }
+
+ public function print_totals(){
+ $totals = array();
+ foreach ( $this->run_log as $k => $entry ) {
+ if ( $entry['type'] == 'start' && $entry['ended'] == true) {
+ $totals[$entry['value']]['duration'] += $entry['duration'];
+ $totals[$entry['value']]['count'] += 1;
+ }
+ }
+ if($this->file_handle){
+ foreach($totals as $name=>$details){
+ fwrite($this->file_handle,$name.": ".number_format($details['duration'],4)."sec, ".$details['count']." calls \n");
+ }
+ }
+ }
+
+ private function get_indent(){
+ $buf = "";
+ for($i = 0; $i < $this->indent; $i++){
+ $buf .= " ";
+ }
+ return $buf;
+ }
+
+
+ function __destruct(){
+ foreach($this->file_handles as $handle){
+ fclose($handle);
+ }
+ }
+
+}
+
+?>
View
39 plugins/emoticons/emoticons.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Display Emoticons
+ *
+ * Sample plugin to replace emoticons in plain text message body with real icons
+ *
+ * @version 1.0.1
+ * @author Thomas Bruederli
+ * @website http://roundcube.net
+ */
+class emoticons extends rcube_plugin
+{
+ public $task = 'mail';
+ private $map;
+
+ function init()
+ {
+ $this->task = 'mail';
+ $this->add_hook('message_part_after', array($this, 'replace'));
+
+ $this->map = array(
+ ':)' => html::img(array('src' => './program/js/tiny_mce/plugins/emotions/img/smiley-smile.gif', 'alt' => ':)')),
+ ':-)' => html::img(array('src' => './program/js/tiny_mce/plugins/emotions/img/smiley-smile.gif', 'alt' => ':-)')),
+ ':(' => html::img(array('src' => './program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif', 'alt' => ':(')),
+ ':-(' => html::img(array('src' => './program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif', 'alt' => ':-(')),
+ );
+ }
+
+ function replace($args)
+ {
+ if ($args['type'] == 'plain')
+ return array('body' => strtr($args['body'], $this->map));
+
+ return null;
+ }
+
+}
+
View
42 plugins/example_addressbook/example_addressbook.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Sample plugin to add a new address book
+ * with just a static list of contacts
+ */
+class example_addressbook extends rcube_plugin
+{
+ private $abook_id = 'static';
+
+ public function init()
+ {
+ $this->add_hook('address_sources', array($this, 'address_sources'));
+ $this->add_hook('get_address_book', array($this, 'get_address_book'));
+
+ // use this address book for autocompletion queries
+ // (maybe this should be configurable by the user?)
+ $config = rcmail::get_instance()->config;
+ $sources = $config->get('autocomplete_addressbooks', array('sql'));
+ if (!in_array($this->abook_id, $sources)) {
+ $sources[] = $this->abook_id;
+ $config->set('autocomplete_addressbooks', $sources);
+ }
+ }
+
+ public function address_sources($p)
+ {
+ $p['sources'][$this->abook_id] = array('id' => $this->abook_id, 'name' => 'Static List', 'readonly' => true);
+ return $p;
+ }
+
+ public function get_address_book($p)
+ {
+ if ($p['id'] == $this->abook_id) {
+ require_once(dirname(__FILE__) . '/example_addressbook_backend.php');
+ $p['instance'] = new example_addressbook_backend;
+ }
+
+ return $p;
+ }
+
+}
View
72 plugins/example_addressbook/example_addressbook_backend.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Example backend class for a custom address book
+ *
+ * This one just holds a static list of address records
+ *
+ * @author Thomas Bruederli
+ */
+class example_addressbook_backend extends rcube_addressbook
+{
+ public $primary_key = 'ID';
+ public $readonly = true;
+
+ private $filter;
+ private $result;
+
+ public function __construct()
+ {
+ $this->ready = true;
+ }
+
+ public function set_search_set($filter)
+ {
+ $this->filter = $filter;
+ }
+
+ public function get_search_set()
+ {
+ return $this->filter;
+ }
+
+ public function reset()
+ {
+ $this->result = null;
+ $this->filter = null;
+ }
+
+ public function list_records($cols=null, $subset=0)
+ {
+ $this->result = $this->count();
+ $this->result->add(array('ID' => '111', 'name' => "Example Contact", 'firstname' => "Example", 'surname' => "Contact", 'email' => "example@roundcube.net"));
+
+ return $this->result;
+ }
+
+ public function search($fields, $value, $strict=false, $select=true)
+ {
+ // no search implemented, just list all records
+ return $this->list_records();
+ }
+
+ public function count()
+ {
+ return new rcube_result_set(1, ($this->list_page-1) * $this->page_size);
+ }
+
+ public function get_result()
+ {
+ return $this->result;
+ }
+
+ public function get_record($id, $assoc=false)
+ {
+ $this->list_records();
+ $first = $this->result->first();
+ $sql_arr = $first['ID'] == $id ? $first : null;
+
+ return $assoc && $sql_arr ? $sql_arr : $this->result;
+ }
+
+}
View
144 plugins/filesystem_attachments/filesystem_attachments.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * Filesystem Attachments
+ *
+ * This is a core plugin which provides basic, filesystem based
+ * attachment temporary file handling. This includes storing
+ * attachments of messages currently being composed, writing attachments
+ * to disk when drafts with attachments are re-opened and writing
+ * attachments to disk for inline display in current html compositions.
+ *
+ * Developers may wish to extend this class when creating attachment
+ * handler plugins:
+ * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
+ * class myCustom_attachments extends filesystem_attachments
+ *
+ * @author Ziba Scott <ziba@umich.edu>
+ * @author Thomas Bruederli <roundcube@gmail.com>
+ *
+ */
+class filesystem_attachments extends rcube_plugin
+{
+ public $task = 'mail';
+
+ function init()
+ {
+ // Save a newly uploaded attachment
+ $this->add_hook('upload_attachment', array($this, 'upload'));
+
+ // Save an attachment from a non-upload source (draft or forward)
+ $this->add_hook('save_attachment', array($this, 'save'));
+
+ // Remove an attachment from storage
+ $this->add_hook('remove_attachment', array($this, 'remove'));
+
+ // When composing an html message, image attachments may be shown
+ $this->add_hook('display_attachment', array($this, 'display'));
+
+ // Get the attachment from storage and place it on disk to be sent
+ $this->add_hook('get_attachment', array($this, 'get_attachment'));
+
+ // Delete all temp files associated with this user
+ $this->add_hook('cleanup_attachments', array($this, 'cleanup'));
+ }
+
+ /**
+ * Save a newly uploaded attachment
+ */
+ function upload($args)
+ {
+ $args['status'] = false;
+ $rcmail = rcmail::get_instance();
+
+ // use common temp dir for file uploads
+ // #1484529: we need absolute path on Windows for move_uploaded_file()
+ $temp_dir = realpath($rcmail->config->get('temp_dir'));
+ $tmpfname = tempnam($temp_dir, 'rcmAttmnt');
+
+ if (move_uploaded_file($args['path'], $tmpfname) && file_exists($tmpfname)) {
+ $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1;
+ $args['path'] = $tmpfname;
+ $args['status'] = true;
+
+ // Note the file for later cleanup
+ $_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmpfname;
+ }
+
+ return $args;
+ }
+
+ /**
+ * Save an attachment from a non-upload source (draft or forward)
+ */
+ function save($args)
+ {
+ $args['status'] = false;
+ $rcmail = rcmail::get_instance();
+ $temp_dir = unslashify($rcmail->config->get('temp_dir'));
+ $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
+
+ if ($fp = fopen($tmp_path, 'w')) {
+ fwrite($fp, $args['data']);
+ fclose($fp);
+
+ $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1;
+ $args['path'] = $tmp_path;
+ $args['status'] = true;
+
+ // Note the file for later cleanup
+ $_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmp_path;
+ }
+
+ return $args;
+ }
+
+ /**
+ * Remove an attachment from storage
+ * This is triggered by the remove attachment button on the compose screen
+ */
+ function remove($args)
+ {
+ $args['status'] = @unlink($args['path']);
+ return $args;
+ }
+
+ /**
+ * When composing an html message, image attachments may be shown
+ * For this plugin, the file is already in place, just check for
+ * the existance of the proper metadata
+ */
+ function display($args)
+ {
+ $args['status'] = file_exists($args['path']);
+ return $args;
+ }
+
+ /**
+ * This attachment plugin doesn't require any steps to put the file
+ * on disk for use. This stub function is kept here to make this
+ * class handy as a parent class for other plugins which may need it.
+ */
+ function get_attachment($args)
+ {
+ return $args;
+ }
+
+ /**
+ * Delete all temp files associated with this user
+ */
+ function cleanup($args)
+ {
+ // $_SESSION['compose']['attachments'] is not a complete record of
+ // temporary files because loading a draft or starting a forward copies
+ // the file to disk, but does not make an entry in that array
+ if (is_array($_SESSION['plugins']['filesystem_attachments']['tmp_files'])){
+ foreach ($_SESSION['plugins']['filesystem_attachments']['tmp_files'] as $filename){
+ if(file_exists($filename)){
+ unlink($filename);
+ }
+ }
+ unset($_SESSION['plugins']['filesystem_attachments']['tmp_files']);
+ }
+ return $args;
+ }
+}
View
41 plugins/http_authentication/http_authentication.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * HTTP Basic Authentication
+ *
+ * Make use of an existing HTTP authentication and perform login with the existing user credentials
+ *
+ * @version 1.0
+ * @author Thomas Bruederli
+ */
+class http_authentication extends rcube_plugin
+{
+
+ function init()
+ {
+ $this->add_hook('startup', array($this, 'startup'));
+ $this->add_hook('authenticate', array($this, 'authenticate'));
+ }
+
+ function startup($args)
+ {
+ // change action to login
+ if ($args['task'] == 'mail' && empty($args['action']) && empty($_SESSION['user_id'])
+ && !empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW']))
+ $args['action'] = 'login';
+
+ return $args;
+ }
+
+ function authenticate($args)
+ {
+ if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
+ $args['user'] = $_SERVER['PHP_AUTH_USER'];
+ $args['pass'] = $_SERVER['PHP_AUTH_PW'];
+ }
+
+ return $args;
+ }
+
+}
+
View
BIN  plugins/markasjunk/junk_act.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  plugins/markasjunk/junk_pas.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
7 plugins/markasjunk/localization/en_US.inc
@@ -0,0 +1,7 @@
+<?php
+
+$labels = array();
+$labels['buttontitle'] = 'Mark as Junk';
+$labels['reportedasjunk'] = 'Successfully reported as Junk';
+
+?>
View
28 plugins/markasjunk/markasjunk.js
@@ -0,0 +1,28 @@
+/* Mark-as-Junk plugin script */
+
+function rcmail_markasjunk(prop)
+{
+ if (!rcmail.env.uid && (!rcmail.message_list || !rcmail.message_list.get_selection().length))
+ return;
+
+ var uids = rcmail.env.uid ? rcmail.env.uid : rcmail.message_list.get_selection().join(',');
+
+ rcmail.set_busy(true, 'loading');
+ rcmail.http_post('plugin.markasjunk', '_uid='+uids+'&_mbox='+urlencode(rcmail.env.mailbox), true);
+}
+
+// callback for app-onload event
+if (window.rcmail) {
+ rcmail.addEventListener('init', function(evt) {
+
+ // register command (directly enable in message view mode)
+ rcmail.register_command('plugin.markasjunk', rcmail_markasjunk, rcmail.env.uid);
+
+ // add event-listener to message list
+ if (rcmail.message_list)
+ rcmail.message_list.addEventListener('select', function(list){
+ rcmail.enable_command('plugin.markasjunk', list.get_selection().length > 0);
+ });
+ })
+}
+
View
47 plugins/markasjunk/markasjunk.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Mark as Junk
+ *
+ * Sample plugin that adds a new button to the mailbox toolbar
+ * to mark the selected messages as Junk and move them to the Junk folder
+ *
+ * @version 1.0
+ * @author Thomas Bruederli
+ */
+class markasjunk extends rcube_plugin
+{
+ public $task = 'mail';
+
+ function init()
+ {
+ $this->register_action('plugin.markasjunk', array($this, 'request_action'));
+ $GLOBALS['IMAP_FLAGS']['JUNK'] = 'Junk';
+
+ $rcmail = rcmail::get_instance();
+ if ($rcmail->action == '' || $rcmail->action == 'show') {
+ $this->include_script('markasjunk.js');
+ $this->add_texts('localization', true);
+ $this->add_button(array('command' => 'plugin.markasjunk', 'imagepas' => 'junk_pas.png', 'imageact' => 'junk_act.png'), 'toolbar');
+ }
+ }
+
+ function request_action()
+ {
+ $this->add_texts('localization');
+
+ $uids = get_input_value('_uid', RCUBE_INPUT_POST);
+ $mbox = get_input_value('_mbox', RCUBE_INPUT_POST);
+
+ $rcmail = rcmail::get_instance();
+ $rcmail->imap->set_flag($uids, 'JUNK');
+
+ if (($junk_mbox = $rcmail->config->get('junk_mbox')) && $mbox != $junk_mbox) {
+ $rcmail->output->command('move_messages', $junk_mbox);
+ }
+
+ $rcmail->output->command('display_message', $this->gettext('reportedasjunk'), 'confirmation');
+ $rcmail->output->send();
+ }
+
+}
View
49 plugins/new_user_identity/new_user_identity.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * New user identity
+ *
+ * Populates a new user's default identity from LDAP on their first visit.
+ *
+ * This plugin requires that a working public_ldap directory be configured.
+ *
+ * @version 1.0
+ * @author Kris Steinhoff
+ *
+ * Example configuration:
+ *
+ * // The id of the address book to use to automatically set a new
+ * // user's full name in their new identity. (This should be an
+ * // string, which refers to the $rcmail_config['ldap_public'] array.)
+ * $rcmail_config['new_user_identity_addressbook'] = 'People';
+ *
+ * // When automatically setting a new users's full name in their
+ * // new identity, match the user's login name against this field.
+ * $rcmail_config['new_user_identity_match'] = 'uid';
+ *
+ * // Use the value in this field to automatically set a new users's
+ * // full name in their new identity.
+ * $rcmail_config['new_user_identity_field'] = 'name';
+ */
+class new_user_identity extends rcube_plugin
+{
+ function init()
+ {
+ $this->add_hook('create_user', array($this, 'lookup_user_name'));
+ }
+
+ function lookup_user_name($args)
+ {
+ $rcmail = rcmail::get_instance();
+ if ($addressbook = $rcmail->config->get('new_user_identity_addressbook')) {
+ $match = $rcmail->config->get('new_user_identity_match');
+ $ldap = $rcmail->get_address_book($addressbook);
+ $ldap->prop['search_fields'] = array($match);
+ $results = $ldap->search($match, $args['user'], TRUE);
+ if (count($results->records) == 1) {
+ $args['user_name'] = $results->records[0][$rcmail->config->get('new_user_identity_field')];
+ }
+ }
+ return $args;
+ }
+}
+?>
View
15 plugins/password/localization/en_US.inc
@@ -0,0 +1,15 @@
+<?php
+
+$labels = array();
+$labels['changepasswd'] = 'Change Password';
+$labels['curpasswd'] = 'Current Password:';
+$labels['newpasswd'] = 'New Password:';
+$labels['confpasswd'] = 'Confirm New Password:';
+
+$messages = array();
+$messages['nopassword'] = "Please input new password.";
+$messages['nocurpassword'] = "Please input current password.";
+$messages['passwordincorrectly'] = "Current password incorrectly.";
+$messages['passwordinconsistency'] = "Inconsistency of password, please try again.";
+
+?>
View
15 plugins/password/localization/pl_PL.inc
@@ -0,0 +1,15 @@
+<?php
+
+$labels = array();
+$labels['changepasswd'] = 'Zmiana hasła';
+$labels['curpasswd'] = 'Aktualne hasło:';
+$labels['newpasswd'] = 'Nowe hasło:';
+$labels['confpasswd'] = 'Potwierdź hasło:';
+
+$messages = array();
+$messages['nopassword'] = 'Wprowadź nowe hasło.';
+$messages['nocurpassword'] = 'Wprowadź aktualne hasło.';
+$messages['passwordincorrect'] = 'Błędne aktualne hasło, spróbuj ponownie.';
+$messages['passwordinconsistency'] = 'Hasła nie pasują, spróbuj ponownie.';
+
+?>
View
44 plugins/password/password.js
@@ -0,0 +1,44 @@
+/* Password change interface (tab) */
+
+if (window.rcmail) {
+ rcmail.addEventListener('init', function(evt) {
+ // <span id="settingstabdefault" class="tablink"><roundcube:button command="preferences" type="link" label="preferences" title="editpreferences" /></span>
+ var tab = $('<span>').attr('id', 'settingstabpluginpassword').addClass('tablink');
+
+ var button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.password').html(rcmail.gettext('password')).appendTo(tab);
+ button.bind('click', function(e){ return rcmail.command('plugin.password', this) });
+
+ // add button and register commands
+ rcmail.add_element(tab, 'tabs');
+ rcmail.register_command('plugin.password', function() { rcmail.goto_url('plugin.password') }, true);
+ rcmail.register_command('plugin.password-save', function() {
+ var input_curpasswd = rcube_find_object('_curpasswd');
+ var input_newpasswd = rcube_find_object('_newpasswd');
+ var input_confpasswd = rcube_find_object('_confpasswd');
+
+ if (input_curpasswd && input_curpasswd.value=='') {
+ alert(rcmail.gettext('nocurpassword', 'password'));
+ input_curpasswd.focus();
+ } else if (input_newpasswd && input_newpasswd.value=='') {
+ alert(rcmail.gettext('nopassword', 'password'));
+ input_newpasswd.focus();
+ } else if (input_confpasswd && input_confpasswd.value=='') {
+ alert(rcmail.gettext('nopassword', 'password'));
+ input_confpasswd.focus();
+ } else if ((input_newpasswd && input_confpasswd) && (input_newpasswd.value != input_confpasswd.value)) {
+ alert(rcmail.gettext('passwordinconsistency', 'password'));
+ input_newpasswd.focus();
+ } else {
+ rcmail.gui_objects.passform.submit();
+ }
+ }, true);
+ })
+
+ // set page title
+ if (rcmail.env.action == 'plugin.password' && rcmail.env.task == 'settings') {
+ var title = rcmail.gettext('changepasswd','password')
+ if (rcmail.env.product_name)
+ title = rcmail.env.product_name + ' :: ' + title;
+ rcmail.set_pagetitle(title);
+ }
+}
View
160 plugins/password/password.php
@@ -0,0 +1,160 @@
+<?php
+
+/**
+ * Change Password
+ *
+ * Sample plugin that adds a possibility to change password
+ * (Settings -> Password tab)
+ *
+ * @version 1.0
+ * @author Aleksander 'A.L.E.C' Machniak
+ */
+class password extends rcube_plugin
+{
+ public $task = 'settings';
+
+ function init()
+ {
+ $rcmail = rcmail::get_instance();
+ // add Tab label
+ $rcmail->output->add_label('password');
+ $this->register_action('plugin.password', array($this, 'password_init'));
+ $this->register_action('plugin.password-save', array($this, 'password_save'));
+ $this->register_handler('plugin.body', array($this, 'password_form'));
+ $this->include_script('password.js');
+ }
+
+ function password_init()
+ {
+ $this->add_texts('localization/');
+ rcmail::get_instance()->output->send('plugin');
+ }
+
+ function password_save()
+ {
+ $rcmail = rcmail::get_instance();
+
+ $this->add_texts('localization/');
+
+ if (!isset($_POST['_curpasswd']) || !isset($_POST['_newpasswd']))
+ $rcmail->output->command('display_message', $this->gettext('nopassword'), 'error');
+ else {
+ $curpwd = get_input_value('_curpasswd', RCUBE_INPUT_POST);
+ $newpwd = get_input_value('_newpasswd', RCUBE_INPUT_POST);
+
+ if ($_SESSION['password'] != $rcmail->encrypt_passwd($curpwd))
+ $rcmail->output->command('display_message', $this->gettext('passwordincorrect'), 'error');
+ else if ($res = $this->_save($newpwd)) {
+ $rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation');
+ $_SESSION['password'] = $rcmail->encrypt_passwd($newpwd);
+ } else
+ $rcmail->output->command('display_message', $this->gettext('errorsaving'), 'error');
+ }
+
+ rcmail_overwrite_action('plugin.password');
+ rcmail::get_instance()->output->send('plugin');
+ }
+
+ function password_form()
+ {
+ $rcmail = rcmail::get_instance();
+
+ // add some labels to client
+ $rcmail->output->add_label(
+ 'password.nopassword',
+ 'password.nocurpassword',
+ 'password.passwordinconsistency',
+ 'password.changepasswd'
+ );
+// $rcmail->output->set_pagetitle($this->gettext('changepasswd'));
+ $rcmail->output->set_env('product_name', $rcmail->config->get('product_name'));
+
+ // allow the following attributes to be added to the <table> tag
+ $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
+
+ // return the complete edit form as table
+ $out = '<table' . $attrib_str . ">\n\n";
+
+ $a_show_cols = array('curpasswd' => array('type' => 'text'),
+ 'newpasswd' => array('type' => 'text'),
+ 'confpasswd' => array('type' => 'text'));
+
+ // show current password selection
+ $field_id = 'curpasswd';
+ $input_newpasswd = new html_passwordfield(array('name' => '_curpasswd', 'id' => $field_id, 'size' => 20));
+
+ $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
+ $field_id,
+ rep_specialchars_output($this->gettext('curpasswd')),
+ $input_newpasswd->show($rcmail->config->get('curpasswd')));
+
+ // show new password selection
+ $field_id = 'newpasswd';
+ $input_newpasswd = new html_passwordfield(array('name' => '_newpasswd', 'id' => $field_id, 'size' => 20));
+
+ $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
+ $field_id,
+ rep_specialchars_output($this->gettext('newpasswd')),
+ $input_newpasswd->show($rcmail->config->get('newpasswd')));
+
+ // show confirm password selection
+ $field_id = 'confpasswd';
+ $input_confpasswd = new html_passwordfield(array('name' => '_confpasswd', 'id' => $field_id, 'size' => 20));
+
+ $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
+ $field_id,
+ rep_specialchars_output($this->gettext('confpasswd')),
+ $input_confpasswd->show($rcmail->config->get('confpasswd')));
+
+ $out .= "\n</table>";
+
+ $out .= '<br />';
+
+ $out .= $rcmail->output->button(array(
+ 'command' => 'plugin.password-save',
+ 'type' => 'input',
+ 'class' => 'button mainaction',
+ 'label' => 'save'
+ ));
+
+ $rcmail->output->add_gui_object('passform', 'password-form');
+
+ return $rcmail->output->form_tag(array(
+ 'id' => 'password-form',
+ 'name' => 'password-form',
+ 'method' => 'post',
+ 'action' => './?_task=settings&_action=plugin.password-save',
+ ), $out);
+ }
+
+
+ private function _save($passwd)
+ {
+ $cfg = rcmail::get_instance()->config;
+
+ if (!($sql = $cfg->get('password_query')))
+ $sql = "SELECT update_passwd('%p', '%u')";
+
+ $sql = str_replace('%u', $_SESSION['username'], $sql);
+ $sql = str_replace('%p', crypt($passwd), $sql);
+
+ if ($dsn = $cfg->get('db_passwd_dsn')) {
+ $db = new rcube_mdb2($dsn, '', FALSE);
+ $db->set_debug((bool)$cfg->get('sql_debug'));
+ $db->db_connect('w');
+ } else {
+ $db = rcmail::get_instance()->get_dbh();
+ }
+
+ if (!$db->db_connected)
+ return false;
+
+ $res = $db->query($sql);
+ $res = $db->fetch_array($res);
+
+ return $res;
+ }
+
+}
+
+?>
View
49 plugins/show_additional_headers/show_additional_headers.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Show additional message headers
+ *
+ * Proof-of-concept plugin which will fetch additional headers
+ * and display them in the message view.
+ *
+ * Enable the plugin in config/main.inc.php and add your desired headers:
+ * $rcmail_config['show_additional_headers'] = array('User-Agent');
+ *
+ * @version 1.0
+ * @author Thomas Bruederli
+ * @website http://roundcube.net
+ */
+class show_additional_headers extends rcube_plugin
+{
+ public $task = 'mail';
+
+ function init()
+ {
+ $rcmail = rcmail::get_instance();
+ if ($rcmail->action == 'show' || $rcmail->action == 'preview') {
+ $this->add_hook('imap_init', array($this, 'imap_init'));
+ $this->add_hook('message_headers_output', array($this, 'message_headers'));
+ }
+ }
+
+ function imap_init($p)
+ {
+ $rcmail = rcmail::get_instance();
+ if ($add_headers = $rcmail->config->get('show_additional_headers', array()))
+ $p['fetch_headers'] = trim($p['fetch_headers'].' ' . strtoupper(join(' ', $add_headers)));
+
+ return $p;
+ }
+
+ function message_headers($p)
+ {
+ $rcmail = rcmail::get_instance();
+ foreach ($rcmail->config->get('show_additional_headers', array()) as $header) {
+ $key = strtolower($header);
+ if ($value = $p['headers']->others[$key])
+ $p['output'][$key] = array('title' => $header, 'value' => $value);
+ }
+
+ return $p;
+ }
+}
View
6 plugins/subscriptions_option/localization/en_US.inc
@@ -0,0 +1,6 @@
+<?php
+
+$labels = array();
+$labels['useimapsubscriptions'] = 'Use IMAP Subscriptions';
+
+?>
View
84 plugins/subscriptions_option/subscriptions_option.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * Subscription Options
+ *
+ * A plugin which can enable or disable the use of imap subscriptions.
+ * It includes a toggle on the settings page under "Server Settings".
+ * The preference can also be locked
+ *
+ * Add it to the plugins list in config/main.inc.php to enable the user option
+ * The user option can be hidden and set globally by adding 'use_subscriptions'
+ * to the the 'dont_override' configure line:
+ * $rcmail_config['dont_override'] = array('use_subscriptions');
+ * and then set the global preference"
+ * $rcmail_config['use_subscriptions'] = true; // or false
+ *
+ * Roundcube caches folder lists. When a user changes this option or visits
+ * their folder list, this cache is refreshed. If the option is on the
+ * 'dont_override' list and the global option has changed, don't expect
+ * to see the change until the folder list cache is refreshed.
+ *
+ * @version 1.0
+ * @author Ziba Scott
+ */
+class subscriptions_option extends rcube_plugin
+{
+
+ function init()
+ {
+ $this->add_texts('localization/', false);
+ $dont_override = rcmail::get_instance()->config->get('dont_override', array());
+ if (!in_array('use_subscriptions', $dont_override)){
+ $this->add_hook('user_preferences', array($this, 'settings_table'));
+ $this->add_hook('save_preferences', array($this, 'save_prefs'));
+ }
+ $this->add_hook('list_mailboxes', array($this, 'list_mailboxes'));
+ $this->add_hook('manage_folders', array($this, 'manage_folders'));
+ }
+
+ function settings_table($args)
+ {
+ if ($args['section'] == 'server') {
+ $use_subscriptions = rcmail::get_instance()->config->get('use_subscriptions');
+ $field_id = 'rcmfd_use_subscriptions';
+ $use_subscriptions = new html_checkbox(array('name' => '_use_subscriptions', 'id' => $field_id, 'value' => 1));
+
+ $args['table']->add('title', html::label($field_id, Q($this->gettext('useimapsubscriptions'))));
+ $args['table']->add(null, $use_subscriptions->show($use_subscriptions?1:0));
+ }
+
+ return $args;
+ }
+
+ function save_prefs($args){
+ $rcmail = rcmail::get_instance();
+ $use_subscriptions = $rcmail->config->get('use_subscriptions');
+
+ $args['prefs']['use_subscriptions'] = isset($_POST['_use_subscriptions']) ? true : false;
+ // if the use_subscriptions preference changes, flush the folder cache
+ if (($use_subscriptions && !isset($_POST['_use_subscriptions'])) ||
+ (!$use_subscriptions && isset($_POST['_use_subscriptions']))) {
+ $rcmail->imap_init(true);
+ $rcmail->imap->clear_cache('mailboxes');
+ }
+
+ return $args;
+ }
+
+ function list_mailboxes($args){
+ $rcmail = rcmail::get_instance();
+ if (!$rcmail->config->get('use_subscriptions', true)) {
+ $args['folders'] = iil_C_ListMailboxes($rcmail->imap->conn, $rcmail->imap->_mod_mailbox($args['root']), $args['filter']);
+ }
+ return $args;
+ }
+
+ function manage_folders($args){
+ $rcmail = rcmail::get_instance();
+ if (!$rcmail->config->get('use_subscriptions', true)) {
+ $args['table']->remove_column('subscribed');
+ }
+ return $args;
+ }
+}
View
9 plugins/userinfo/localization/de_CH.inc
@@ -0,0 +1,9 @@
+<?php
+
+$labels = array();
+$labels['userinfo'] = 'Benutzerinfo';
+$labels['created'] = 'Erstellt';
+$labels['lastlogin'] = 'Letztes Login';
+$labels['defaultidentity'] = 'Standard-Absender';
+
+?>
View
9 plugins/userinfo/localization/en_US.inc
@@ -0,0 +1,9 @@
+<?php
+
+$labels = array();
+$labels['userinfo'] = 'User info';
+$labels['created'] = 'Created';
+$labels['lastlogin'] = 'Last Login';
+$labels['defaultidentity'] = 'Default Identity';
+
+?>
View
16 plugins/userinfo/userinfo.js
@@ -0,0 +1,16 @@
+/* Show user-info plugin script */
+
+if (window.rcmail) {
+ rcmail.addEventListener('init', function(evt) {
+ // <span id="settingstabdefault" class="tablink"><roundcube:button command="preferences" type="link" label="preferences" title="editpreferences" /></span>
+ var tab = $('<span>').attr('id', 'settingstabpluginuserinfo').addClass('tablink');
+
+ var button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.userinfo').html(rcmail.gettext('userinfo', 'userinfo')).appendTo(tab);
+ button.bind('click', function(e){ return rcmail.command('plugin.userinfo', this) });
+
+ // add button and register command
+ rcmail.add_element(tab, 'tabs');
+ rcmail.register_command('plugin.userinfo', function(){ rcmail.goto_url('plugin.userinfo') }, true);
+ })
+}
+
View
53 plugins/userinfo/userinfo.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Sample plugin that adds a new tab to the settings section
+ * to display some information about the current user
+ */
+class userinfo extends rcube_plugin
+{
+ public $task = 'settings';
+
+ function init()
+ {
+ $this->add_texts('localization/', array('userinfo'));
+ $this->register_action('plugin.userinfo', array($this, 'infostep'));
+ $this->include_script('userinfo.js');
+ }
+
+ function infostep()
+ {
+ $this->register_handler('plugin.body', array($this, 'infohtml'));
+ rcmail::get_instance()->output->send('plugin');
+ }
+
+ function infohtml()
+ {
+ $rcmail = rcmail::get_instance();
+ $user = $rcmail->user;
+
+ $table = new html_table(array('cols' => 2, 'cellpadding' => 3));
+
+ $table->add('title', 'ID');
+ $table->add('', Q($user->ID));
+
+ $table->add('title', Q($this->gettext('username')));
+ $table->add('', Q($user->data['username']));
+
+ $table->add('title', Q($this->gettext('server')));
+ $table->add('', Q($user->data['mail_host']));
+
+ $table->add('title', Q($this->gettext('created')));
+ $table->add('', Q($user->data['created']));
+
+ $table->add('title', Q($this->gettext('lastlogin')));
+ $table->add('', Q($user->data['last_login']));
+
+ $identity = $user->get_identity();
+ $table->add('title', Q($this->gettext('defaultidentity')));
+ $table->add('', Q($identity['name'] . ' <' . $identity['email'] . '>'));
+
+ return html::tag('h4', null, Q('Infos for ' . $user->get_username())) . $table->show();
+ }
+
+}
View
115 plugins/vcard_attachments/vcard_attachments.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Detect VCard attachments and show a button to add them to address book
+ *
+ * @version 1.0
+ * @author Thomas Bruederli
+ */
+class vcard_attachments extends rcube_plugin
+{
+ public $task = 'mail';
+
+ private $message;
+ private $vcard_part;
+
+ function init()
+ {
+ $rcmail = rcmail::get_instance();
+ if ($rcmail->action == 'show' || $rcmail->action == 'preview') {
+ $this->add_hook('message_load', array($this, 'message_load'));
+ $this->add_hook('template_object_messagebody', array($this, 'html_output'));
+ }
+
+ $this->register_action('plugin.savevcard', array($this, 'save_vcard'));
+ }
+
+ /**
+ * Check message attachments for vcards
+ */
+ function message_load($p)
+ {
+ $this->message = $p['object'];
+
+ foreach ((array)$this->message->attachments as $attachment) {
+ if (in_array($attachment->mimetype, array('text/vcard', 'text/x-vcard')))
+ $this->vcard_part = $attachment->mime_id;
+ }
+ }
+
+ /**
+ * This callback function adds a box below the message content
+ * if there is a vcard attachment available
+ */
+ function html_output($p)
+ {
+ if ($this->vcard_part) {
+ $vcard = new rcube_vcard($this->message->get_part_content($this->vcard_part));
+
+ // successfully parsed vcard
+ if ($vcard->displayname) {
+ $display = $vcard->displayname;
+ if ($vcard->email[0])
+ $display .= ' <'.$vcard->email[0].'>';
+
+ // add box below messsage body
+ $p['content'] .= html::p(array('style' => "margin:1em; padding:0.5em; border:1px solid #999; width: auto;"),
+ html::a(array(
+ 'href' => "#",
+ 'onclick' => "return plugin_vcard_save_contact('".JQ($this->vcard_part)."')",
+ 'title' => "Save contact in local address book"), // TODO: localize this title
+ html::img(array('src' => '/images/buttons/add_contact_act.png', 'align' => "middle")))
+ . ' ' . html::span(null, Q($display)));
+
+ $this->include_script('vcardattach.js');
+ }
+ }
+
+ return $p;
+ }
+
+ /**
+ * Handler for request action
+ */
+ function save_vcard()
+ {
+ $uid = get_input_value('_uid', RCUBE_INPUT_POST);
+ $mbox = get_input_value('_mbox', RCUBE_INPUT_POST);
+ $mime_id = get_input_value('_part', RCUBE_INPUT_POST);
+
+ $rcmail = rcmail::get_instance();
+ $part = $uid && $mime_id ? $rcmail->imap->get_message_part($uid, $mime_id) : null;
+
+ $error_msg = 'Failed to saved vcard'; // TODO: localize this text
+
+ if ($part && ($vcard = new rcube_vcard($part)) && $vcard->displayname && $vcard->email) {
+ $contacts = $rcmail->get_address_book(null, true);
+
+ // check for existing contacts
+ $existing = $contacts->search('email', $vcard->email[0], true, false);
+ if ($done = $existing->count) {
+ $rcmail->output->command('display_message', $this->gettext('contactexists'), 'warning');
+ }
+ else {
+ // add contact
+ $success = $contacts->insert(array(
+ 'name' => $vcard->displayname,
+ 'firstname' => $vcard->firstname,
+ 'surname' => $vcard->surname,
+ 'email' => $vcard->email[0],
+ 'vcard' => $vcard->export(),
+ ));
+
+ if ($success)
+ $rcmail->output->command('display_message', $this->gettext('addedsuccessfully'), 'confirmation');
+ else
+ $rcmail->output->command('display_message', $error_msg, 'error');
+ }
+ }
+ else
+ $rcmail->output->command('display_message', $error_msg, 'error');
+
+ $rcmail->output->send();
+ }
+
+}
View
10 plugins/vcard_attachments/vcardattach.js
@@ -0,0 +1,10 @@
+
+function plugin_vcard_save_contact(mime_id)
+{
+ rcmail.set_busy(true, 'loading');
+ rcmail.http_post('plugin.savevcard', '_uid='+rcmail.env.uid+'&_mbox='+urlencode(rcmail.env.mailbox)+'&_part='+urlencode(mime_id), true);
+
+ return false;
+}
+
+
View
30 program/include/html.php
@@ -33,7 +33,7 @@ class html
protected $content;
public static $common_attrib = array('id','class','style','title','align');
- public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','tr','th','td','style');
+ public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','tr','th','td','style','script');
public static $lc_tags = true;
/**
@@ -599,6 +599,34 @@ public function add_header($attr, $cont)
$this->header[] = $cell;
}
+ /**
+ * Remove a column from a table
+ * Useful for plugins making alterations
+ *
+ * @param string $class
+ */
+ public function remove_column($class)
+ {
+ // Remove the header
+ foreach($this->header as $index=>$header){
+ if($header->attrib['class'] == $class){
+ unset($this->header[$index]);
+ break;
+ }
+ }
+
+ // Remove cells from rows
+ foreach($this->rows as $i=>$row){
+ foreach($row->cells as $j=>$cell){
+ if($cell->attrib['class'] == $class){
+ unset($this->rows[$i]->cells[$j]);
+ break;
+ }
+ }
+ }
+ }
+
+
/**
* Jump to next row
*
View
2  program/include/iniset.php
@@ -22,7 +22,7 @@
// application constants
-define('RCMAIL_VERSION', '0.2-trunk');
+define('RCMAIL_VERSION', '0.3-trunk');
define('RCMAIL_CHARSET', 'UTF-8');
define('JS_OBJECT_NAME', 'rcmail');
View
25 program/include/main.inc
@@ -88,9 +88,9 @@ function get_sequence_name($sequence)
* @return string Localized text
* @see rcmail::gettext()
*/
-function rcube_label($p)
+function rcube_label($p, $domain=null)
{
- return rcmail::get_instance()->gettext($p);
+ return rcmail::get_instance()->gettext($p, $domain);
}
@@ -302,12 +302,11 @@ function rcube_charset_convert($str, $from, $to=NULL)
*/
function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
{
- global $OUTPUT;
static $html_encode_arr = false;
static $js_rep_table = false;
static $xml_rep_table = false;
- $charset = $OUTPUT->get_charset();
+ $charset = rcmail::get_instance()->config->get('charset', RCMAIL_CHARSET);
$is_iso_8859_1 = false;